|
AJA NTV2 SDK
17.1.3.1410
NTV2 SDK 17.1.3.1410
|
Go to the documentation of this file.
5 #include <QJsonDocument>
14 #if defined (AJALinux) || defined (AJAMac)
15 #include <arpa/inet.h>
28 mEnable2022_7 =
false;
29 mNetworkPathDifferential = 50;
36 QFile loadFile(fileName);
37 if ( !loadFile.open(QIODevice::ReadOnly))
39 qWarning(
"Couldn't open json file.");
43 QByteArray saveData = loadFile.readAll();
46 QJsonDocument loadDoc = (QJsonDocument::fromJson(saveData,&err));
47 if (err.error != QJsonParseError::NoError)
49 qDebug() <<
"JSON ERROR" << err.errorString() <<
"offset=" << err.offset;
58 const QJsonObject &
json = loadDoc.object();
59 QJsonValue qjv =
json.value(
"protocol");
60 if (qjv != QJsonValue::Undefined)
62 QString protocol = qjv.toString();
63 if (protocol ==
"2022")
71 cout <<
"-----Protocol2110-----" << endl;
76 cout <<
"-----Protocol2022-----" << endl;
77 qjv =
json.value(
"enable2022_7");
78 if (qjv != QJsonValue::Undefined)
80 mEnable2022_7 =
getEnable(qjv.toString());
84 mEnable2022_7 =
false;
86 cout <<
"2022-7 mode " << mEnable2022_7 << endl;
88 qjv =
json.value(
"networkPathDifferential");
89 if (qjv != QJsonValue::Undefined)
91 mNetworkPathDifferential = qjv.toString().toUInt();
95 mNetworkPathDifferential = 50;
97 cout <<
"NetworkPathDifferential " << mNetworkPathDifferential << endl;
109 QJsonArray sfpArray =
json[
"sfps"].toArray();
110 for (
int sfpIndex = 0; sfpIndex < sfpArray.size(); ++sfpIndex)
112 cout <<
"SFP" << endl;
114 QJsonObject sfpObject = sfpArray[sfpIndex].toObject();
119 cout <<
"SFPDesignator " << sfpStruct.
mSfpDesignator.toStdString() << endl;
121 sfpStruct.
mIPAddress = sfpObject[
"ipAddress"].toString();
123 cout <<
"IPAddress " << sfpStruct.
mIPAddress.toStdString() << endl;
125 sfpStruct.
mSubnetMask = sfpObject[
"subnetMask"].toString();
127 cout <<
"SubnetMask " << sfpStruct.
mSubnetMask.toStdString() << endl;
129 sfpStruct.
mGateway = sfpObject[
"gateway"].toString();
131 cout <<
"Gateway " << sfpStruct.
mGateway.toStdString() << endl;
133 sfpStruct.
mEnable = sfpObject[
"enable"].toString();
134 if (!sfpStruct.
mEnable.isEmpty())
135 cout <<
"Enable " << sfpStruct.
mEnable.toStdString() << endl;
142 QJsonArray receiveChannelArray =
json[
"receive2022"].toArray();
143 for (
int receiveChannelIndex = 0; receiveChannelIndex < receiveChannelArray.size(); ++receiveChannelIndex)
145 cout <<
"Receive2022Channels" << endl;
147 QJsonObject receiveChannelObject = receiveChannelArray[receiveChannelIndex].toObject();
152 cout <<
"ChannelDesignator " << receive2022Struct.
mChannelDesignator.toStdString() << endl;
154 receive2022Struct.
mSfp1SrcIPAddress = receiveChannelObject[
"sfp1SrcIPAddress"].toString();
156 cout <<
"SFP1SrcIPAddress " << receive2022Struct.
mSfp1SrcIPAddress.toStdString() << endl;
158 receive2022Struct.
mSfp1SrcPort = receiveChannelObject[
"sfp1SrcPort"].toString();
160 cout <<
"SFP1SrcPort " << receive2022Struct.
mSfp1SrcPort.toStdString() << endl;
162 receive2022Struct.
mSfp1DestIPAddress = receiveChannelObject[
"sfp1DestIPAddress"].toString();
164 cout <<
"SFP1DestIPAddress " << receive2022Struct.
mSfp1DestIPAddress.toStdString() << endl;
166 receive2022Struct.
mSfp1DestPort = receiveChannelObject[
"sfp1DestPort"].toString();
168 cout <<
"SFP1DestPort " << receive2022Struct.
mSfp1DestPort.toStdString() << endl;
170 receive2022Struct.
mSfp1Filter = receiveChannelObject[
"sfp1Filter"].toString();
172 cout <<
"SFP1Filter " << receive2022Struct.
mSfp1Filter.toStdString() << endl;
174 receive2022Struct.
mSfp2SrcIPAddress = receiveChannelObject[
"sfp2SrcIPAddress"].toString();
176 cout <<
"SFP2SrcIPAddress " << receive2022Struct.
mSfp2SrcIPAddress.toStdString() << endl;
178 receive2022Struct.
mSfp2SrcPort = receiveChannelObject[
"sfp2SrcPort"].toString();
180 cout <<
"SFP2SrcPort " << receive2022Struct.
mSfp2SrcPort.toStdString() << endl;
182 receive2022Struct.
mSfp2DestIPAddress = receiveChannelObject[
"sfp2DestIPAddress"].toString();
184 cout <<
"SFP1DestIPAddress " << receive2022Struct.
mSfp2DestIPAddress.toStdString() << endl;
186 receive2022Struct.
mSfp2DestPort = receiveChannelObject[
"sfp2DestPort"].toString();
188 cout <<
"SFP1DestPort " << receive2022Struct.
mSfp2DestPort.toStdString() << endl;
190 receive2022Struct.
mSfp2Filter = receiveChannelObject[
"sfp2Filter"].toString();
192 cout <<
"SFP1Filter " << receive2022Struct.
mSfp2Filter.toStdString() << endl;
194 receive2022Struct.
mPlayoutDelay = receiveChannelObject[
"playoutDelay"].toString();
196 cout <<
"PlayoutDelay " << receive2022Struct.
mPlayoutDelay.toStdString() << endl;
198 receive2022Struct.
mVLAN = receiveChannelObject[
"vlan"].toString();
199 if (!receive2022Struct.
mVLAN.isEmpty())
200 cout <<
"VLAN " << receive2022Struct.
mVLAN.toStdString() << endl;
202 receive2022Struct.
mSSRC = receiveChannelObject[
"ssrc"].toString();
203 if (!receive2022Struct.
mSSRC.isEmpty())
204 cout <<
"SSRC " << receive2022Struct.
mSSRC.toStdString() << endl;
206 receive2022Struct.
mSfp1Enable = receiveChannelObject[
"sfp1Enable"].toString();
208 cout <<
"SFP1 Enable " << receive2022Struct.
mSfp1Enable.toStdString() << endl;
210 receive2022Struct.
mSfp2Enable = receiveChannelObject[
"sfp2Enable"].toString();
212 cout <<
"SFP2 Enable " << receive2022Struct.
mSfp2Enable.toStdString() << endl;
214 receive2022Struct.
mEnable = receiveChannelObject[
"enable"].toString();
215 if (!receive2022Struct.
mEnable.isEmpty())
216 cout <<
"Enable " << receive2022Struct.
mEnable.toStdString() << endl;
223 QJsonArray transmitChannelArray =
json[
"transmit2022"].toArray();
224 for (
int transmitChannelIndex = 0; transmitChannelIndex < transmitChannelArray.size(); ++transmitChannelIndex)
226 cout <<
"Transmit2022Channels" << endl;
228 QJsonObject transmitChannelObject = transmitChannelArray[transmitChannelIndex].toObject();
231 transmitStruct2022.
mChannelDesignator = transmitChannelObject[
"designator"].toString();
233 cout <<
"ChannelDesignator " << transmitStruct2022.
mChannelDesignator.toStdString() << endl;
235 transmitStruct2022.
mSfp1RemoteIPAddress = transmitChannelObject[
"sfp1RemoteIPAddress"].toString();
237 cout <<
"SFP1RemoteIPAddress " << transmitStruct2022.
mSfp1RemoteIPAddress.toStdString() << endl;
239 transmitStruct2022.
mSfp1RemotePort = transmitChannelObject[
"sfp1RemotePort"].toString();
241 cout <<
"SFP1RemotePort " << transmitStruct2022.
mSfp1RemotePort.toStdString() << endl;
243 transmitStruct2022.
mSfp1LocalPort = transmitChannelObject[
"sfp1LocalPort"].toString();
245 cout <<
"SFP1LocalPort " << transmitStruct2022.
mSfp1LocalPort.toStdString() << endl;
247 transmitStruct2022.
mSfp2RemoteIPAddress = transmitChannelObject[
"sfp2RemoteIPAddress"].toString();
249 cout <<
"SFP2RemoteIPAddress " << transmitStruct2022.
mSfp2RemoteIPAddress.toStdString() << endl;
251 transmitStruct2022.
mSfp2RemotePort = transmitChannelObject[
"sfp2RemotePort"].toString();
253 cout <<
"SFP2RemotePort " << transmitStruct2022.
mSfp2RemotePort.toStdString() << endl;
255 transmitStruct2022.
mSfp2LocalPort = transmitChannelObject[
"sfp2LocalPort"].toString();
257 cout <<
"SFP2LocalPort " << transmitStruct2022.
mSfp2LocalPort.toStdString() << endl;
259 transmitStruct2022.
mTOS = transmitChannelObject[
"tos"].toString();
260 if (!transmitStruct2022.
mTOS.isEmpty())
261 cout <<
"TOS " << transmitStruct2022.
mTOS.toStdString() << endl;
263 transmitStruct2022.
mTTL = transmitChannelObject[
"ttl"].toString();
264 if (!transmitStruct2022.
mTTL.isEmpty())
265 cout <<
"TTL " << transmitStruct2022.
mTTL.toStdString() << endl;
267 transmitStruct2022.
mSSRC = transmitChannelObject[
"ssrc"].toString();
268 if (!transmitStruct2022.
mSSRC.isEmpty())
269 cout <<
"SSRC " << transmitStruct2022.
mSSRC.toStdString() << endl;
271 transmitStruct2022.
mSfp1Enable = transmitChannelObject[
"sfp1Enable"].toString();
273 cout <<
"SFP1 Enable " << transmitStruct2022.
mSfp1Enable.toStdString() << endl;
275 transmitStruct2022.
mSfp2Enable = transmitChannelObject[
"sfp2Enable"].toString();
277 cout <<
"SFP2 Enable " << transmitStruct2022.
mSfp2Enable.toStdString() << endl;
279 transmitStruct2022.
mEnable = transmitChannelObject[
"enable"].toString();
280 if (!transmitStruct2022.
mEnable.isEmpty())
281 cout <<
"Enable " << transmitStruct2022.
mEnable.toStdString() << endl;
305 if (!mDevice.IsOpen())
307 cerr <<
"## ERROR: No devices found " << deviceSpec.c_str() << endl;
316 cout <<
"## NOTE: Waiting for device to become ready... (Ctrl-C will abort)" << endl;
320 cout <<
"## NOTE: Device is ready" << endl;
326 cerr <<
"## ERROR: board firmware package is incompatible with this application" << endl;
334 cerr <<
"## ERROR: Need To Specify at Least 1 SFP" << endl;
339 while (sfpIter.hasNext())
400 bool rv = config2022.
Set2022_7_Mode(mEnable2022_7,mNetworkPathDifferential);
408 cerr <<
"## receiveIter" << endl;
411 while (receiveIter.hasNext())
413 cerr <<
"## receiveIter " << endl;
443 rxChannelConfig.
ssrc = receive.
mSSRC.toUInt();
448 cerr <<
"Error (config2022.SetRxChannelConfiguration) " << config2022.
getLastError() << endl;
454 cerr <<
"Error (config2022.SetRxChannelConfiguration) " << config2022.
getLastError() << endl;
458 cerr <<
"## transmitIter" << endl;
461 while (transmitIter.hasNext())
463 cerr <<
"## transmitIter " << endl;
487 txChannelConfig.
ssrc = transmit.
mSSRC.toUInt();
488 txChannelConfig.
tos = transmit.
mTOS.toUInt();
489 txChannelConfig.
ttl = transmit.
mTTL.toUInt();
494 cerr <<
"Error (config2022.SetTxChannelConfiguration) " << config2022.
getLastError() << endl;
500 cerr <<
"Error (config2022.SetTxChannelEnable) " << config2022.
getLastError() << endl;
512 if (!device.IsOpen())
513 {cerr <<
"## ERROR: No devices found " << deviceSpec.c_str() << endl;
return false;}
520 cout <<
"## NOTE: Waiting for device to become ready... (Ctrl-C will abort)" << endl;
524 cout <<
"## NOTE: Device is ready" << endl;
527 cerr <<
"## ERROR: board firmware package is incompatible with this application" << endl;
557 for (uint32_t i = 0; i < net2110.
numSFPs; i++)
559 cerr <<
"## network " << i+1 << endl;
590 cerr <<
"## receiveVideo " << i+1 << endl;
592 rxChannelConfig.
init();
627 ip = inet_addr(rxChannelConfig.
sourceIP.c_str());
631 ip = inet_addr(rxChannelConfig.
destIP.c_str());
639 if (rxChannelConfig.
vlan)
643 if (rxChannelConfig.
ssrc)
653 cerr <<
"SetRxStreamConfiguration: Video FAILED: " << config2110.
getLastError() << endl;
662 cerr <<
"SetRxStreamEnable: Video FAILED: " << config2110.
getLastError() << endl;
671 cerr <<
"## receiveAudio " << i+1 << endl;
673 rxChannelConfig.
init();
707 ip = inet_addr(rxChannelConfig.
sourceIP.c_str());
711 ip = inet_addr(rxChannelConfig.
destIP.c_str());
719 if (rxChannelConfig.
vlan)
723 if (rxChannelConfig.
ssrc)
733 cerr <<
"SetRxStreamConfiguration: Audio FAILED: " << config2110.
getLastError() << endl;
742 cerr <<
"SetRxStreamEnable: Audio FAILED: " << config2110.
getLastError() << endl;
751 cerr <<
"## receiveAnc " << i+1 << endl;
753 rxChannelConfig.
init();
785 ip = inet_addr(rxChannelConfig.
sourceIP.c_str());
789 ip = inet_addr(rxChannelConfig.
destIP.c_str());
797 if (rxChannelConfig.
vlan)
801 if (rxChannelConfig.
ssrc)
810 cerr <<
"SetRxStreamConfiguration: ANC FAILED: " << config2110.
getLastError() << endl;
819 cerr <<
"SetRxStreamEnable: ANC FAILED: " << config2110.
getLastError() << endl;
830 cerr <<
"## transmitVideo " << i+1 << endl;
833 txChannelConfig.
init();
852 cerr <<
"SetTxStreamConfiguration Video: FAILED: " << config2110.
getLastError() << endl;
863 cerr <<
"SetTxStreamEnable Video: FAILED: " << config2110.
getLastError() << endl;
873 cerr <<
"## transmitAudio " << i+1 << endl;
876 txChannelConfig.
init();
899 cerr <<
"SetTxStreamConfiguration Audio: FAILED: " << config2110.
getLastError() << endl;
910 cerr <<
"SetTxStreamEnable Audio: FAILED: " << config2110.
getLastError() << endl;
920 cerr <<
"## transmitAnc " << i+1 << endl;
923 txChannelConfig.
init();
940 cerr <<
"SetTxStreamConfiguration ANC: FAILED: " << config2110.
getLastError() << endl;
951 cerr <<
"SetTxStreamEnable ANC: FAILED: " << config2110.
getLastError() << endl;
965 if ( channelDesignator ==
"channel2")
967 else if ( channelDesignator ==
"channel3")
969 else if ( channelDesignator ==
"channel4")
977 return (enableBoolString ==
"true");
uint32_t ssrc
Specifies the SSRC identifier (if RX_MATCH_2110_SSRC set)
RxAncChData2110 rxAncCh[4]
TxVideoChData2110 txVideoCh[4]
Configures a SMPTE 2022 Transmit Channel.
ReceiveVideoData2110 m_receiveVideo2110
@ NTV2_REFERENCE_SFP1_PTP
Specifies the PTP source on SFP 1.
@ NTV2_CHANNEL2
Specifies channel or Frame Store 2 (or the 2nd item).
uint32_t numTxAudioChannels
NTV2VideoFormat videoFormat
uint32_t localPort[2]
Specifies the local (source) port number.
bool Set2022_7_Mode(bool enable, uint32_t rx_networkPathDifferential)
QString mChannelDesignator
bool SetPTPDomain(const uint8_t domain)
Declares device capability functions.
bool SetRxStreamEnable(const eSFP sfp, const NTV2Stream stream, bool enable)
virtual bool ReadRegister(const ULWord inRegNum, ULWord &outValue, const ULWord inMask=0xFFFFFFFF, const ULWord inShift=0)
Reads all or part of the 32-bit contents of a specific register (real or virtual) on the AJA device....
#define RX_MATCH_2110_PAYLOAD
NTV2Channel
These enum values are mostly used to identify a specific widget_framestore. They're also commonly use...
KonaIP2022ParamSetupStruct mKonaIP2022Params
uint32_t numAudioChannels
NTV2VideoFormat videoFormat
std::string sfp1RemoteIP
Specifies remote (destination) IP address.
bool SetTxChannelConfiguration(const NTV2Channel channel, const tx_2022_channel &txConfig)
NTV2VideoFormat videoFormat
VPIDSampling videoSamples
uint32_t firstAudioChannel
Declares the AJATime class.
NTV2Channel getChannel(QString channelDesignator)
bool setupBoard2110(std::string deviceSpec)
uint32_t playoutDelay
Specifies the wait time in milliseconds to SDI playout from incoming packet (0-150).
The CNTV2Config2022 class is the interface to Kona-IP network I/O using SMPTE 2022.
static bool GetFirstDeviceFromArgument(const std::string &inArgument, CNTV2Card &outDevice)
Rescans the host, and returns an open CNTV2Card instance for the AJA device that matches a command li...
Defines a number of handy byte-swapping macros.
The CNTV2Config2110 class inquires and configures SMPTE 2110 network I/O for KONA IP and Io IP.
uint32_t sfp2RemotePort
Specifies the remote (destination) port number.
uint32_t ssrc
Specifies the SSRC identifier (if RX_MATCH_2022_SSRC set)
eNTV2PacketInterval audioPktInterval
bool setupBoard(std::string deviceSpec)
TxAudioChData2110 txAudioCh[4]
uint32_t sfp1RemotePort
Specifies the remote (destination) port number.
std::string sfp2RemoteIP
Specifies remote (destination) IP address.
bool SetAudioCombineEnable(const bool enable)
Enables or disables the audio combiner.
@ NTV2_CHANNEL1
Specifies channel or Frame Store 1 (or the first item).
VPIDSampling videoSamples
uint32_t destPort
Specifies the destination (target) port number (if RX_MATCH_2110_DEST_PORT set)
ReceiveAncData2110 m_receiveAnc2110
uint32_t numTxVideoChannels
ReceiveAudioData2110 m_receiveAudio2110
NTV2VideoFormat videoFormat
QList< ReceiveStruct2022 > mReceive2022Channels
std::string sfp1SourceIP
Specifies the source (sender) IP address (if RX_MATCH_2022_SOURCE_IP set). If it's in the multiclass ...
TransmitAncData2110 m_transmitAnc2110
Declares the most fundamental data types used by NTV2. Since Windows NT was the first principal devel...
QString mChannelDesignator
RxAudioChData2110 rxAudioCh[4]
uint32_t numAudioChannels
uint32_t numRxVideoChannels
uint32_t numRxAncChannels
@ NTV2_CHANNEL4
Specifies channel or Frame Store 4 (or the 4th item).
TransmitVideoData2110 m_transmitVideo2110
uint32_t sourcePort
Specifies the source (sender) port number (if RX_MATCH_2110_SOURCE_PORT set)
uint16_t vlan
Specifies the VLAN TCI (if RX_MATCH_2110_VLAN set)
uint32_t sfp2LocalPort
Specifies the local (source) port number.
eNTV2PacketInterval audioPktInterval
bool openJson(QString fileName)
#define RX_MATCH_2110_SSRC
bool SetNetworkConfiguration(const eSFP sfp, const IPVNetConfig &netConfig)
uint32_t sfp1LocalPort
Specifies the local (source) port number.
QString mSfp1DestIPAddress
static void Sleep(const int32_t inMilliseconds)
Suspends execution of the current thread for a given number of milliseconds.
bool SetTxStreamConfiguration(const NTV2Stream stream, const tx_2110Config &txConfig)
bool DisableNetworkInterface(const eSFP sfp)
eNTV2PacketInterval audioPktInterval
Declares the CNTV2DeviceScanner class.
std::string remoteIP[2]
Specifies remote (destination) IP address.
#define NTV2EndianSwap32(__val__)
NetworkData2110 m_net2110
bool SetTxChannelEnable(const NTV2Channel channel, bool enable)
uint32_t numAudioChannels
bool getEnable(QString enableBoolString)
uint8_t sfp1RxMatch
Bitmap of rxMatch criteria used.
@ NTV2_CHANNEL3
Specifies channel or Frame Store 3 (or the 3rd item).
Enumerations for controlling NTV2 devices.
std::string sourceIP
Specifies the source (sender) IP address (if RX_MATCH_2110_SOURCE_IP set). If it's in the multiclass ...
std::string sfp1DestIP
Specifies the destination (target) IP address (if RX_MATCH_2022_DEST_IP set)
I interrogate and control an AJA video/audio capture/playout device.
uint32_t numTxAncChannels
QString mSfp2DestIPAddress
virtual bool IsMBSystemValid(void)
QString mSfp2SrcIPAddress
TransmitAudioData2110 m_transmitAudio2110
TxAncChData2110 txAncCh[4]
#define RX_MATCH_2110_VLAN
std::string sfp2DestIP
Specifies the destination (target) IP address (if RX_MATCH_2022_DEST_IP set)
uint8_t firstAudioChannel
uint32_t rxMatch
Bitmap of rxMatch criteria used.
QString mSfp1RemoteIPAddress
uint32_t sfp1DestPort
Specifies the destination (target) port number (if RX_MATCH_2022_DEST_PORT set)
bool SetRxChannelEnable(const NTV2Channel channel, bool enable)
uint32_t sfp2SourcePort
Specifies the source (sender) port number (if RX_MATCH_2022_SOURCE_PORT set)
QString mSfp1SrcIPAddress
bool readJson2022(const QJsonObject &json)
bool setupBoard2022(std::string deviceSpec)
Configures a SMPTE 2110 Receive Channel.
Configures a SMPTE 2110 Transmit Channel.
bool SetJson(const QJsonObject &topObj, bool verbose)
#define RX_MATCH_2110_DEST_IP
This file contains some structures, constants, classes and functions that are used in some of the dem...
bool SetTxStreamEnable(const NTV2Stream stream, bool enableSfp1, bool enableSfp2=(0))
eNTV2PacketInterval audioPktInterval
bool SetPTPPreferredGrandMasterId(const uint8_t id[8])
std::string sfp2SourceIP
Specifies the source (sender) IP address (if RX_MATCH_2022_SOURCE_IP set). If it's in the multiclass ...
#define RX_MATCH_2110_DEST_PORT
#define RX_MATCH_2110_SOURCE_IP
QString mSfp2RemoteIPAddress
bool Set4KModeEnable(const bool enable)
RxVideoChData2110 rxVideoCh[4]
bool DisableNetworkInterface(const eSFP sfp)
Configures a SMPTE 2022 Receive Channel.
std::string getLastError(void)
uint8_t sfp2RxMatch
Bitmap of rxMatch criteria used.
uint32_t remotePort[2]
Specifies the remote (destination) port number.
std::string getLastError()
virtual bool SetReference(const NTV2ReferenceSource inRefSource, const bool inKeepFramePulseSelect=(0))
Sets the device's clock reference source. See Video Output Clocking & Synchronization for more inform...
uint32_t sfp2DestPort
Specifies the destination (target) port number (if RX_MATCH_2022_DEST_PORT set)
QList< TransmitStruct2022 > mTransmit2022Channels
bool SetRxStreamConfiguration(const eSFP sfp, const NTV2Stream stream, const rx_2110Config &rxConfig)
bool SetRxChannelConfiguration(const NTV2Channel channel, const rx_2022_channel &rxConfig)
std::string destIP
Specifies the destination (target) IP address (if RX_MATCH_2110_DEST_IP set)
uint32_t sfp1SourcePort
Specifies the source (sender) port number (if RX_MATCH_2022_SOURCE_PORT set)
uint32_t numRxAudioChannels
bool SetNetworkConfiguration(const eSFP sfp, const IPVNetConfig &netConfig)
basic_json<> json
default specialization
virtual bool IsMBSystemReady(void)
#define RX_MATCH_2110_SOURCE_PORT
uint8_t ptpPreferredGMID[8]