Copyright © 2025 the Contributors to the Web Serial API Specification, published by the Web Platform Incubator Community Group under the W3C Community Contributor License Agreement (CLA). A human-readable summary is available.
본 명세는 Web Platform Incubator Community Group에서 발행하였습니다. W3C 표준이 아니며, W3C 표준 트랙에도 포함되어 있지 않습니다. W3C Community Contributor License Agreement (CLA)에 따라 제한적 옵트아웃 및 기타 조건이 적용됨을 참고하세요. W3C Community and Business Groups에 대해 더 알아보세요.
본 문서는 진행 중인 작업입니다. 모든 기여를 환영합니다.본 명세에 대한 논의는 GitHub Issues를 사용하는 것이 권장됩니다.
Serial 인터페이스
WebIDL[Exposed=(DedicatedWorker, Window), SecureContext]
interface Serial : EventTarget {
attribute EventHandler onconnect;
attribute EventHandler ondisconnect;
Promise<sequence<SerialPort>> getPorts();
[Exposed=Window] Promise<SerialPort> requestPort(optional SerialPortRequestOptions options = {});
};
requestPort() 메서드 단계는 다음과 같습니다:
serial"을 사용할 수 없다면,
reject
promise를 "SecurityError" DOMException와 함께 반환합니다.
SecurityError"
DOMException와 함께 반환합니다.
filters"]가 존재한다면,
각 filter에 대해 다음 단계를 수행합니다:
bluetoothServiceClassId"]
가 존재한다면:
usbVendorId"]
가 있으면,
reject
promise를 TypeError와
함께 반환합니다.
usbProductId"]
가 있으면,
reject
promise를 TypeError와
함께 반환합니다.
usbVendorId"]가 없다면,
reject
promise를 TypeError와
함께 반환합니다.
BluetoothServiceUUID를
순회합니다:
allowedBluetoothServiceClassIds"]가
존재하고 포함한다면
uuid:
SerialPort로
생성합니다.
SerialPort로 설정합니다.
filters"]가 있을 시 필터와
일치하는 포트, 그렇지 않으면 모든 포트 목록을 표시합니다.
NotFoundError"
DOMException와
함께 반환하고 이 단계를 중단합니다.
SerialPort로 설정합니다.
시리얼 포트는 사용 가능하려면 유선 시리얼 포트가 시스템에 물리적으로 연결되어 있거나, 무선 시리얼 포트가 해당 포트를 호스팅하는 무선 장치가 시스템에 등록되어 있는 경우입니다.
WebIDLdictionary SerialPortRequestOptions {
sequence<SerialPortFilter> filters;
sequence<BluetoothServiceUUID> allowedBluetoothServiceClassIds;
};
filters 멤버
allowedBluetoothServiceClassIds 멤버
BluetoothServiceUUID
값들의 목록.
Bluetooth 포트가 사용자에게 표시되는 포트 목록에서 제외되며, 해당 서비스 클래스 ID가 이 목록에 있지 않으면 표시되지 않습니다.
WebIDLdictionary SerialPortFilter {
unsigned short usbVendorId;
unsigned short usbProductId;
BluetoothServiceUUID bluetoothServiceClassId;
};
usbVendorId 멤버
usbProductId 멤버
bluetoothServiceClassId 멤버
시리얼 포트 port가 filter를 일치하면
true를 반환합니다. 단계는 다음과 같습니다:
getInfo() 호출 값으로 설정합니다.
bluetoothServiceClassId"]가
있다면:
false 반환bluetoothServiceClassId"]와
info["bluetoothServiceClassId"]가
같으면 true 반환
false 반환usbVendorId"]가 없으면
true 반환
false 반환usbVendorId"]와
filter["usbVendorId"]가 다르면
false 반환
usbProductId"]가 없으면
true 반환
usbProductId"]와
filter["usbProductId"]가 다르면
false 반환
true 반환
시리얼 포트 port가 SerialPortFilter 시퀀스에서 하나라도 일치하면 true를 반환합니다.
true를 반환합니다.
false를 반환합니다.
getPorts() 메서드 단계는 다음과 같습니다:
SecurityError"
DOMException와 함께 반환합니다.
requestPort() 호출 결과로
사용자가 사이트에 접근을 허락한
사용 가능한 시리얼 포트들의 시퀀스로 설정합니다.
SerialPort의 시퀀스로 설정합니다.
onconnect는
이벤트 핸들러
IDL 속성입니다.
connect 이벤트 타입에 해당합니다.
ondisconnect는
이벤트 핸들러
IDL 속성입니다.
disconnect 이벤트 타입에
해당합니다.
WebIDL[Exposed=(DedicatedWorker,Window), SecureContext]
interface SerialPort : EventTarget {
attribute EventHandler onconnect;
attribute EventHandler ondisconnect;
readonly attribute boolean connected;
readonly attribute ReadableStream readable;
readonly attribute WritableStream writable;
SerialPortInfo getInfo();
Promise<undefined> open(SerialOptions options);
Promise<undefined> setSignals(optional SerialOutputSignals signals = {});
Promise<SerialInputSignals> getSignals();
Promise<undefined> close();
Promise<undefined> forget();
};
이 인터페이스의 메서드는 일반적으로 비동기적으로 완료되며, 작업을 시리얼 포트 태스크 소스에 큐잉합니다.
SerialPort에 대한 부모 가져오기 알고리즘은,
Serial 인스턴스를 반환합니다. 이는 Navigator
객체의 serial getter로 반환되는 것과 같습니다. (해당 SerialPort의 관련 전역 객체 사용)
SerialPort의 인스턴스는 아래 표에 설명된 내부 슬롯들과 함께 생성됩니다:
| 내부 슬롯 | 초기 값 | 설명 (비규범) |
|---|---|---|
| [[state]] |
"closed"
|
SerialPort의 활성 상태를 추적
|
| [[bufferSize]] | undefined | 송수신을 위해 버퍼링할 데이터의 양 |
| [[connected]] |
false
|
시리얼 포트의 논리적 연결 상태를 나타내는 플래그 |
| [[readable]] |
null
|
포트에서 데이터를 수신하는 ReadableStream
|
| [[readFatal]] |
false
|
포트에서 치명적인 읽기 오류가 발생했음을 나타내는 플래그 |
| [[writable]] |
null
|
포트로 데이터를 전송하는 WritableStream
|
| [[writeFatal]] |
false
|
포트에서 치명적인 쓰기 오류가 발생했음을 나타내는 플래그 |
| [[pendingClosePromise]] |
null
|
Promise로,
readable 및
writable이 닫힐 때까지 대기하는 용도
|
onconnect는
이벤트 핸들러
IDL 속성입니다.
connect 이벤트 타입에 해당합니다.
사용자가 이전에 requestPort()를 호출한 결과로 사이트가 접근을
허용받은 시리얼 포트가
논리적으로 연결되면, 다음 단계를 수행합니다:
SerialPort로 설정합니다.
[[connected]]를 true로 설정합니다.
connect이고 대상은 port이며,
bubbles 속성은
true로 초기화됩니다.
시리얼 포트가 논리적으로 연결되었다고 판단되는 경우는, 유선 시리얼 포트의 경우 시스템에 물리적으로 연결된 경우거나, 무선 시리얼 포트의 경우 시스템이 무선 장치(예: 활성 Bluetooth L2CAP 채널)에 적극적으로 연결된 경우입니다.
ondisconnect는
이벤트 핸들러
IDL 속성입니다.
disconnect 이벤트 타입에 해당합니다.
사용자가 이전에 requestPort()를 호출한 결과로 사이트가 접근을
허용받은 시리얼 포트가
더 이상 논리적으로 연결되어 있지 않다면, 다음 단계를 수행합니다:
SerialPort로 설정합니다.
[[connected]]를 false로 설정합니다.
disconnect이고 대상은 port이며,
bubbles 속성은
true로 초기화됩니다.
getInfo() 메서드 단계는 다음과 같습니다:
usbVendorId"]를
장치의 vendor ID 값으로 설정
usbProductId"]를
장치의 product ID 값으로 설정
bluetoothServiceClassId"]
를 Bluetooth 서비스의 서비스 클래스 UUID로 설정
WebIDLdictionary SerialPortInfo {
unsigned short usbVendorId;
unsigned short usbProductId;
BluetoothServiceUUID bluetoothServiceClassId;
};
usbVendorId 멤버
undefined입니다.
usbProductId 멤버
undefined입니다.
bluetoothServiceClassId 멤버
BluetoothServiceUUID입니다.
그렇지 않으면 undefined입니다.
open() 메서드 단계는 다음과 같습니다:
[[state]]가 "closed"가 아니라면,
promise를 "InvalidStateError"
DOMException과 함께 reject
하고
promise를 반환합니다.
dataBits"]가 7 또는 8이 아니면,
promise를 TypeError와 함께
reject 하고,
promise를 반환합니다.
stopBits"]가 1 또는 2가 아니면,
promise를 TypeError와 함께
reject 하고,
promise를 반환합니다.
bufferSize"]가 0이면,
promise를 TypeError와 함께
reject 하고,
promise를 반환합니다.
bufferSize"]가
구현체에서 지원 가능한 크기보다 크면, promise를 TypeError와 함께
reject 하고,
promise를 반환합니다.
[[state]]를 "opening"으로 설정합니다.
NetworkError"
DOMException과
함께 하고,
단계를 중단합니다.
[[state]]를 "opened"로 설정합니다.
[[bufferSize]]를
options["bufferSize"]로 설정합니다.
undefined와 함께 합니다.
WebIDLdictionary SerialOptions {
[EnforceRange] required unsigned long baudRate;
[EnforceRange] octet dataBits = 8;
[EnforceRange] octet stopBits = 1;
ParityType parity = "none";
[EnforceRange] unsigned long bufferSize = 255;
FlowControlType flowControl = "none";
};
baudRate 멤버
baudRate는 이 딕셔너리의 유일한 필수
멤버입니다.
다른 연결 파라미터에는 일반적인 기본값이 존재하지만, 개발자는 연결하려는 특정 장치에 맞는 값을 반드시 확인해야 하며 설명서를 참고할 필요가 있습니다.
일부 값이 자주 사용되긴 하지만 표준 통신 속도가 정해져 있지 않습니다. 이 파라미터를 필수로 하는 것은 이 명세에서 임의의 기본값을 설정할 경우의 혼란을
줄여주기 위함입니다.
dataBits 멤버
stopBits 멤버
parity 멤버
bufferSize
멤버
flowControl 멤버
WebIDLenum ParityType {
"none",
"even",
"odd"
};
none
even
odd
WebIDLenum FlowControlType {
"none",
"hardware"
};
none
hardware
connected getter의 단계는 다음과 같습니다:
[[connected]]를 반환합니다.
readable getter 단계는 다음과 같습니다:
[[readable]]가 null이 아니면
this.[[readable]]를 반환한다.
[[state]]가 "opened"가 아니면,
null을 반환한다.
[[readFatal]]이 true이면
null을 반환한다.
ReadableStream으로 둔다.
[[readable]]에 대하여.
[[readable]]의
현재 BYOB
요청 뷰가 null이 아니면,
desiredSize를 this.[[readable]]의
현재 BYOB
요청 뷰의
바이트
길이로 설정한다.
[[readable]]의
현재
BYOB 요청 뷰가
null이 아니라면, bytes
를
this.[[readable]]의
현재
BYOB 요청 뷰에 기록하고,
view를 this.[[readable]]의
현재
BYOB 요청 뷰로 둔다.
Uint8Array를
this의 관련
렐름에서 생성해 대입한다.
[[readable]]에 추가한다.
[[readable]]에
"BufferOverrunError" DOMException을
전달하고
읽기 스트림 닫기 처리
단계를 실행한다.
[[readable]]에
"BreakError" DOMException을
전달하고
읽기 스트림 닫기 처리
단계를 실행한다.
[[readable]]에
"FramingError" DOMException을
전달하고
읽기 스트림 닫기 처리
단계를 실행한다.
[[readable]]에
"ParityError" DOMException을
전달하고
읽기 스트림 닫기 처리
단계를 실행한다.
[[readable]]에
"UnknownError"
DOMException을
전달하고,
읽기 스트림 닫기 처리
단계를 실행한다.
[[readFatal]]을
true로 설정
[[readable]]에
"NetworkError"
DOMException을
전달한다.
[[bufferSize]]로 설정하여 stream을 구성한다.
[[readable]]를 stream으로 둔다.
[[readable]]를 null로 설정한다.
[[writable]]가 null이고
this.[[pendingClosePromise]]가
null이 아니면,
resolve
this.[[pendingClosePromise]]를
undefined로 한다.
writable getter 단계는 다음과 같습니다:
[[writable]]가 null이 아니면
this.[[writable]]를 반환한다.
[[state]]가 "opened"가 아니면
null을 반환한다.
[[writeFatal]]이 true이면
null을 반환한다.
WritableStream으로 둔다.
BufferSource 타입의
IDL 값으로
변환될 수
없다면,
promise를 TypeError와
함께 reject하고
promise를 반환한다. 그렇지 않으면, 변환 결과를 source에 저장한다.
undefined를 전달한다.
UnknownError"
DOMException을
전달한다.
[[writeFatal]]을
true로 설정한다.
NetworkError"
DOMException을
전달한다.
undefined를 전달한다.
undefined를 전달한다.
[[bufferSize]]로,
sizeAlgorithm을 바이트 단위 사이즈 계산 알고리즘으로 설정한다.
[[writable]]를 stream으로 설정한다.
[[writable]]를 null로 설정한다.
[[readable]]가 null이고
this.[[pendingClosePromise]]가
null이 아니면,
resolve
this.[[pendingClosePromise]]를
undefined로 한다.
setSignals() 메서드의 단계는 다음과
같습니다:
[[state]]가 "opened"가 아니라면,
promise를 "InvalidStateError"
DOMException으로 reject하고
promise를 반환합니다.
TypeError로
reject하고
promise를 반환합니다.
dataTerminalReady"]
가 존재하면, 운영체제에 시리얼 포트의 "data terminal ready" 또는 "DTR" 신호를 assert(true일 때)하거나
deassert(false일 때)하도록 요청합니다.
requestToSend"]가
존재하면, 운영체제에 시리얼 포트의 "request to send" 또는 "RTS" 신호를 assert(true일 때)하거나
deassert(false일 때)하도록 요청합니다.
break"]가 존재하면,
운영체제에 시리얼 포트의 "break" 신호를 assert(true일 때)하거나 deassert(false일 때)하도록
요청합니다.
NetworkError"
DOMException으로
reject합니다.
undefined를 전달합니다.
WebIDLdictionary SerialOutputSignals {
boolean dataTerminalReady;
boolean requestToSend;
boolean break;
};
dataTerminalReady
requestToSend
break
getSignals() 메서드의 단계는 다음과 같습니다:
[[state]]가 "opened"가 아니라면,
promise를 "InvalidStateError"
DOMException으로 reject하고
promise를 반환합니다.
NetworkError"
DOMException으로
reject하며 이 단계를 중단합니다.
true, 아니면 false로 둡니다.
true, 아니면
false로 둡니다.
true, 아니면
false로 둡니다.
true, 아니면
false로 둡니다.
dataCarrierDetect"
→ dataCarrierDetect,
"clearToSend" →
clearToSend,
"ringIndicator" →
ringIndicator,
"dataSetReady" →
dataSetReady ]»로 둡니다.
WebIDLdictionary SerialInputSignals {
required boolean dataCarrierDetect;
required boolean clearToSend;
required boolean ringIndicator;
required boolean dataSetReady;
};
dataCarrierDetect
멤버
clearToSend
멤버
ringIndicator
멤버
dataSetReady
멤버
close() 메서드의 단계는 다음과 같습니다:
[[state]]가 "opened"가 아니면,
promise를 "InvalidStateError"
DOMException으로 reject하고
promise를 반환한다.
[[readable]]에 호출한 결과값 또는
undefined로
resolve된 promise로 둔다.
this.[[readable]]가 null일 경우.
[[writable]]에 호출한 결과값 또는
undefined로
resolve된 promise로 둔다.
this.[[writable]]가 null일 경우.
[[readable]]와
this.[[writable]] 모두 null이면,
pendingClosePromise를
undefined로 resolve한다.
[[pendingClosePromise]]를
pendingClosePromise로 설정한다.
[[state]]를 "closing"으로 둔다.
[[state]]
를 "closed"로 둔다.[[readFatal]]와
this.[[writeFatal]]를
false로 둔다.
[[pendingClosePromise]]
를 null로 둔다.undefined로.
[[pendingClosePromise]]
를 null로 둔다.
forget() 메서드의 단계는 다음과 같습니다:
[[state]]를 "forgetting"으로 설정한다.
requestPort() 호출 결과로
사이트에 접근 허가된 시리얼 포트 목록에서 this를 제거한다.
[[state]]를 "forgotten"으로 설정한다.
undefined로 한다.
이 명세는 웹사이트가 접근할 수 있는 포트 집합을 제한하기 위해 https://github.com/WICG/serial 리포지토리의 차단 목록 파일에 의존합니다.
Bluetooth 서비스 클래스 ID 차단 목록을 분석한 결과는 URL url에서
커스텀 서비스 ID를 나타내는 리스트의 UUID값입니다.
Serial Port Profile 서비스 클래스 ID는
값이
"00001101-0000-1000-8000-00805f9b34fb"인
BluetoothServiceUUID
입니다.
{{BluetoothServiceUUID} serviceUuid}가
만약 다음 단계를 거쳐 true를 반환하면
차단된 Bluetooth 서비스 클래스 UUID입니다:
BluetoothUUID.getService()
를 serviceUuid로 호출한 결과로 둡니다.
true를 반환합니다.
false를 반환합니다.
-0000-1000-8000-00805f9b34fb",
true를 반환합니다.
false를 반환합니다.
이 명세는 serial 속성이
Navigator
객체에 노출할 메서드의 사용 여부를 제어하는 기능을 정의합니다.
이 기능의 이름은 "serial"입니다.
이 기능에 대한 기본 허용
사용 목록(allowlist)은
'self'입니다.
이 절은 비규범적(참고용)입니다.
이 API는 [WEB-BLUETOOTH] 및 [WEBUSB]과 비슷한 보안 위험을 내포하며 이들로부터 얻은 교훈이 본 명세에도 적용됩니다. 주요 위협은 다음과 같습니다:requestPort() 패턴이며, 이는 사용자의 상호작용이 필요하고
한 번에 하나의 장치만 접근 권한을 부여하도록 합니다. 이로 인해 사이트가 연결된 모든 장치를 열거하여 취약한 장치가 있는지 확인하는 드라이브-바이 공격이 방지됩니다. 사이트는 장치 접근 요청 시
사용자에게 명확하게 알릴 필요가 있습니다. 구현에서는 또한 사이트가 장치와 통신 중임을 시각적으로 표시하거나, 언제든 권한을 취소할 수 있는 제어 기능을 제공할 수 있습니다.
이 명세는 네트워크 공격자에 의해 악의적 코드가 삽입되는 것을 방지하기 위해 보안 컨텍스트에서 사이트가 제공되어야 함을 요구합니다. 이를 통해 권한 결정 시 사용자에게 표시되는 사이트의 신원이 정확함을 보장합니다. 또한, 본 명세는 교차 출처 iframe에서 API 사용을 허용하기 전에 반드시 [PERMISSIONS-POLICY]를 통한 명시적 설정을 요구합니다. [CSP3]와 함께 사용할 때 이러한 메커니즘은 악의적 코드 삽입 공격으로부터 보호합니다.
남은 문제는 피싱 공격을 통한 장치 악용입니다. 공격자가 사용자를 속여 악성 사이트에 장치 접근 권한을 부여하도록 만들 수 있습니다. 이 공격은 장치의 본래 기능을 악용하거나, 악성 펌웨어를 설치해 나중에 호스트 컴퓨터를 공격하는 데 사용될 수 있습니다. 호스트 소프트웨어는 연결된 장치의 입력을 적절히 검증하지 않아 취약해질 수 있습니다. 보안 연구에 따르면 연결된 장치를 신뢰하지 않는 쪽으로 소프트웨어 벤더의 인식을 유도하고 있습니다.
이러한 유형의 공격을 완전히 막을 수 있는 메커니즘은 없습니다. 페이지에서 장치로 보낼 데이터는 불투명한 바이트 시퀀스이기 때문입니다. 특정 데이터 유형 전송을 차단하려는 시도를 하더라도 장치 제조사가 우회 방법을 마련할 가능성이 높습니다.
사용자 에이전트는 장치 접근을 추가로 통제할 수 있는 메커니즘을 구현할 수 있습니다:
requestPort()를 호출할 수 없도록 하는 설정.
시스템 관리자는 엔터프라이즈 정책을 사용해 조직 전체에 이러한 설정을 적용할 수 있습니다. 예를 들어 관리자가 특정 사이트에만 특정 장치의 접근을 허용하고, 나머지 사이트에는 허용하지 않을 수 있습니다.
또한, USB 및 Bluetooth의 경우 메타데이터로 해당 장치의 제조사/모델을 식별할 수 있는 out-of-band 기제가 정의되어 있기 때문에, 이러한 취약 장치 목록 관리가 꽤 효과적으로 작동합니다. 하지만 일반 USB/Bluetooth-시리얼 어댑터나 DB-25, DE-9, RJ-45 커넥터 등 "진짜" 시리얼 포트는 연결된 장치의 신원을 알 수 있는 메타데이터가 없기 때문에 접근 차단이 불가능합니다.
이 절은 비규범적(참고용)입니다.
시리얼 포트와 시리얼 장치에는 두 종류의 민감한 정보가 존재합니다. 포트가 USB 또는 Bluetooth 장치인 경우, 벤더 및 제품 ID(제조사와 모델 명시)는 물론, 일련번호나 MAC 주소가 해당됩니다. 또한 시리얼 장치 자체에 시리얼 포트를 통해 명령어로 얻을 수 있는 자체 식별자가 있을 수 있습니다. 장치에는 이 외에도 식별 가능 여부와 상관없이 추가 개인 정보가 저장될 수 있습니다.장치 권한을 관리하기 위해, 구현에서는 USB 벤더 ID, 제품 ID, 시리얼 번호 등 장치 식별자를 사용자 환경설정 파일에 저장하여 사용자가 사이트에 접근을 허용한 장치의 안정적인 식별자로 삼을 수 있습니다. 이러한 정보는 사이트에 직접 노출되지 않으며, 권한이 철회되거나 사이트 데이터가 삭제될 때 함께 제거됩니다.
접근 권한이 부여된 후 페이지가 장치로 보낼 수 있는 명령을 통해, 페이지가 장치에 저장된 여러 민감한 정보에 접근할 수 있게 될 수 있습니다. 7. 보안 고려사항에서 언급한 바와 같이 이러한 정보 접근을 원천적으로 차단하는 것은 비현실적이며 바람직하지도 않습니다.
구현에서는 사용자가 어떤 장치에 대해 어떤 사이트에 접근을 허용하는지 완벽한 통제를 제공해야 하며, 사용자 상호작용 없이 권한이 부여되지 않아야 합니다. 이것이 requestPort()
메서드의 설계 목적입니다. 이 방식은 사이트가 연결된 모든 장치를 은밀히 열거/수집하는 것을 막습니다. 이는 파일 선택기 UI와 유사합니다. 사이트는 파일 시스템 구조를 전혀 모르고, 오직
사용자가 직접 선택한 파일/디렉터리만 알 수 있습니다. 구현에서는 사이트가 이런 권한을 사용 중일 때 탭이나 주소창에 아이콘 등 시각적 표시로 알릴 수 있습니다.
"프라이빗" 또는 "시크릿" 브라우징 모드를 지원하는 구현은 반드시 일반 프로필의 권한이 당해 세션에 이월되지 않아야 하며, 세션 내에서 부여된 권한도 세션 종료 시 보존되지 않도록 해야 합니다. 사용자가 이런 세션에서 장치 접근을 허용할 때 경고할 수도 있습니다. 이는 사용자가 수동으로 식별 정보를 입력하는 경우와 마찬가지로, 위에서 언급한 식별자 및 장치와의 통신에서 얻을 수 있는 기타 고유 특성을 통해 세션 간에 사용자를 식별할 수 있기 때문입니다.
사용자는 이 API로 장치 접근 권한을 부여할 때 웹 보안 모델의 기존 경계가 어떻게 깨질 수 있는지 잘 모를 수 있습니다. 보안 UI와 문서는 사이트가 장치에 대한 접근 권한을 부여 받을 경우 해당 장치와 그 안의 데이터 전체에 대한 완전한 제어 권한이 허용됨을 명확히 안내해야 합니다.
비규범적(참고용)으로 표시된 절 외에도, 본 명세의 모든 작성 가이드라인, 다이어그램, 예시, 참고는 규범적이지 않습니다. 그 밖의 모든 내용은 규범적입니다.
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: