- 마지막 업데이트
웹에서 게임 실행
이해하기
웹에서 스토브 런처를 호출해 게임을 실행하기 위한 연동 기능이에요.
약관 동의 → 게임점검 체크 → 화이트리스트 체크 → 런처 실행 흐름을 스토브 JS Service 모듈로 통합 연동할 수 있어요.
스토브 공홈, 게임별 공홈, 런칭 페이지 등 스토브 도메인 하위의 웹 환경에서 사용해요.
적용 환경
게임 실행 연동은 스토브 인증을 사용하는 웹 서비스 도메인에서 동작해요.
외부 도메인을 사용해야 하는 경우 별도 SSL 인증서 발급과 인프라 설정이 필요하니 담당 스토브 기술PM과 사전 협의가 필요해요.
| 구분 | 환경 | 설명 |
|---|---|---|
| Sandbox | https://js-cdn.gate8.com | 개발/QA 환경. gate8 도메인 사용. |
| Live | https://js-cdn.onstove.com | 실서비스 환경. onstove 도메인 사용. |
| 웹 도메인 | xxx.game.onstove.com | 스토브 인증 사용 시 권장 도메인 형식. |
구성 요소
게임 실행은 4개의 스토브 JS Service 모듈을 조합해 동작해요.
모듈을 한 번에 묶은 패키지(launcher-pack.js)와 개별 모듈로 나눠 부르는 방식 중 선택해서 연동할 수 있어요.
| 모듈 | 파일 | 역할 |
|---|---|---|
| LauncherService | launcher.js launcher-pack.js |
런처 실행과 다운로드 URL 조회를 담당. |
| MaintenanceService | maintenance.js | 게임 점검 상태를 조회. 점검 중일 때 실행을 차단하는 기준. |
| WhiteUserService | white-user.js | 점검 중에도 실행을 허용해야 하는 화이트리스트 이용자를 식별. |
| StoveTermsService | stove-terms.js | 게임 서비스이용약관 동의 여부를 체크. 미동의 상태면 통합약관 페이지로 분기. |
동작 원리
게임 실행 버튼이 눌렸을 때 내부적으로 약관 → 점검 → 화이트유저 → 런처실행 순으로 체크가 일어나요.
각 단계는 다음 단계의 진입 조건을 결정해요.
| 단계 | 체크 항목 | 실패 시 분기 |
|---|---|---|
| 1. 약관 | 서비스이용약관 동의 여부 | 통합약관 페이지로 이동해 동의 처리. |
| 2. 게임 점검 | 현재 점검 진행 여부 (REGULAR / TEMPORARY / URGENT) | 점검 안내 노출 후 실행 차단. 화이트유저는 통과. |
| 3. 화이트리스트 | 로그인 이용자가 화이트유저 대상인지 여부 | 점검 시 일반 이용자는 차단, 화이트유저는 통과. |
| 4. 런처 실행 | 런처 설치 여부와 실행 프로토콜 호출 | 미설치 시 다운로드 URL 안내. |
launcher.run({}) 메서드 내부에서는 이 흐름이 자동으로 처리돼요.
단, 자동 체크가 동작하려면 사전에 window.stoveJsService.maintenance 객체와 window.stoveJsService.whiteUser 객체가 존재해야 해요.
즉, 점검 체크와 화이트유저 체크를 사용하려면 해당 모듈을 미리 로드하고 초기화해 둬야 해요.
점검·화이트유저 체크가 실행되기 위한 조건이 있어요window.stoveJsService.maintenance 객체가 존재하고 isSkipMaintenance 값이 false인 경우 점검 체크가 실행돼요.window.stoveJsService.whiteUser 객체가 존재하고 점검 체크 결과값이 true인 경우 화이트유저 체크가 실행돼요.
연동 가이드
연동 준비
- 인프라
스토브 인증을 사용하려면 웹 서비스(공홈) 도메인이
xxx.game.onstove.com형식이어야 해요. 외부 공홈으로 연동할 경우 SSL 인증서 발급 및 별도 인프라 설정이 필요하며, 담당 스토브 기술PM을 통해 발급 받아요.
- 코드 발급
inflow_path는 이용자 유입경로를 식별하기 위한 값이에요. 담당 스토브 기술PM을 통해 발급 받아요.
기본 연동 구조
- CDN 도메인 스토브 JS Service 라이브러리는 환경별 CDN으로 제공돼요. Sandbox 테스트 후 Live 전환 시 Host 값을 변경해야 해요.
| 환경 | CDN Domain |
|---|---|
| Sandbox | https://js-cdn.gate8.com |
| Live | https://js-cdn.onstove.com |
- 라이브러리 Path 빠른 연동을 위해서는 패키징 방식을 권장해요. 개별 방식은 사용 기능에 따라 필요한 lib만 선택해서 연결할 수 있어요.
| 방식 | lib Path |
|---|---|
| 패키징 방식 | /libs/stove-js-service/latest/launcher-pack.js (런처 / 점검 / 화이트유저 통합) |
| 개별 방식 - 런처 | /libs/stove-js-service/latest/launcher.js |
| 개별 방식 - 점검 | /libs/stove-js-service/latest/maintenance.js |
| 개별 방식 - 화이트유저 | /libs/stove-js-service/latest/white-user.js |
| 약관 | /libs/stove-js-service/latest/stove-terms.js |
- script 태그 위치
head또는body가장 하단에 정의해요.defer옵션을 사용해서 모든 컨텐츠가 다운로드 완료된 후 script가 실행되도록 해요.
defer 옵션을 반드시 적용해 주세요
script 태그 옵션은 defer로 설정해서 모든 컨텐츠가 다운로드 완료된 후 script가 실행되도록 해야 해요.
defer 없이 즉시 실행되면 DOM이 준비되기 전에 모듈 초기화가 진행돼 정상 동작하지 않을 수 있어요.
개발하기
라이브러리 연결
- 패키징 방식
패키징 방식은 런처 실행·점검·화이트유저를 한 번에 연동하는 방식이에요.
<html>
<head>
<meta charset="UTF-8">
<title>stove launcher</title>
</head>
<body>
// ...컨텐츠 내용 생략
<script src="https://js-cdn.gate8.com/libs/stove-js-service/latest/launcher-pack.js" defer />
</body>
</html>
- 개별 방식
개별 방식은 사용 기능에 따라 각 기능(런처 실행·점검·화이트유저) lib를 연결해요.
<html>
<head>
<meta charset="UTF-8">
<title>stove launcher</title>
</head>
<body>
// ...컨텐츠 내용 생략
<script src="https://js-cdn.gate8.com/libs/stove-js-service/latest/white-user.js" defer />
<script src="https://js-cdn.gate8.com/libs/stove-js-service/latest/maintenance.js" defer />
<script src="https://js-cdn.gate8.com/libs/stove-js-service/latest/launcher.js" defer />
</body>
</html>
런처 실행
launcher.run({}) 메서드를 통해 런처를 실행해요. 내부에서 점검·화이트유저 체크가 자동으로 처리돼요.
- Parameter
| Parameter | Type | Requirement | Default Value | Description |
|---|---|---|---|---|
| gameId | String | Y | - | 게임 아이디 또는 게임 넘버 |
| nation | String | N | KR |
쿠키값 NNTO 참조쿠키 정보가 없는 경우 defaultValue = 'KR'
|
| lang | String | N | EN |
쿠키값 LOCALE 참조쿠키 정보가 없는 경우 defaultValue = 'EN'
|
| inflow_path | String | N | - | 게임 아이디와 동일 |
| isSkipMaintenance | Boolean | N | false |
점검 체크 유무 기본값은 점검 체크 사용 |
| gameMarketName | String | N | PC_MARKET |
웹에서 런처 실행 시 defaultValue = 'PC_MARKET'
|
| executeWaitingTime | Number | N | 5 | 실행 딜레이 만료 체크 시간 (초 단위) |
isSkipMaintenance : true
웹에서 게임 점검 체크를 사용하지 않을 경우 true로 설정하면 돼요.
해당 Param을 설정하면 화이트유저도 체크하지 않아요.
- Example (Promise)
런처 메서드(launcher.run({}))를 호출하면 응답값으로 Promise 객체의 then·catch 메서드를 통해 결과값을 받을 수 있어요.
window.stoveJsService.launcher.run({
gameId: 'STOVE_EPIC7',
nation: 'KR',
lang: 'KO',
isSkipMaintenance: true
})
.then(data => {
console.log('런처 실행 성공시 처리', data);
})
.catch(error => {
console.log('런처 실행 실패시 처리', error);
});
- Example (HTML 통합 사용예제)
<html>
<head>
<meta charset="UTF-8">
<title>stove launcher</title>
<script src="https://js-cdn.gate8.com/libs/stove-js-service/latest/launcher-pack.js" defer />
<script>
function initializeJsService() {
window.stoveJsService = window.stoveJsService || {};
}
function startLoadingForLauncher() {
// 런처 실행 로딩 시작 UI 처리
}
function stopLoadingForLauncher() {
// 런처 실행 로딩 종료 UI 처리
}
function errorHandler( errorCode ) {
switch (errorCode) {
case 601:
// 런처가 설치되어 있지 않습니다. 런처를 다운로드한 다음 설치해주세요.
break;
case 602:
// 런처 URI가 없는 경우 반환합니다.
break;
case 'API 리턴 오류 코드':
// 런처, 점검 그리고 화이트유저 api 호출 시 발생한 오류에 대한 처리가 필요한 경우 case 추가 정의
break;
default:
// 기타 오류 공통 처리
break;
}
}
function runLauncher() {
if (!window.stoveJsService.launcher) {
alert('현재 런처 실행 준비가 되어 있지 않습니다!')
return;
}
startLoadingForLauncher();
window.stoveJsService.launcher.run({
gameId: 'STOVE_EPIC7'
}).then(() => {
// 런처 실행 성공 시 처리
}).catch(error => {
// 런처 실행 실패시 처리
errorHandler(error.code)
}).finally(() => {
stopLoadingForLauncher();
});
}
</script>
</head>
<body onload="initializeJsService">
<button onclick="runLauncher">게임 실행</button>
</body>
</html>
- Error Code
| Error Code | Constant | Description |
|---|---|---|
| 601 | NOT_FOUND_LAUNCHER | 클라이언트 환경에 런처가 설치되어 있지 않은 경우 반환 |
| 602 | NOT_FOUND_PROTOCOL_URI | 런처 Protocol URI 정보가 없는 경우 반환 |
| 503100 | GAME_MAINTENANCE | 실행한 게임 서비스가 점검 중인 경우 반환 |
| - | - |
각 API 응답별 개별 코드에 대한 예외 처리가 필요할 경우Error Status Handling List 문서를 참고해 주세요.
|
런처 다운로드
launcher.download({}) 메서드를 통해 런처 다운로드 URL을 조회해요. 60초 동안 메모리 캐싱돼요.
- Parameter
| Property | Type | Requirement | Description |
|---|---|---|---|
| gameId | String | Y |
gameId 파라미터는 필수값이며 gameId 또는 gameNo를 전달해야 해요.gameNo 전달 시 내부적으로 최종 gameId로 변환되어 처리돼요.
|
| nation | String | N |
nation 파라미터는 선택값이에요. 생략 시 로컬 쿠키값 NNTO를 참조해요.쿠키 정보가 없는 경우 기본값은 'KR'이에요.
|
| lang | String | N |
lang 파라미터는 선택값이에요. 생략 시 로컬 쿠키값 LOCALE을 참조해요.쿠키 정보가 없는 경우 기본값은 'EN'이에요.
|
- Example (Promise)
stoveJsService.launcher.download({
gameId : 'STOVE_EPIC7',
nation : 'KR',
lang : 'KO'
}).then(url => {
console.log('url =>', url);
}).catch(error => {
console.log('error =>', error.code, error.message);
})
- Response (다운로드 URL)
'https://sgs-gate8-dl.game.playstove.com/game/lcs/STOVESetup_SGA.exe'
약관 체크
stoveTerms.checkAgreeState({}) 메서드를 통해 서비스이용약관 동의 여부를 확인해요.
- Parameter
| Property | Type | Requirement | Description |
|---|---|---|---|
| service_id | String | Y |
game_id 매개변수는 필수값이에요. 예시: service_id='스토브_EPIC7'
|
| viewarea_id | String | Y |
약관(서비스이용동의) 체크 구분 값이에요. 공홈에서 서비스 이용약관 연동 시 SVC_AG 코드를 기본값으로 사용해요.
|
| nation | String | Y |
nation 매개변수는 필수값이며 대문자 국가 코드를 전달해요. 예: KR, JP, TW
|
- Example (Promise)
stoveJsService.stoveTerms.checkAgreeState({
service_id: 'STOVE_EPIC7',
viewarea_id: 'STC_REWE',
nation: 'KR'
}).then(isAgreeState => {
console.log('isAgreeState =>', isAgreeState);
}).catch(error => {
console.log('error =>', error.code, error.message);
});
- Response (약관 동의 상태)
true
점검 조회
maintenance.retrieveData({}) 메서드를 통해 게임 점검 상태를 조회해요.
- Parameter
| Property | Type | Requirement | Description |
|---|---|---|---|
| category | String | Y |
category 파라미터는 필수값이며 gameId 또는 gameNo를 전달해요.
|
| service_id1 | String | Y |
service_id1 파라미터는 필수값이며 game_id 또는 service_id 값을 전달해요.
|
| service_id2 | String | Y |
service_id2 파라미터는 필수값이며 PC 게임은 기본적으로 'PC_MARKET' 값을 사용해요.필요한 경우 사용자 정의 마켓 이름을 사용할 수 있어요. |
| lang | String | N |
lang 파라미터는 선택값이며 특정 언어 정보만 받고 싶은 경우 전달해요. 언어값을 지정하지 않는 경우 파트너스에 등록된 기본 언어 정보 기준으로 반환돼요. |
- Response
| Property | Type | Requirement | Description |
|---|---|---|---|
| isInMaintenance | Boolean | - | 점검 상태 여부를 반환해요. - 점검 중: true- 운영 중: false |
| maintenanceNo | Number | - | 점검 번호 |
| type | String | - | 점검 타입을 반환해요. - REGULAR: 정기 점검- TEMPORARY: 임시 점검- URGENT: 긴급 점검 |
| title | String | - | 점검 제목 |
| content | String | - | 점검 내용 |
| startDt | Number | - | UTC 기준 점검 시작일 milli-timestamp (13자리) |
| endDt | Number | - | UTC 기준 점검 종료일 milli-timestamp (13자리) |
- Example (Promise)
stoveJsService.maintenance.retrieveData({
category: 'STOVE_EPIC7',
service_id1: 'KR',
service_id2: '',
lang: 'KO'
}).then(model => {
console.log('model =>', model);
}).catch(error => {
console.log('error =>', error.code, error.message);
});
- Response (점검 정보)
{
isInMaintenance: true,
maintenanceNo: 95',
type: 'REGULAR',
title: '임시 점검',
content: '일시적인 접속 지연이 발견되어 임시 점검 진행합니다.',
startDt: 22783279472389,
endDt: 247832793489304
}
화이트유저 체크
whiteUser.checkStatue({}) 메서드를 통해 점검 중에도 실행을 허용할 화이트리스트 이용자인지 식별해요.
- Parameter
| Property | Type | Requirement | Description |
|---|---|---|---|
| category | String | Y | category 파라미터는 필수값이며 'GAME' 값을 전달해요. |
| service_id1 | String | Y | service_id1 파라미터는 필수값이며 game_id 값을 전달해요. |
- Example (Promise)
stoveJsService.whiteUser.checkStatue({
category: 'PLATFORM',
service_id1: 'STOVE_EPIC7'
}).then(isWhiteUser => {
console.log('isWhiteUser =>', isWhiteUser);
}).catch(error => {
console.log('error =>', error.code, error.message);
});
- Response (화이트 유저 대상 상태 정보)
true
통합약관 페이지 이동
웹 서비스에서 연동되는 게임의 "게임 이용약관 동의"가 안 된 경우, 스토브가 제공하는 약관 동의 페이지로 연동할 수 있어요.
- Host
Host:
https://policy.gate8.com (SANDBOX)
https://policy.onstove.com (Live)
- Parameter (Query String)
| Name | Type | Required | Default Value | Example | Description |
|---|---|---|---|---|---|
| inflow_path | String | Y | 약관 진입처 (사용처) | - | 약관 진입처 정보예요. 담당 기술PM에게 문의 |
| game_id | String | Y | 게임 아이디 | - | game_id 정보예요. 담당 기술PM에게 문의 |
| redirect_url (사용 권장) |
String | N | 약관 동의 완료 시 이동 URL | - | 약관 동의 완료 및 에러 발생 시 이동할 페이지 URL이에요. 1. redirect_url 이 전달되면 동의 완료 페이지로 이동하지 않고 항상 redirect_url 로 이동해요. 2. redirect_url 이 전달되면 inflow_path 값과 관계없이 항상 redirect_url 로 이동해요. |
| show_play_button | String | N | 약관 동의 완료 페이지에서 "게임 시작" 버튼 출력 여부 | "N" | - Y : 동의 완료 페이지에서 "확인" 버튼 대신 "게임 시작" 버튼이 출력돼요. - N : 동의 완료 페이지에서 "확인" 버튼이 출력돼요. |
- Sample Request (goPolicyTerms)
protected goPolicyTerms() {
window.location.href = `https://policy.onstove.com?inflow_path=STOVE_GAME_ID&game_id=STOVE_GAME_ID&redirect_url=${encodeURIComponent(window.location.href)}`;
}
- Return Code (page)
| Code | Message | Description |
|---|---|---|
| 1 | 올바르지 않은 접근입니다. 다시 시도해 주세요. |
약관동의 동선을 위한 최소 필수값 game_id, inflow_path 값은 기술PM에게 문의 |
| 2 | 로그인이 필요한 서비스입니다. |
미로그인 상태에서 접근 시 미로그인 상태에서는 약관동의 처리 불가 |
| 3 |
현재 연결이 원활하지 않습니다. 잠시 후에 다시 시도해 주세요. |
게임정보 확인 API 조회 실패 game_id 또는 game_no 확인 필요 |
| 4 |
현재 연결이 원활하지 않습니다. 잠시 후에 다시 시도해 주세요. |
약관동의 여부 확인 API 조회 실패 파트너스 약관 설정 확인 필요 |
| 5 |
이미 약관 동의를 완료한 계정입니다. 게임을 실행해 주세요. |
이미 약관동의한 상태에서는 약관동의 동선을 제공할 필요 없음 계정 약관 중복 동의 동선 차단 |
| 6 |
현재 연결이 원활하지 않습니다. 잠시 후에 다시 시도해 주세요. |
약관 노출정책 판단 불가. 파트너스 정보 확인 필요 1) 게임정보 등록 2) 서비스(연령) 등급 정보 등록 3) 푸터 회사 정보 등록 |
| 7 | 해당 서비스를 이용하실 수 있는 나이가 아닙니다. | 파트너스에서 이용등급 나이 확인 필요 |
| 8 |
현재 연결이 원활하지 않습니다. 잠시 후에 다시 시도해 주세요. |
본인인증 여부, 연령정보 확인 불가 |
| 10 |
본인인증이 필요한 서비스입니다. 본인인증을 진행하시겠습니까? |
- |
| 11 |
현재 연결이 원활하지 않습니다. 잠시 후에 다시 시도해 주세요. |
본인인증은 된 상태이나 연령정보가 없는 경우 |
| 12 |
현재 연결이 원활하지 않습니다. 잠시 후에 다시 시도해 주세요. |
파트너스 약관 정보 등록 확인 필요 |
| 13 | 올바르지 않은 접근입니다. 다시 시도해 주세요. | game_id 항목에 game_no가 전달되는 경우 |
| 14 | 연령확인이 필요한 서비스입니다. | 글로벌 동선에서 생년월일 입력이 필요한 계정인 경우 |
Service 별 통합 Error Code
- LauncherService
| Code | Constant | Exception Class | Description |
|---|---|---|---|
| 40101 | INVALID_ACCESS_TOKEN | AuthenticationException | 토큰 정보가 유효하지 않습니다. |
| 70051 | INVALID_REQUEST | InvalidRequestException | API 호출 시 파라미터 전송 또는 누락 오류 |
| 500000 | INTERNAL_SERVER_ERROR | InternalServerExeption | 패치 중 오류가 발생했습니다. (공통 처리 에러 코드) |
| 503100 | GAME_MAINTENANCE | UnderMaintenanceException |
점검 중이므로 게임을 실행할 수 없습니다. 점검 종료 후 다시 시도해 주세요. Error 응답 예시 json
|
| 403101 | ACCOUNT_LOCKED | - | 서비스 이용이 제한된 회원 정보입니다. 자세한 내용은 제재 내역을 확인해 주세요. |
| 403102 | ACCOUNT_PROTECTED | - | 해당 아이디는 보안 정책에 따라 보호된 상태입니다. |
| 403103 | ACCOUNT_CI_RESTRICTION | - | 서비스 이용이 제한된 회원 정보입니다. 고객센터로 문의해 주세요. |
| 403201 | GAME_EXECUTION_RESTRICTION | - | 요청하신 서비스는 아래의 사유로 이용이 제한되었습니다. |
| 403202 | PERSON_VERIFY_RESTRICTION | - | 이용 제한 안내(선택적 본인인증). 요청하신 서비스는 아래의 사유로 이용이 제한되었습니다. 이용 제한 또는 이의 제기 관련 문의는 고객센터를 이용해 주세요. |
| 403300 | INDIE_RESTRICTION | - | 인디 제재 |
| 406101 | UNRELEASED_SVC | - | 사전 다운로드 기간입니다. 공식 홈페이지에서 정식 오픈 일정을 확인해 주세요. |
| 406102 | UNABLE_CLIENT | - | 이용불가(클라이언트) 기간입니다. |
| 406201 | UNSERVICEABLE_COUNTRY | - | %게임명%은(는) 해당 국가에서 실행할 수 없습니다. |
| 406202 | UNAVAILABLE_COUNTRY_SERVICE | - | %게임명%은(는) 해당 국가에서 실행할 수 없습니다. |
| 406203 | UNAVAILABLE_COUNTRY_COPYRIGHT | - | %게임명%은(는) 해당 국가에서 실행할 수 없습니다. |
| 406300 | REQUIRED_BIRTH_DAY | - | 게임 이용을 위해 연령 확인이 필요합니다. |
| 406301 | PROHIBITED_RATING_AGE | - | 게임 이용 가능한 연령이 아닙니다. |
| 406302 | PERSON_VERIFY_REQUIRED | - | 본인인증이 필요합니다. 인증을 진행해 주세요. |
| 406303 | PARENT_VERIFY_REQUIRED | - | 보호자 동의가 필요한 아이디입니다. 보호자 동의를 진행해 주세요. |
| 406304 | EMAIL_VERIFY_REQUIRED | - | 이메일 인증이 필요합니다. 인증을 진행해 주세요. |
| 406400 | REQUIRED_TERMS_AGREE | - | 게임 이용을 위해 서비스 이용 약관 동의가 필요합니다. |
| 406701 | REQUIRED_CANCEL_USE_SERVICE | - | 게임 이용을 해지한 아이디입니다. 게임을 플레이하려면 이용 해지를 취소해야 합니다. |
| 701 | NOT_FOUND_GAME | NotFoundGameException | 게임 정보를 찾을 수 없습니다. |
- MaintenanceService / WhiteUserService
| Code | Constant | Exception Class | Description |
|---|---|---|---|
| 40101 | INVALID_ACCESS_TOKEN | InvalidAccessTokenException | 부적절한 액세스 토큰입니다. |
| 70051 | INVALID_REQUEST | InvalidRequestException | 부적절한 파라미터 요청입니다. |
- StoveTermsService
| Code | Constant | Exception Class | Description |
|---|---|---|---|
| 40103 | EXPIRED_ACCESS_TOKEN | ExpiredAccessTokenException | 토큰이 만료되었습니다. |
| 70051 | INVALID_REQUEST | InvalidRequestException | 잘못된 입력값입니다. |
| 70800 | NOT_EXIST_TERMS | BasicBusinessException | 약관이 존재하지 않습니다. |
| 70804 | GS_NETWORK_ERROR | BasicBusinessException | GS 연동 네트워크 에러가 발생했습니다. |
| 70805 | GUID_NETWORK_ERROR | BasicBusinessException | GUID 연동 네트워크 에러가 발생했습니다. |
| 70806 | NOT_EXIST_SERVICE_ID | BasicBusinessException | service id 정보를 찾을 수 없습니다. |
| 70807 | UNKNOWN_GUID_SERVER | BasicBusinessException | GUID 서비스에 문제가 있습니다. 잠시 후 다시 시도해 주세요. |
| 70870 | NOT_EXIST_CALLER_ID | BasicBusinessException | caller-id 값을 확인해 주세요. |
| 70871 | NOT_EXIST_CALLER_DETAIL | BasicBusinessException | caller-detail 값을 확인해 주세요. |