Harald Welte | f7c2b20 | 2020-03-29 17:34:11 +0200 | [diff] [blame] | 1 | module BSSMAP_LE_Templates { |
| 2 | |
| 3 | /* BSSMAP-LE Templates, building on top of BSSAP_LE_Types. |
| 4 | * |
| 5 | * (C) 2017-2020 by Harald Welte <laforge@gnumonks.org> |
| 6 | * contributions by sysmocom - s.f.m.c. GmbH |
| 7 | * All rights reserved. |
| 8 | * |
| 9 | * Released under the terms of GNU General Public License, Version 2 or |
| 10 | * (at your option) any later version. |
| 11 | * |
| 12 | * SPDX-License-Identifier: GPL-2.0-or-later |
| 13 | */ |
| 14 | |
| 15 | import from General_Types all; |
| 16 | import from Osmocom_Types all; |
| 17 | import from GSM_Types all; |
| 18 | import from BSSAP_Types all; |
| 19 | import from BSSAP_LE_Types all; |
| 20 | import from BSSMAP_Templates all; |
| 21 | import from L3_Templates all; |
| 22 | |
| 23 | function ts_BSSMAP_LE_LcsCause(template (omit) BSSMAP_LE_LcsCause cause) |
| 24 | return template (omit) BSSMAP_LE_IE_LcsCause { |
| 25 | if (istemplatekind(cause, "omit")) { |
| 26 | return omit; |
| 27 | } |
| 28 | var template (omit) BSSMAP_LE_IE_LcsCause ie := { |
Neels Hofmeyr | 8a6863c | 2020-10-01 06:37:38 +0200 | [diff] [blame] | 29 | iei := BSSMAP_LE_IEI_LCS_CAUSE, |
| 30 | len := 1, |
Harald Welte | f7c2b20 | 2020-03-29 17:34:11 +0200 | [diff] [blame] | 31 | cause := cause, |
| 32 | diag_val := omit |
| 33 | } |
| 34 | return ie; |
| 35 | } |
| 36 | function tr_BSSMAP_LE_LcsCause(template BSSMAP_LE_LcsCause cause) |
| 37 | return template BSSMAP_LE_IE_LcsCause { |
| 38 | if (istemplatekind(cause, "omit")) { |
| 39 | return omit; |
| 40 | } |
| 41 | var template BSSMAP_LE_IE_LcsCause ie := { |
Neels Hofmeyr | 8a6863c | 2020-10-01 06:37:38 +0200 | [diff] [blame] | 42 | iei := BSSMAP_LE_IEI_LCS_CAUSE, |
Harald Welte | f7c2b20 | 2020-03-29 17:34:11 +0200 | [diff] [blame] | 43 | len := ?, |
| 44 | cause := cause, |
| 45 | diag_val := * |
| 46 | } |
| 47 | return ie; |
| 48 | } |
| 49 | |
| 50 | |
| 51 | function ts_BSSMAP_LE_GeographicLoc(template (omit) octetstring loc) |
| 52 | return template (omit) BSSMAP_LE_IE_GeographicLoc { |
| 53 | if (istemplatekind(loc, "omit")) { |
| 54 | return omit; |
| 55 | } |
| 56 | var template (omit) BSSMAP_LE_IE_GeographicLoc ie := { |
| 57 | iei := BSSMAP_LE_IEI_GEO_LOCATION, |
| 58 | len := 0, |
| 59 | location := loc |
| 60 | } |
| 61 | return ie; |
| 62 | } |
| 63 | function tr_BSSMAP_LE_GeographicLoc(template octetstring loc) |
| 64 | return template BSSMAP_LE_IE_GeographicLoc { |
| 65 | if (istemplatekind(loc, "omit")) { |
| 66 | return omit; |
| 67 | } |
| 68 | var template BSSMAP_LE_IE_GeographicLoc ie := { |
| 69 | iei := BSSMAP_LE_IEI_GEO_LOCATION, |
| 70 | len := ?, |
| 71 | location := loc |
| 72 | } |
| 73 | return ie; |
| 74 | } |
| 75 | |
| 76 | |
| 77 | |
| 78 | |
| 79 | template (value) PDU_BSSAP_LE ts_BSSAP_LE_BSSMAP := { |
| 80 | discriminator := '0'B, |
| 81 | spare := '0000000'B, |
| 82 | dlci := omit, |
| 83 | lengthIndicator := 0, /* overwritten by codec */ |
| 84 | pdu := { |
| 85 | bssmap := - |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | template (present) PDU_BSSAP_LE tr_BSSAP_LE_BSSMAP := { |
| 90 | discriminator := '0'B, |
| 91 | spare := '0000000'B, |
| 92 | dlci := *, |
| 93 | lengthIndicator := ?, |
| 94 | pdu := { |
| 95 | bssmap := ? |
| 96 | } |
| 97 | } |
| 98 | |
| 99 | template (value) PDU_BSSAP_LE ts_BSSAP_LE_DTAP(octetstring dtap, template (value) OCT1 dlci) := { |
| 100 | discriminator := '1'B, |
| 101 | spare := '0000000'B, |
| 102 | dlci := dlci, |
| 103 | lengthIndicator := 0, /* overwritten by codec */ |
| 104 | pdu := { |
| 105 | dtap := dtap |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | template (present) PDU_BSSAP_LE tr_BSSAP_LE_DTAP := { |
| 110 | discriminator := '1'B, |
| 111 | spare := '0000000'B, |
| 112 | dlci := *, |
| 113 | lengthIndicator := ?, |
| 114 | pdu := { |
| 115 | dtap := ? |
| 116 | } |
| 117 | } |
| 118 | |
| 119 | function ts_BSSMAP_LE_IMSI(template (omit) hexstring imsi) return template (omit) BSSMAP_LE_IE_IMSI { |
| 120 | if (istemplatekind(imsi, "omit")) { |
| 121 | return omit; |
| 122 | } |
| 123 | template (value) BSSMAP_LE_IE_IMSI res := { |
| 124 | iei := BSSMAP_LE_IEI_IMSI, |
| 125 | len := 0, |
| 126 | imsi := ts_MI_IMSI(valueof(imsi)) |
| 127 | }; |
| 128 | return res; |
| 129 | } |
| 130 | function tr_BSSMAP_LE_IMSI(template hexstring imsi) return template BSSMAP_LE_IE_IMSI { |
| 131 | if (istemplatekind(imsi, "omit")) { |
| 132 | return omit; |
| 133 | } |
| 134 | template BSSMAP_LE_IE_IMSI res := { |
| 135 | iei := BSSMAP_LE_IEI_IMSI, |
| 136 | len := ?, |
| 137 | imsi := tr_MI_IMSI(imsi) |
| 138 | }; |
| 139 | return res; |
| 140 | } |
| 141 | |
| 142 | template (value) BSSMAP_LE_IE_LocationType ts_BSSMAP_LE_LocType(template (value) BSSMAP_LE_LocInfo li, |
| 143 | template (omit) BSSMAP_LE_PosMethod pm := omit) := { |
| 144 | iei := BSSMAP_LE_IEI_LOCATION_TYPE, |
| 145 | len := 0, |
| 146 | loc_info := li, |
| 147 | pos_method := pm |
| 148 | } |
| 149 | template (present) BSSMAP_LE_IE_LocationType tr_BSSMAP_LE_LocType(template (present) BSSMAP_LE_LocInfo li, |
| 150 | template BSSMAP_LE_PosMethod pm := omit) := { |
| 151 | iei := BSSMAP_LE_IEI_LOCATION_TYPE, |
| 152 | len := ?, |
| 153 | loc_info := li, |
| 154 | pos_method := pm |
| 155 | } |
| 156 | |
| 157 | |
| 158 | /* Section 9.1 */ |
Neels Hofmeyr | fc64f53 | 2020-10-01 06:38:31 +0200 | [diff] [blame] | 159 | template (value) PDU_BSSAP_LE ts_BSSMAP_LE_PerfLocReq(BSSMAP_LE_LocInfo loc_info := BSSMAP_LE_LOC_INFO_CURRENT_GEOGRAPHIC_LOC, |
| 160 | template (value) BSSMAP_IE_CellIdentifier cell_id, |
| 161 | template (omit) hexstring imsi, |
| 162 | template (omit) octetstring bsslap_apdu := omit) |
Harald Welte | f7c2b20 | 2020-03-29 17:34:11 +0200 | [diff] [blame] | 163 | |
| 164 | modifies ts_BSSAP_LE_BSSMAP := { |
| 165 | pdu := { |
| 166 | bssmap := { |
| 167 | perf_loc_req := { |
| 168 | msg_type := BSSMAP_LE_PERFORM_LOC_REQ, |
| 169 | location_type := ts_BSSMAP_LE_LocType(loc_info), |
| 170 | cell_id := cell_id, |
| 171 | cm3 := omit, |
| 172 | lcs_client_type := omit, |
| 173 | chosen_channel := omit, |
| 174 | lcs_priority := omit, |
| 175 | lcs_qos := omit, |
| 176 | req_gps_ass_d := omit, |
Neels Hofmeyr | fc64f53 | 2020-10-01 06:38:31 +0200 | [diff] [blame] | 177 | bsslap_apdu := ts_BSSMAP_LE_APDU(BSSMAP_LE_PROT_BSSLAP, bsslap_apdu), |
Harald Welte | f7c2b20 | 2020-03-29 17:34:11 +0200 | [diff] [blame] | 178 | lcs_capability := omit, |
| 179 | packet_meas_rep := omit, |
| 180 | meas_cell_id_list := omit, |
| 181 | imsi := ts_BSSMAP_LE_IMSI(imsi), |
| 182 | imei := omit |
| 183 | } |
| 184 | } |
| 185 | } |
| 186 | } |
Neels Hofmeyr | fc64f53 | 2020-10-01 06:38:31 +0200 | [diff] [blame] | 187 | template (present) PDU_BSSAP_LE tr_BSSMAP_LE_PerfLocReq(BSSMAP_LE_LocInfo loc_info := BSSMAP_LE_LOC_INFO_CURRENT_GEOGRAPHIC_LOC, |
| 188 | template (present) BSSMAP_IE_CellIdentifier cell_id, |
| 189 | template hexstring imsi) |
Harald Welte | f7c2b20 | 2020-03-29 17:34:11 +0200 | [diff] [blame] | 190 | modifies tr_BSSAP_LE_BSSMAP := { |
| 191 | pdu := { |
| 192 | bssmap := { |
| 193 | perf_loc_req := { |
| 194 | msg_type := BSSMAP_LE_PERFORM_LOC_REQ, |
| 195 | location_type := tr_BSSMAP_LE_LocType(loc_info), |
| 196 | cell_id := cell_id, |
| 197 | cm3 := *, |
| 198 | lcs_client_type := *, |
| 199 | chosen_channel := *, |
| 200 | lcs_priority := *, |
| 201 | lcs_qos := *, |
| 202 | req_gps_ass_d := *, |
| 203 | bsslap_apdu := *, |
| 204 | lcs_capability := *, |
| 205 | packet_meas_rep := *, |
| 206 | meas_cell_id_list := *, |
| 207 | imsi := tr_BSSMAP_LE_IMSI(imsi), |
| 208 | imei := * |
| 209 | } |
| 210 | } |
| 211 | } |
| 212 | } |
| 213 | |
| 214 | |
| 215 | /* Section 9.2 */ |
Neels Hofmeyr | fc64f53 | 2020-10-01 06:38:31 +0200 | [diff] [blame] | 216 | template (value) PDU_BSSAP_LE ts_BSSMAP_LE_PerfLocResp(template (omit) octetstring geo_loc, |
| 217 | template (omit) BSSMAP_LE_LcsCause cause) |
Harald Welte | f7c2b20 | 2020-03-29 17:34:11 +0200 | [diff] [blame] | 218 | |
| 219 | modifies ts_BSSAP_LE_BSSMAP := { |
| 220 | pdu := { |
| 221 | bssmap := { |
| 222 | perf_loc_resp := { |
| 223 | msg_type := BSSMAP_LE_PERFORM_LOC_RESP, |
| 224 | geographic_loc := ts_BSSMAP_LE_GeographicLoc(geo_loc), |
| 225 | pos_data := omit, |
| 226 | deciph_keys := omit, |
| 227 | lcs_cause := ts_BSSMAP_LE_LcsCause(cause), |
| 228 | velocity_data := omit, |
| 229 | ganss_pos_data := omit |
| 230 | } |
| 231 | } |
| 232 | } |
| 233 | } |
Neels Hofmeyr | fc64f53 | 2020-10-01 06:38:31 +0200 | [diff] [blame] | 234 | template (present) PDU_BSSAP_LE tr_BSSMAP_LE_PerfLocResp(template octetstring geo_loc, |
| 235 | template BSSMAP_LE_LcsCause cause) |
Harald Welte | f7c2b20 | 2020-03-29 17:34:11 +0200 | [diff] [blame] | 236 | modifies tr_BSSAP_LE_BSSMAP := { |
| 237 | pdu := { |
| 238 | bssmap := { |
| 239 | perf_loc_resp := { |
| 240 | msg_type := BSSMAP_LE_PERFORM_LOC_RESP, |
| 241 | geographic_loc := tr_BSSMAP_LE_GeographicLoc(geo_loc), |
| 242 | pos_data := *, |
| 243 | deciph_keys := *, |
| 244 | lcs_cause := tr_BSSMAP_LE_LcsCause(cause), |
| 245 | velocity_data := *, |
| 246 | ganss_pos_data := * |
| 247 | } |
| 248 | } |
| 249 | } |
| 250 | } |
| 251 | |
| 252 | |
| 253 | /* Section 9.8 */ |
| 254 | template (value) PDU_BSSAP_LE ts_BSSMAP_LE_ConnInfo(BSSMAP_LE_ProtocolId prot_id, octetstring data, |
| 255 | template (omit) BSSMAP_LE_IE_Segmentation segm := omit) |
| 256 | modifies ts_BSSAP_LE_BSSMAP := { |
| 257 | pdu := { |
| 258 | bssmap := { |
| 259 | co_info := { |
| 260 | msg_type := BSSMAP_LE_CONN_ORIENTED_INFO, |
| 261 | bsslap_apdu := { |
| 262 | iei := BSSMAP_LE_IEI_APDU, |
| 263 | len := 0, |
Harald Welte | f7c2b20 | 2020-03-29 17:34:11 +0200 | [diff] [blame] | 264 | protocol_id := prot_id, |
Neels Hofmeyr | c4c2a91 | 2020-09-05 19:02:05 +0000 | [diff] [blame] | 265 | spare := '0'B, |
Harald Welte | f7c2b20 | 2020-03-29 17:34:11 +0200 | [diff] [blame] | 266 | data := data |
| 267 | }, |
| 268 | segmentation := segm |
| 269 | } |
| 270 | } |
| 271 | } |
| 272 | } |
| 273 | template (present) PDU_BSSAP_LE tr_BSSMAP_LE_ConnInfo(template (present) BSSMAP_LE_ProtocolId prot_id, |
| 274 | template (present) octetstring data, |
| 275 | template BSSMAP_LE_IE_Segmentation segm := omit) |
| 276 | modifies tr_BSSAP_LE_BSSMAP := { |
| 277 | pdu := { |
| 278 | bssmap := { |
| 279 | co_info := { |
| 280 | msg_type := BSSMAP_LE_CONN_ORIENTED_INFO, |
| 281 | bsslap_apdu := { |
| 282 | iei := BSSMAP_LE_IEI_APDU, |
| 283 | len := ?, |
Harald Welte | f7c2b20 | 2020-03-29 17:34:11 +0200 | [diff] [blame] | 284 | protocol_id := prot_id, |
Neels Hofmeyr | c4c2a91 | 2020-09-05 19:02:05 +0000 | [diff] [blame] | 285 | spare := '0'B, |
Harald Welte | f7c2b20 | 2020-03-29 17:34:11 +0200 | [diff] [blame] | 286 | data := data |
| 287 | }, |
| 288 | segmentation := segm |
| 289 | } |
| 290 | } |
| 291 | } |
| 292 | } |
| 293 | |
Neels Hofmeyr | fc64f53 | 2020-10-01 06:38:31 +0200 | [diff] [blame] | 294 | template (value) PDU_BSSAP_LE ts_BSSMAP_LE_PerfLocAbort(BSSMAP_LE_LcsCause cause) |
| 295 | modifies ts_BSSAP_LE_BSSMAP := { |
| 296 | pdu := { |
| 297 | bssmap := { |
| 298 | perf_loc_abort := { |
| 299 | msg_type := BSSMAP_LE_PERFORM_LOC_ABORT, |
| 300 | lcs_cause := ts_BSSMAP_LE_LcsCause(cause) |
| 301 | } |
| 302 | } |
| 303 | } |
| 304 | } |
Harald Welte | f7c2b20 | 2020-03-29 17:34:11 +0200 | [diff] [blame] | 305 | |
Neels Hofmeyr | fc64f53 | 2020-10-01 06:38:31 +0200 | [diff] [blame] | 306 | template (present) PDU_BSSAP_LE tr_BSSMAP_LE_PerfLocAbort(template BSSMAP_LE_LcsCause cause) |
| 307 | modifies tr_BSSAP_LE_BSSMAP := { |
| 308 | pdu := { |
| 309 | bssmap := { |
| 310 | perf_loc_abort := { |
| 311 | msg_type := BSSMAP_LE_PERFORM_LOC_ABORT, |
| 312 | lcs_cause := tr_BSSMAP_LE_LcsCause(cause) |
| 313 | } |
| 314 | } |
| 315 | } |
| 316 | } |
Harald Welte | f7c2b20 | 2020-03-29 17:34:11 +0200 | [diff] [blame] | 317 | |
| 318 | /* Section 9.10 */ |
| 319 | template (value) PDU_BSSAP_LE ts_BSSMAP_LE_Reset(myBSSMAP_Cause cause) modifies ts_BSSAP_LE_BSSMAP := { |
| 320 | pdu := { |
| 321 | bssmap := { |
| 322 | reset := { |
| 323 | msg_type := BSSMAP_LE_RESET, |
| 324 | cause := ts_BSSMAP_IE_Cause(enum2int(cause)) |
| 325 | } |
| 326 | } |
| 327 | } |
| 328 | } |
| 329 | template (present) PDU_BSSAP_LE tr_BSSMAP_LE_Reset modifies tr_BSSAP_LE_BSSMAP := { |
| 330 | pdu := { |
| 331 | bssmap := { |
| 332 | reset := { |
| 333 | msg_type := BSSMAP_LE_RESET, |
| 334 | cause := ? |
| 335 | } |
| 336 | } |
| 337 | } |
| 338 | } |
| 339 | |
| 340 | /* Section 9.11 */ |
| 341 | template (value) PDU_BSSAP_LE ts_BSSMAP_LE_ResetAck modifies ts_BSSAP_LE_BSSMAP := { |
| 342 | pdu := { |
| 343 | bssmap := { |
Neels Hofmeyr | a732688 | 2020-10-12 18:07:27 +0000 | [diff] [blame] | 344 | reset_ack := { |
Harald Welte | f7c2b20 | 2020-03-29 17:34:11 +0200 | [diff] [blame] | 345 | msg_type := BSSMAP_LE_RESET_ACK |
| 346 | } |
| 347 | } |
| 348 | } |
| 349 | } |
| 350 | template (present) PDU_BSSAP_LE tr_BSSMAP_LE_ResetAck modifies tr_BSSAP_LE_BSSMAP := { |
| 351 | pdu := { |
| 352 | bssmap := { |
| 353 | reset_ack := { |
| 354 | msg_type := BSSMAP_LE_RESET_ACK |
| 355 | } |
| 356 | } |
| 357 | } |
| 358 | } |
| 359 | |
| 360 | function ts_BSSMAP_LE_APDU(BSSMAP_LE_ProtocolId prot_id, template (omit) octetstring data) |
| 361 | return template (omit) BSSMAP_LE_IE_APDU { |
| 362 | var BSSMAP_LE_IE_APDU ie := { |
| 363 | iei := BSSMAP_LE_IEI_APDU, |
| 364 | len := 0, // overwritten |
Neels Hofmeyr | c4c2a91 | 2020-09-05 19:02:05 +0000 | [diff] [blame] | 365 | protocol_id := prot_id, |
| 366 | spare := '0'B |
Harald Welte | f7c2b20 | 2020-03-29 17:34:11 +0200 | [diff] [blame] | 367 | } |
| 368 | if (istemplatekind(data, "omit")) { |
| 369 | return omit; |
| 370 | } |
| 371 | ie.data := valueof(data); |
| 372 | return ie; |
| 373 | } |
| 374 | |
| 375 | function tr_BSSMAP_LE_APDU(template BSSMAP_LE_ProtocolId prot_id, template octetstring data) |
| 376 | return template BSSMAP_LE_IE_APDU { |
| 377 | var template BSSMAP_LE_IE_APDU ie := { |
| 378 | iei := BSSMAP_LE_IEI_APDU, |
| 379 | len := ?, |
Neels Hofmeyr | c4c2a91 | 2020-09-05 19:02:05 +0000 | [diff] [blame] | 380 | protocol_id := prot_id, |
| 381 | spare := '0'B |
Harald Welte | f7c2b20 | 2020-03-29 17:34:11 +0200 | [diff] [blame] | 382 | } |
| 383 | if (istemplatekind(data, "omit")) { |
| 384 | return omit; |
| 385 | } else if (istemplatekind(data, "*")) { |
| 386 | return *; |
| 387 | } |
Neels Hofmeyr | c4c2a91 | 2020-09-05 19:02:05 +0000 | [diff] [blame] | 388 | ie.data := data; |
Harald Welte | f7c2b20 | 2020-03-29 17:34:11 +0200 | [diff] [blame] | 389 | return ie; |
| 390 | } |
| 391 | |
| 392 | |
| 393 | /* Section 9.12 */ |
| 394 | template (value) PDU_BSSAP_LE ts_BSSMAP_LE_PerformLocInfo(BSSMAP_IE_CellIdentifier cell_id, |
| 395 | BSSMAP_LE_ProtocolId prot_id, |
| 396 | template (omit) octetstring data) |
| 397 | modifies ts_BSSAP_LE_BSSMAP := { |
| 398 | pdu := { |
| 399 | bssmap := { |
| 400 | perf_loc_info := { |
| 401 | msg_type := BSSMAP_LE_PERFORM_LOC_INFO, |
| 402 | cell_id := cell_id, |
| 403 | bsslap_apdu := ts_BSSMAP_LE_APDU(prot_id, data) |
| 404 | } |
| 405 | } |
| 406 | } |
| 407 | } |
| 408 | template (present) PDU_BSSAP_LE tr_BSSMAP_LE_PerformLocInfo(template (present) BSSMAP_IE_CellIdentifier cell_id, |
| 409 | template BSSMAP_LE_ProtocolId prot_id, |
| 410 | template octetstring data) |
| 411 | modifies tr_BSSAP_LE_BSSMAP := { |
| 412 | pdu := { |
| 413 | bssmap := { |
| 414 | perf_loc_info := { |
| 415 | msg_type := BSSMAP_LE_PERFORM_LOC_INFO, |
| 416 | cell_id := cell_id, |
| 417 | bsslap_apdu := tr_BSSMAP_LE_APDU(prot_id, data) |
| 418 | } |
| 419 | } |
| 420 | } |
| 421 | } |
| 422 | |
| 423 | /* return Layer3 octetstring inside BSSAP-LE PDU */ |
| 424 | function f_bssap_le_extract_l3(PDU_BSSAP_LE bssap) return template octetstring { |
| 425 | if (ischosen(bssap.pdu.bssmap)) { |
| 426 | return omit; |
| 427 | } else { |
| 428 | return bssap.pdu.dtap; |
| 429 | } |
| 430 | } |
| 431 | |
| 432 | |
| 433 | template PDU_BSSAP_LE tr_BSSMAP_LE_Paging(template hexstring imsi_digits := ?, |
| 434 | template OCT4 tmsi := *, |
| 435 | template BSSMAP_IE_ChannelNeeded chneed := *) |
| 436 | modifies tr_BSSAP_LE_BSSMAP := { |
| 437 | pdu := { |
| 438 | bssmap := { |
| 439 | paging := { |
| 440 | messageType := '52'O, |
| 441 | iMSI := tr_BSSMAP_Imsi(imsi_digits), |
| 442 | tMSI := tr_BSSMAP_IE_TMSI(tmsi) ifpresent, |
| 443 | cellIdentifierList := ?, |
| 444 | channelNeeded := chneed, |
| 445 | eMLPP_Priority := omit, |
| 446 | pagingInformation := omit /* only VGCS/VBS flag */ |
| 447 | } |
| 448 | } |
| 449 | } |
| 450 | } |
| 451 | |
| 452 | |
| 453 | |
| 454 | |
| 455 | } with { encode "RAW" }; |