@epicgames-ps/lib-pixelstreamingfrontend-ue5.5 0.0.5

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.
Files changed (138) hide show
  1. package/.cspell.json +48 -0
  2. package/.eslintignore +8 -0
  3. package/.eslintrc.js +8 -0
  4. package/.prettierignore +0 -0
  5. package/.prettierrc.json +6 -0
  6. package/dist/lib-pixelstreamingfrontend.esm.js +1 -0
  7. package/dist/lib-pixelstreamingfrontend.js +1 -0
  8. package/jest.config.js +18 -0
  9. package/package.json +48 -0
  10. package/readme.md +15 -0
  11. package/src/AFK/AFKController.test.ts +162 -0
  12. package/src/AFK/AFKController.ts +158 -0
  13. package/src/Config/Config.test.ts +222 -0
  14. package/src/Config/Config.ts +970 -0
  15. package/src/Config/SettingBase.ts +65 -0
  16. package/src/Config/SettingFlag.ts +99 -0
  17. package/src/Config/SettingNumber.ts +111 -0
  18. package/src/Config/SettingOption.ts +124 -0
  19. package/src/Config/SettingText.ts +82 -0
  20. package/src/DataChannel/DataChannelController.ts +138 -0
  21. package/src/DataChannel/DataChannelLatencyTestController.ts +129 -0
  22. package/src/DataChannel/DataChannelLatencyTestResults.ts +67 -0
  23. package/src/DataChannel/DataChannelSender.ts +59 -0
  24. package/src/DataChannel/InitialSettings.ts +61 -0
  25. package/src/DataChannel/LatencyTestResults.ts +76 -0
  26. package/src/FreezeFrame/FreezeFrame.ts +114 -0
  27. package/src/FreezeFrame/FreezeFrameController.ts +114 -0
  28. package/src/Inputs/FakeTouchController.ts +199 -0
  29. package/src/Inputs/GamepadController.ts +314 -0
  30. package/src/Inputs/GamepadTypes.ts +10 -0
  31. package/src/Inputs/HoveringMouseEvents.ts +192 -0
  32. package/src/Inputs/IMouseEvents.ts +64 -0
  33. package/src/Inputs/ITouchController.ts +29 -0
  34. package/src/Inputs/InputClassesFactory.ts +140 -0
  35. package/src/Inputs/KeyboardController.ts +354 -0
  36. package/src/Inputs/LockedMouseEvents.ts +287 -0
  37. package/src/Inputs/MouseButtons.ts +25 -0
  38. package/src/Inputs/MouseController.ts +362 -0
  39. package/src/Inputs/SpecialKeyCodes.ts +16 -0
  40. package/src/Inputs/TouchController.ts +208 -0
  41. package/src/Inputs/XRGamepadController.ts +126 -0
  42. package/src/PeerConnectionController/AggregatedStats.ts +311 -0
  43. package/src/PeerConnectionController/CandidatePairStats.ts +17 -0
  44. package/src/PeerConnectionController/CandidateStat.ts +13 -0
  45. package/src/PeerConnectionController/CodecStats.ts +19 -0
  46. package/src/PeerConnectionController/DataChannelStats.ts +17 -0
  47. package/src/PeerConnectionController/InboundRTPStats.ts +154 -0
  48. package/src/PeerConnectionController/InboundTrackStats.ts +34 -0
  49. package/src/PeerConnectionController/OutBoundRTPStats.ts +26 -0
  50. package/src/PeerConnectionController/PeerConnectionController.ts +563 -0
  51. package/src/PeerConnectionController/SessionStats.ts +10 -0
  52. package/src/PeerConnectionController/StreamStats.ts +11 -0
  53. package/src/PixelStreaming/PixelStreaming.test.ts +626 -0
  54. package/src/PixelStreaming/PixelStreaming.ts +851 -0
  55. package/src/UI/OnScreenKeyboard.ts +97 -0
  56. package/src/UeInstanceMessage/ResponseController.ts +47 -0
  57. package/src/UeInstanceMessage/SendMessageController.ts +154 -0
  58. package/src/UeInstanceMessage/StreamMessageController.ts +233 -0
  59. package/src/UeInstanceMessage/ToStreamerMessagesController.ts +62 -0
  60. package/src/Util/CoordinateConverter.ts +289 -0
  61. package/src/Util/EventEmitter.ts +611 -0
  62. package/src/Util/EventListenerTracker.ts +29 -0
  63. package/src/Util/FileUtil.ts +140 -0
  64. package/src/Util/RTCUtils.ts +41 -0
  65. package/src/Util/WebGLUtils.ts +49 -0
  66. package/src/Util/WebXRUtils.ts +25 -0
  67. package/src/VideoPlayer/StreamController.ts +89 -0
  68. package/src/VideoPlayer/VideoPlayer.ts +246 -0
  69. package/src/WebRtcPlayer/WebRtcPlayerController.ts +2158 -0
  70. package/src/WebXR/WebXRController.ts +319 -0
  71. package/src/__test__/mockMediaStream.ts +124 -0
  72. package/src/__test__/mockRTCPeerConnection.ts +347 -0
  73. package/src/__test__/mockRTCRtpReceiver.ts +22 -0
  74. package/src/__test__/mockWebSocket.ts +136 -0
  75. package/src/pixelstreamingfrontend.ts +46 -0
  76. package/tsconfig.jest.json +8 -0
  77. package/tsconfig.json +24 -0
  78. package/types/AFK/AFKController.d.ts +39 -0
  79. package/types/Config/Config.d.ts +218 -0
  80. package/types/Config/SettingBase.d.ts +30 -0
  81. package/types/Config/SettingFlag.d.ts +33 -0
  82. package/types/Config/SettingNumber.d.ts +45 -0
  83. package/types/Config/SettingOption.d.ts +43 -0
  84. package/types/Config/SettingText.d.ts +29 -0
  85. package/types/DataChannel/DataChannelController.d.ts +59 -0
  86. package/types/DataChannel/DataChannelLatencyTestController.d.ts +26 -0
  87. package/types/DataChannel/DataChannelLatencyTestResults.d.ts +46 -0
  88. package/types/DataChannel/DataChannelSender.d.ts +21 -0
  89. package/types/DataChannel/InitialSettings.d.ts +44 -0
  90. package/types/DataChannel/LatencyTestResults.d.ts +31 -0
  91. package/types/FreezeFrame/FreezeFrame.d.ts +36 -0
  92. package/types/FreezeFrame/FreezeFrameController.d.ts +37 -0
  93. package/types/Inputs/FakeTouchController.d.ts +61 -0
  94. package/types/Inputs/GamepadController.d.ts +85 -0
  95. package/types/Inputs/GamepadTypes.d.ts +8 -0
  96. package/types/Inputs/HoveringMouseEvents.d.ts +56 -0
  97. package/types/Inputs/IMouseEvents.d.ts +53 -0
  98. package/types/Inputs/ITouchController.d.ts +24 -0
  99. package/types/Inputs/InputClassesFactory.d.ts +54 -0
  100. package/types/Inputs/KeyboardController.d.ts +62 -0
  101. package/types/Inputs/LockedMouseEvents.d.ts +80 -0
  102. package/types/Inputs/MouseButtons.d.ts +22 -0
  103. package/types/Inputs/MouseController.d.ts +75 -0
  104. package/types/Inputs/SpecialKeyCodes.d.ts +14 -0
  105. package/types/Inputs/TouchController.d.ts +53 -0
  106. package/types/Inputs/XRGamepadController.d.ts +15 -0
  107. package/types/PeerConnectionController/AggregatedStats.d.ts +77 -0
  108. package/types/PeerConnectionController/CandidatePairStats.d.ts +15 -0
  109. package/types/PeerConnectionController/CandidateStat.d.ts +11 -0
  110. package/types/PeerConnectionController/CodecStats.d.ts +14 -0
  111. package/types/PeerConnectionController/DataChannelStats.d.ts +15 -0
  112. package/types/PeerConnectionController/InboundRTPStats.d.ts +141 -0
  113. package/types/PeerConnectionController/InboundTrackStats.d.ts +32 -0
  114. package/types/PeerConnectionController/OutBoundRTPStats.d.ts +23 -0
  115. package/types/PeerConnectionController/PeerConnectionController.d.ts +132 -0
  116. package/types/PeerConnectionController/SessionStats.d.ts +8 -0
  117. package/types/PeerConnectionController/StreamStats.d.ts +9 -0
  118. package/types/PixelStreaming/PixelStreaming.d.ts +259 -0
  119. package/types/UI/OnScreenKeyboard.d.ts +31 -0
  120. package/types/UeInstanceMessage/ResponseController.d.ts +19 -0
  121. package/types/UeInstanceMessage/SendMessageController.d.ts +18 -0
  122. package/types/UeInstanceMessage/StreamMessageController.d.ts +29 -0
  123. package/types/UeInstanceMessage/ToStreamerMessagesController.d.ts +32 -0
  124. package/types/Util/CoordinateConverter.d.ts +100 -0
  125. package/types/Util/EventEmitter.d.ts +422 -0
  126. package/types/Util/EventListenerTracker.d.ts +14 -0
  127. package/types/Util/FileUtil.d.ts +32 -0
  128. package/types/Util/RTCUtils.d.ts +8 -0
  129. package/types/Util/WebGLUtils.d.ts +4 -0
  130. package/types/Util/WebXRUtils.d.ts +9 -0
  131. package/types/VideoPlayer/StreamController.d.ts +24 -0
  132. package/types/VideoPlayer/VideoPlayer.d.ts +78 -0
  133. package/types/WebRtcPlayer/WebRtcPlayerController.d.ts +377 -0
  134. package/types/WebXR/WebXRController.d.ts +26 -0
  135. package/types/pixelstreamingfrontend.d.ts +22 -0
  136. package/webpack.common.js +35 -0
  137. package/webpack.dev.js +35 -0
  138. package/webpack.prod.js +36 -0
@@ -0,0 +1,158 @@
1
+ // Copyright Epic Games, Inc. All Rights Reserved.
2
+
3
+ import { Config, Flags, NumericParameters } from '../Config/Config';
4
+ import { Logger } from '@epicgames-ps/lib-pixelstreamingcommon-ue5.5';
5
+ import { PixelStreaming } from '../PixelStreaming/PixelStreaming';
6
+ import {
7
+ AfkTimedOutEvent,
8
+ AfkWarningActivateEvent,
9
+ AfkWarningDeactivateEvent,
10
+ AfkWarningUpdateEvent
11
+ } from '../Util/EventEmitter';
12
+
13
+ export class AFKController {
14
+ // time out logic details
15
+ closeTimeout = 10;
16
+ active = false;
17
+ countdownActive = false;
18
+ warnTimer: ReturnType<typeof setTimeout> = undefined;
19
+ countDown = 0;
20
+ countDownTimer: ReturnType<typeof setInterval> = undefined;
21
+ config: Config;
22
+ pixelStreaming: PixelStreaming;
23
+ onDismissAfk: () => void;
24
+
25
+ onAFKTimedOutCallback: () => void;
26
+
27
+ constructor(
28
+ config: Config,
29
+ pixelStreaming: PixelStreaming,
30
+ onDismissAfk: () => void
31
+ ) {
32
+ this.config = config;
33
+ this.pixelStreaming = pixelStreaming;
34
+ this.onDismissAfk = onDismissAfk;
35
+ this.onAFKTimedOutCallback = () => {
36
+ console.log(
37
+ 'AFK timed out, did you want to override this callback?'
38
+ );
39
+ };
40
+ }
41
+
42
+ /**
43
+ * The methods that occur when an afk event listener is clicked
44
+ */
45
+ onAfkClick() {
46
+ clearInterval(this.countDownTimer);
47
+
48
+ if (this.active || this.countdownActive) {
49
+ this.startAfkWarningTimer();
50
+ this.pixelStreaming.dispatchEvent(
51
+ new AfkWarningDeactivateEvent()
52
+ );
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Start the warning timer if a timeout is set greater that 0 seconds
58
+ */
59
+ startAfkWarningTimer() {
60
+ if (
61
+ this.config.getNumericSettingValue(
62
+ NumericParameters.AFKTimeoutSecs
63
+ ) > 0 &&
64
+ this.config.isFlagEnabled(Flags.AFKDetection)
65
+ ) {
66
+ this.active = true;
67
+ } else {
68
+ this.active = false;
69
+ }
70
+ this.resetAfkWarningTimer();
71
+ }
72
+
73
+ /**
74
+ * Stop the afk warning timer
75
+ */
76
+ stopAfkWarningTimer() {
77
+ this.active = false;
78
+ this.countdownActive = false;
79
+ clearTimeout(this.warnTimer);
80
+ clearInterval(this.countDownTimer);
81
+ }
82
+
83
+ /**
84
+ * Pause the timer which when elapsed will warn the user they are inactive.
85
+ */
86
+ pauseAfkWarningTimer() {
87
+ this.active = false;
88
+ }
89
+
90
+ /**
91
+ * If the user interacts then reset the warning timer.
92
+ */
93
+ resetAfkWarningTimer() {
94
+ if (this.active && this.config.isFlagEnabled(Flags.AFKDetection)) {
95
+ clearTimeout(this.warnTimer);
96
+ this.warnTimer = setTimeout(
97
+ () => this.activateAfkEvent(),
98
+ this.config.getNumericSettingValue(
99
+ NumericParameters.AFKTimeoutSecs
100
+ ) * 1000
101
+ );
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Show the AFK overlay and begin the countDown
107
+ */
108
+ activateAfkEvent() {
109
+ // Pause the timer while the user is looking at the inactivity warning overlay
110
+ this.pauseAfkWarningTimer();
111
+
112
+ // instantiate a new overlay
113
+ this.pixelStreaming.dispatchEvent(
114
+ new AfkWarningActivateEvent({
115
+ countDown: this.countDown,
116
+ dismissAfk: this.onDismissAfk
117
+ })
118
+ );
119
+
120
+ // update our countDown timer and overlay contents
121
+ this.countDown = this.closeTimeout;
122
+ this.countdownActive = true;
123
+ this.pixelStreaming.dispatchEvent(
124
+ new AfkWarningUpdateEvent({ countDown: this.countDown })
125
+ );
126
+
127
+ // if we are in locked mouse exit pointerlock
128
+ if (!this.config.isFlagEnabled(Flags.HoveringMouseMode)) {
129
+ // minor hack to alleviate ios not supporting pointerlock
130
+ if (document.exitPointerLock) {
131
+ document.exitPointerLock();
132
+ }
133
+ }
134
+
135
+ // reset our countDown interval accordingly
136
+ this.countDownTimer = setInterval(() => {
137
+ this.countDown--;
138
+ if (this.countDown == 0) {
139
+ // The user failed to click so hide the overlay and disconnect them.
140
+ this.pixelStreaming.dispatchEvent(
141
+ new AfkTimedOutEvent()
142
+ );
143
+ this.onAFKTimedOutCallback();
144
+ Logger.Log(
145
+ Logger.GetStackTrace(),
146
+ 'You have been disconnected due to inactivity'
147
+ );
148
+
149
+ // switch off the afk feature as stream has closed
150
+ this.stopAfkWarningTimer();
151
+ } else {
152
+ this.pixelStreaming.dispatchEvent(
153
+ new AfkWarningUpdateEvent({ countDown: this.countDown })
154
+ );
155
+ }
156
+ }, 1000);
157
+ }
158
+ }
@@ -0,0 +1,222 @@
1
+ import { mockRTCRtpReceiver, unmockRTCRtpReceiver } from '../__test__/mockRTCRtpReceiver';
2
+ import {
3
+ Config,
4
+ Flags,
5
+ FlagsKeys,
6
+ NumericParameters,
7
+ NumericParametersKeys,
8
+ OptionParameters,
9
+ OptionParametersKeys,
10
+ TextParameters,
11
+ TextParametersKeys
12
+ } from './Config';
13
+
14
+ const allFlags = Object.keys(Flags).map((key) => Flags[key as FlagsKeys]);
15
+ const allNumericParameters = Object.keys(NumericParameters).map(
16
+ (key) => NumericParameters[key as NumericParametersKeys]
17
+ );
18
+ const allTextParameters = Object.keys(TextParameters).map(
19
+ (key) => TextParameters[key as TextParametersKeys]
20
+ );
21
+ const allOptionParameters = Object.keys(OptionParameters).map(
22
+ (key) => OptionParameters[key as OptionParametersKeys]
23
+ );
24
+
25
+ const allParameters = [
26
+ ...allFlags,
27
+ ...allNumericParameters,
28
+ ...allTextParameters,
29
+ ...allOptionParameters
30
+ ];
31
+
32
+ describe('Config', () => {
33
+ beforeEach(() => {
34
+ mockRTCRtpReceiver();
35
+ });
36
+
37
+ afterEach(() => {
38
+ unmockRTCRtpReceiver();
39
+ jest.resetAllMocks();
40
+ });
41
+
42
+ it('should populate initial values for all settings when initialized without parameters', () => {
43
+ const config = new Config();
44
+
45
+ const settings = config.getSettings();
46
+ expect(Object.keys(settings)).toEqual(
47
+ expect.arrayContaining(allParameters)
48
+ );
49
+ });
50
+
51
+ it('should populate given initial setting values', () => {
52
+ const initialSettings = {
53
+ [Flags.AutoPlayVideo]: false,
54
+ [NumericParameters.WebRTCMaxBitrate]: 12345,
55
+ [TextParameters.SignallingServerUrl]: 'url'
56
+ };
57
+
58
+ const config = new Config({ initialSettings });
59
+
60
+ expect(config.isFlagEnabled(Flags.AutoPlayVideo)).toEqual(
61
+ initialSettings[Flags.AutoPlayVideo]
62
+ );
63
+ expect(
64
+ config.getNumericSettingValue(NumericParameters.WebRTCMaxBitrate)
65
+ ).toEqual(initialSettings[NumericParameters.WebRTCMaxBitrate]);
66
+ expect(
67
+ config.getTextSettingValue(TextParameters.SignallingServerUrl)
68
+ ).toEqual(initialSettings[TextParameters.SignallingServerUrl]);
69
+ });
70
+
71
+ it('should replace setting values when new settings are set with setSettings', () => {
72
+ const config = new Config();
73
+
74
+ const preferredCodecs = ['c1', 'c2', 'c3'];
75
+ config.setOptionSettingOptions(
76
+ OptionParameters.PreferredCodec,
77
+ preferredCodecs
78
+ );
79
+
80
+ const changedSettings = {
81
+ [Flags.AutoPlayVideo]: false,
82
+ [NumericParameters.WebRTCMaxBitrate]: 54321,
83
+ [TextParameters.SignallingServerUrl]: 'signalling-url',
84
+ [OptionParameters.PreferredCodec]: 'c2'
85
+ };
86
+
87
+ config.setSettings(changedSettings);
88
+
89
+ expect(config.isFlagEnabled(Flags.AutoPlayVideo)).toEqual(
90
+ changedSettings[Flags.AutoPlayVideo]
91
+ );
92
+ expect(
93
+ config.getNumericSettingValue(NumericParameters.WebRTCMaxBitrate)
94
+ ).toEqual(changedSettings[NumericParameters.WebRTCMaxBitrate]);
95
+ expect(
96
+ config.getTextSettingValue(TextParameters.SignallingServerUrl)
97
+ ).toEqual(changedSettings[TextParameters.SignallingServerUrl]);
98
+ expect(
99
+ config.getSettingOption(OptionParameters.PreferredCodec).selected
100
+ ).toEqual(changedSettings[OptionParameters.PreferredCodec]);
101
+ });
102
+
103
+ it('should replace setting values when new settings are set with set* setters', () => {
104
+ const config = new Config();
105
+
106
+ const preferredCodecs = ['c1', 'c2', 'c3'];
107
+ config.setOptionSettingOptions(
108
+ OptionParameters.PreferredCodec,
109
+ preferredCodecs
110
+ );
111
+
112
+ const changedSettings = {
113
+ [Flags.AutoPlayVideo]: false,
114
+ [NumericParameters.WebRTCMaxBitrate]: 54321,
115
+ [TextParameters.SignallingServerUrl]: 'signalling-url',
116
+ [OptionParameters.PreferredCodec]: 'c2'
117
+ };
118
+
119
+ config.setFlagEnabled(
120
+ Flags.AutoPlayVideo,
121
+ changedSettings[Flags.AutoPlayVideo]
122
+ );
123
+ config.setNumericSetting(
124
+ NumericParameters.WebRTCMaxBitrate,
125
+ changedSettings[NumericParameters.WebRTCMaxBitrate]
126
+ );
127
+ config.setTextSetting(
128
+ TextParameters.SignallingServerUrl,
129
+ changedSettings[TextParameters.SignallingServerUrl]
130
+ );
131
+ config.setOptionSettingValue(
132
+ OptionParameters.PreferredCodec,
133
+ changedSettings[OptionParameters.PreferredCodec]
134
+ );
135
+
136
+ expect(config.isFlagEnabled(Flags.AutoPlayVideo)).toEqual(
137
+ changedSettings[Flags.AutoPlayVideo]
138
+ );
139
+ expect(
140
+ config.getNumericSettingValue(NumericParameters.WebRTCMaxBitrate)
141
+ ).toEqual(changedSettings[NumericParameters.WebRTCMaxBitrate]);
142
+ expect(
143
+ config.getTextSettingValue(TextParameters.SignallingServerUrl)
144
+ ).toEqual(changedSettings[TextParameters.SignallingServerUrl]);
145
+ expect(
146
+ config.getSettingOption(OptionParameters.PreferredCodec).selected
147
+ ).toEqual(changedSettings[OptionParameters.PreferredCodec]);
148
+ });
149
+
150
+ it('should persist config changes to window.location URL when updateURLParams() is called', () => {
151
+ const config = new Config({ useUrlParams: true });
152
+
153
+ const preferredCodecs = ['c1', 'c2', 'c3'];
154
+ config.setOptionSettingOptions(
155
+ OptionParameters.PreferredCodec,
156
+ preferredCodecs
157
+ );
158
+
159
+ const changedSettings = {
160
+ [Flags.AutoPlayVideo]: false,
161
+ [NumericParameters.WebRTCMaxBitrate]: 54321,
162
+ [TextParameters.SignallingServerUrl]: 'signalling-url',
163
+ [OptionParameters.PreferredCodec]: 'c2'
164
+ };
165
+
166
+ config.setSettings(changedSettings);
167
+
168
+ config
169
+ .getFlags()
170
+ .find((setting) => setting.id === Flags.AutoPlayVideo)
171
+ ?.updateURLParams();
172
+ config
173
+ .getNumericSettings()
174
+ .find(
175
+ (setting) => setting.id === NumericParameters.WebRTCMaxBitrate
176
+ )
177
+ ?.updateURLParams();
178
+ config
179
+ .getTextSettings()
180
+ .find(
181
+ (setting) => setting.id === TextParameters.SignallingServerUrl
182
+ )
183
+ ?.updateURLParams();
184
+ config
185
+ .getOptionSettings()
186
+ .find((setting) => setting.id === OptionParameters.PreferredCodec)
187
+ ?.updateURLParams();
188
+
189
+ const urlParams = new URLSearchParams(window.location.search);
190
+
191
+ expect(urlParams.get(Flags.AutoPlayVideo)).toEqual(
192
+ changedSettings[Flags.AutoPlayVideo].toString()
193
+ );
194
+ expect(urlParams.get(NumericParameters.WebRTCMaxBitrate)).toEqual(
195
+ changedSettings[NumericParameters.WebRTCMaxBitrate].toString()
196
+ );
197
+ expect(urlParams.get(TextParameters.SignallingServerUrl)).toEqual(
198
+ changedSettings[TextParameters.SignallingServerUrl].toString()
199
+ );
200
+ expect(urlParams.get(OptionParameters.PreferredCodec)).toEqual(
201
+ changedSettings[OptionParameters.PreferredCodec].toString()
202
+ );
203
+ });
204
+
205
+ it('should read initial config from window.location URL if initialized with useUrlParams: true', () => {
206
+ window.history.replaceState(
207
+ {},
208
+ '',
209
+ 'http://localhost/?AutoPlayVideo=false&WebRTCMaxBitrate=43210&ss=signalling-url-from-url-param'
210
+ );
211
+
212
+ const config = new Config({ useUrlParams: true });
213
+
214
+ expect(config.isFlagEnabled(Flags.AutoPlayVideo)).toEqual(false);
215
+ expect(
216
+ config.getNumericSettingValue(NumericParameters.WebRTCMaxBitrate)
217
+ ).toEqual(43210);
218
+ expect(
219
+ config.getTextSettingValue(TextParameters.SignallingServerUrl)
220
+ ).toEqual('signalling-url-from-url-param');
221
+ });
222
+ });