채팅방 API
개요
- 이벤트등에서 넘겨지는 room 인스턴스는 모두 이 페이지에 있는 정보를 참고하셔야됩니다.
- 채팅방에 필요한 모든 명령어는 room 에 담겨있습니다.
room Object의 구조는 다음과 비슷한 형태로 구성되어 있습니다.
id
v1 TEXT
채팅방의 id 입니다.
info
v1 JSON
서버로 부터 받아온 정보입니다. JSON 형식입니다.
info.id
v1 TEXT
채팅방의 아이디입니다.
info.name
v1 TEXT
채팅방의 제목(타이틀)입니다.
info.mode
v1 NUMBER
채팅방의 종류를 나타내는 숫자입니다.
숫자 (값) | 설명 |
---|---|
0 | 기본 채팅방 (uchat.io에서 만든 채팅방) |
1 | 개인 채팅방 (채팅방에 접속한 유저끼리 만든 개인 채팅방) |
4 | 채널 채팅방 (uchat.ch에서 만든 채팅방) |
info.created
v1 TEXT (YYYY-MM-DD HH:MM:SS)
채팅방이 생성된 시각 입니다. 서버에서 채팅방이 만들어진 시각입니다.
agent
v1 JSON
접속자 브라우저의 종류를 알아낼 수 있습니다.
agent.userAgent
v1 TEXT
접속자의 User-Agent값을 그대로 확인가능합니다.
agent.charset
v1 TEXT
접속자의 문자열셋을 확인할 수 있습니다.
agent.ie
v1 TRUE / FALSE
접속자가 Internet Explorer로 접속하면 True, 아니면 False를 가집니다. User-Agent값을 기준으로 판별하기에, User-Agent값이 조작되어 있다면 정상적인 판단이 안될수도 있습니다.
agent.android
v1 TRUE / FALSE
접속자가 안드로이드 OS에서 접속하면 True, 아니면 False를 가집니다. User-Agent값을 기준으로 판별하기에, User-Agent값이 조작되어 있다면 정상적인 판단이 안될수도 있습니다.
agent.ios
v1 TRUE / FALSE
접속자가 애플 iOS에서 접속하면 True, 아니면 False를 가집니다. User-Agent값을 기준으로 판별하기에, User-Agent값이 조작되어 있다면 정상적인 판단이 안될수도 있습니다.
agent.mobile
v1 TRUE / FALSE
접속자가 모바일에서 접속하면 True, 아니면 False를 가집니다. User-Agent값을 기준으로 판별하기에, User-Agent값이 조작되어 있다면 정상적인 판단이 안될수도 있습니다.
모바일 접속자라도, 브라우저에서 "데스크톱 모드"이거나 User-Agent가 제대로 설정되지 않은 기기에서는 False값이 나올 수 있습니다. 원칙적으로는 태블릿도 인식이 됩니다만, 일부 기기는 인식되지 않을수 있습니다.
agent.webkit
v1 TEXT
접속자가 웹킷을 이용해서 접속하면 웹킷의 버전을, 사용하지 않는다면 false를 가지고 있습니다.
my
v1 Object
접속자의 정보가 담겨있습니다. 구조는 다음과 같습니다.
{
'auth': 0, #접속 권한 - http://uchat.io/doc/2.2/%EC%9D%B4%EB%B2%A4%ED%8A%B8#before.user.modi 참고
'connected': "2018-05-12 03:15:59", #접속 일자
'icons': "", #아이콘 주소
'id': "", #아이디
'level': undefined, #레벨
'mute': 0, #벙어리 모드 여부 (0: 아님, 1: 벙어리 상태)
'nick': "Guest_9DabV", #닉네임
'nickcon': "", #닉콘 주소
'time': 1526062559, #접속 시각 (Epoch)
}
getTimeStamp
v1 FUNCTION
서버 시간을 기준으로 현재 시각을 "YYYY-MM-DD HH:MM:SS" 형식의 타임스탬프를 리턴합니다.
now
v1 FUNCTION
서버시간을 기준으로 시간을 Epoch 초로 나타냅니다.
language
v1 Object
출력될 시스템, 에러 메세지가 정의되어 있습니다. 추후 외국어 버전이 지원되면 language값 변경으로 다국어화 될 예정입니다. 접속자 브라우저의 언어셋을 기준으로 값이 저장되어 있으며, 브라우저나 사이트마다 인코딩이 다를 수 있습니다.
language.system
v1 Object
시스템 알림과 관련된 문구들이 모여 있습니다.
language.error
v1 Object
에러 메세지와 관련된 문구들이 모여 있습니다. 에러 코드를 키 값으로 가집니다.
reload
v1 FUNCTION
채팅방을 새로고침 합니다. 채팅방을 감싸는 iframe을 새로고침 하는것과 같은 효과를 보입니다. 일부 경우에, 싱크타임 오류등이 발생할 수 있습니다.
skin
v1 Object
스킨과 관련된 데이터를 가집니다. 스킨 관련 모듈들은 스킨에서 받아온 값으로서, 스킨이 완전히 로딩된 후에 사용하실 수 있습니다. (after.create 또는 그 이후에 발생하는 이벤트에서 부터 접근이 보장됩니다.) 일부 스킨들에서는 모듈을 제공하지 않을 수 있으며, 제공한다 하더라도 유챗에서 사용하는 구조를 따르지 않는 모듈을 만들수도 있습니다.
skin.arguments
v1 Object
채팅방 생성시 스킨에서 사용할 옵션이 정의 되어 있습니다. 주로 서버에서 가져온 채팅방의 ‘스킨설정’과 스크립트로 정의한 설정들입니다.
skin.document
v1 document (DOM)
스킨의 document (DOM) 입니다.
skin.popup
v1 팝업 모듈
스킨내의 팝업 모듈입니다. 어디까지나 스킨 API의 모듈을 연결해 주는 연결다리 역할로써, 자세한 정보는 스킨 API를 참고하시길 바랍니다.
skin.userMenu
v1 유저 메뉴 모듈
채팅방 접속 목록이나, 채팅창에서 유저를 클릭하면 나오는 메뉴의 관리 모듈입니다. 어디까지나 스킨 API의 모듈을 연결해 주는 연결다리 역할로써, 자세한 정보는 스킨 API를 참고하시길 바랍니다.
skin.menubar
v1 메뉴바 모듈
글씨 크기, 굵기, 기울기, 이모티콘등이 있는 메뉴바의 관리 모듈입니다. 어디까지나 스킨 API의 모듈을 연결해 주는 연결다리 역할로써, 자세한 정보는 스킨 API를 참고하시길 바랍니다.
skin.dom
v1 JSON
스킨에서 자주 쓰이는 element들을 모아둔 JSON입니다. 각 값들은 jquery 객체로 되어 있습니다. 일부 커스텀 스킨에서는 유챗이 제공하는 dom 목록및 구조를 따라가지 않을수도 있습니다.
skin.window
v1 WINDOW 개체
스킨에서 사용하는 window 객체를 가르킵니다.
skin.window.$
을 이용해서 Jquery를 사용하실 수도 있습니다.
setting
v1 Object
채팅방의 설정을 관리합니다. 설정은 브라우저의 쿠키값을 통해 저장됩니다. 쿠키값이 삭제되거나, 손상될 경우 저장된 값을 부르지 못할수 있습니다.
setting.data
v1 JSON
설정들이 모여있는 JSON 객체입니다.
setting.init
v1 FUNCTION(json)
기본 설정값을 지정합니다. 스킨이 초기화된 후에 따로 값을 지정하지 않은 설정들은 여기서 설정된 값을 따릅니다.
스킨이 초기화 될 때, 이 함수를 호출해야 합니다. 일반 사용자들은 호출할 필요가 없습니다.setting.set
v1 FUNCTION(key, value)
설정을 저장합니다. key - value를 짝으로 가집니다. 해당 함수를 실행한 후, setting.save()
를 호출하셔야 합니다. setting.set(key, value)
자체는 설정값 저장을 보장하지 않습니다.
호출 예: room.setting.set('key', 'value1234');
setting.get
v1 FUNCTION(key)
인수로 받은 key에 대한 설정값을 리턴합니다.
setting.save
v1 FUNCTION
설정값을 저장합니다. 타 언어의 flush()와 같은 역할로서, 설정값 지정후 이 함수를 호출하지 않으면 설정값 저장을 보장하지 않습니다.
v1 FUNCTION(message)
채팅방에 공지사항 형태로 메세지를 출력합니다. message는 일반 텍스트 및 HTML 텍스트 두 종류를 지원합니다.
해당 함수 실행시 before.system 이벤트가 작동되며, 출력후 after.system 이벤트가 작동됩니다.
action
v1 Object
채팅방의 명령어들이 모여 있습니다.
action.send
v1 FUNCTION(message [, style])
서버에 메세지를 송신합니다.
message는 일반 평문 메세지만을 지원합니다. HTML등을 전송할 경우, 모든 테그들이 escape됩니다. message는 길이 제한을 가지고 있으며, 서버내 제한값 이상으로 메세지를 전송할 경우 오류가 발생할 수 있습니다. 전송 성공 여부는 별도로 제공하지 않습니다. 필요시 before.error, after.error등으로 확인하셔야 합니다.
style은 다음과 같은 형식을 따르는 JSON 입니다.
{
bold bool : TRUE / FALSE
,
italic bool : TRUE / FALSE
,
underline bool : TRUE / FALSE
,
color text : HEX / RGB 코드 ( 예) #aabbcc
)
}
action.command
v1 FUNCTION(type, arg1 [, arg2 [, arg3 ···]])
특정 명령어를 실행할 수 있습니다. 명령어는 스킨, 채팅방 API, 또는 서버 어딘가에서 정의되어 있어야 합니다. 일부 커스텀 스킨에서는 특정 명령어를 지원하지 않을수 있습니다. 채팅방 API와 스킨 모두에서 정의되어 있지 않은 명령어는 서버에 직접 질의하여 결과를 받아옵니다.
일부 명령어들은 채팅방 내에서 관리자 권한을 가지고 있어야만 작동됩니다. 그렇지 않을 경우, 명령이 정상적으로 실행되지 않을 수도 있습니다.
발생한 오류들은 before.error, after.error를 통해 확인하셔야 합니다.
아래는 유챗이 기본적으로 지원하는 명령어의 모음입니다. 일부 커스텀 스킨에서는 몇몇 명령어를 사용하지 못하시거나, 아래의 명령어 외의 다른 명령어들도 지원될 수 있습니다.
action.command('password', password STRING)
입장 비밀번호를 서버에 보냅니다. 입장 비밀번호가 적용되어 있는 채팅방에 접속시에만 쓰입니다.
해당 명령어는 before.join에서만 사용 가능합니다. 또한, 이벤트 결과에서 false를 return 해야지 정상 작동합니다.
U.chat('*').on('before.create', function(room, data){
room.action.command('password', '1234');
return false;
});
action.command('ban', target STRING, reason STRING)
특정 유저를 차단합니다. target은 차단할 유저의 닉네임을, reason은 차단 사유를 의미합니다.
room.action.command('ban', '차단할_닉네임', '지속적 도배로 인한 차단');
action.command('whisper', target STRING, message STRING)
특정 유저한테 귓말을 전송합니다. target은 귓말을 수신할 대상의 닉네임을, 메세지는 보낼 메세지를 의미합니다. 귓말 명령어는 별도의 글씨 스타일을 지원하지 않습니다.
room.action.command('whisper', '귓말을_받을_대상의_닉네임', '귓말 메세지');
action.command('upload', callback CALLBACK)
이미지 업로드를 할 수 있게 팝업을 띄웁니다. 팝업 차단이 되어있을 경우 비정상적으로 작동될 수 있습니다.
callback에는 결과값에 대한 JSON이 인자로 넘어갑니다. 인자로 넘어가는 JSON은 다음과 같습니다:
{ status INTEGER: 0 or 1 // 0 이면 실패, 1이면 성공입니다. , url STRING: ‘url’ // 업로드된 이미지의 주소입니다. , msg STRING: ‘’ // 에러 메세지 입니다. }
room.action.command('upload', function(result){
if(status == 0) { alert('이미지 업로드에 실패하였습니다.\r\n참고 메세지: ' + result.msg); return; }
alert('이미지가 정상적으로 업로드 되었습니다. 이미지는 ' + result.url + '에 저장되었습니다.');
}
action.command('mute', target STRING, period INTEGER(MINUTE), reason STRING)
특정 유저를 벙어리 상태로 만듭니다. 부 관리자 권한 이상을 필요로 합니다. target은 벙어리로 만들 유저의 닉네임을, period는 벙어리를 유지할 기간(분 단위)을, reason은 벙어리를 적용하는 이유를 의미합니다.
room.action.command('mute', '벙어리_먹일_닉네임', 15, '도배가 심해서 15분간 벙어리');
action.command('unmute', target STRING)
특정 유저의 벙어리 상태를 해제합니다. 부 관리자 권한 이상을 필요로 합니다. target은 벙어리 상태를 해제할 유저의 닉네임 입니다.
room.action.command('unmute', '벙어리_먹은_닉네임');
action.command('call', target STRING)
특정 유저를 호출합니다. target은 호출할 대상의 닉네임 입니다.
room.action.command('call', '호출_대상_닉네임');
action.command('ip', target STRING)
특정 유저의 IP를 확인합니다. target은 IP를 확인할 대상의 닉네임 입니다.
room.action.command('ip', 'IP를_확인할_대상');
action.command('ignore', target STRING)
특정 유저의 채팅을 모두 무시합니다. 자신의 채팅창에서만 특정 접속자의 채팅을 숨기는 명령어로, 관리자 권한은 필요 없습니다. target은 무시할 대상의 닉네임 입니다.
room.action.command('ignore', '무시할_대상');
action.command('un_ignore', target STRING)
특정 유저에게 적용했던 무시하기를 해제합니다. 해제 이후의 채팅부터 정상 표시 되며, 해제 이전에 대상이 입력한 채팅 내용은 다시 보여주거나 하지는 않습니다. target은 무시하기를 해제할 대상의 닉네임 입니다.
room.action.command('un_ignore', '무시했던_대상');
action.command('popup')
현재 채팅방을 새창으로 띄웁니다.
action.command('invite', target STRING)
개인 채팅방을 만들어 둔 상태에서만 작동되는 명령어로, 특정 유저를 자신의 개인 채팅방에 초대할 수 있습니다. target은 초대할 대상의 닉네임 입니다.
room.action.command('invite', '개인채팅방에_초대할_대상');
action.command('individual', target STRING)
내 개인 채팅방에 상대방을 초대 합니다. 필요하다고 판단되면 (개인 채팅방이 없는경우) 개인 채팅방을 팝업으로 띄웁니다.
room.action.command('individual', '개인채팅방에_초대할_대상');
individual 명령어는 부모 채팅방(원래 채팅방)에서 사용하도록 만들어진 명령어 입니다.
개인 채팅방 내에서 기존의 유저를 초대할 때는 invite, 기존 채팅방에서 내 개인 채팅방에 유저를 초대할 때는 individual을 사용하시면 됩니다.
action.command('noticeList')
입장 공지사항을 가져옵니다. 유챗의 기본 스킨에서 접속시 1회 자동으로 호출합니다. 아래 코드는 5분에 한번씩 공지사항을 출력하는 예제입니다.
setInterval(
function(){ room.action.command('noticeList'); },
5 * 60 * 1000
);
action.command('io', TRUE / FALSE)
입·퇴장 정보를 수신할지 여부입니다. FALSE로 설정될 경우 접속자 목록을 갱신하지 않고 접속자 수만 서버에서 불러옵니다. (before.user.count, after.user.count 이벤트 실행됨). TRUE로 설정될 경우 접속자 목록을 실시간 갱신하며, 실시간 접속자 수를 서버에서 불러오지는 않습니다. (before.user.count, after.user.count 이벤트가 실행되지 않습니다.)
before.user.count, after.user.count는 입퇴장 목록을 갱신하지 않는 대신에 발생하는 이벤트 입니다. 그 결과, 전체 입퇴장 목록을 갱신하는 대신, 실시간 접속자 수만 갱신합니다.
room.action.command('io', TRUE);
action.command('chatList', count INTEGER)
최근 채팅 리스트를 불러옵니다. count는 최근 채팅의 갯수이며, 서버내 갯수 제한이 있을수 있습니다. 이 경우, 아무리 큰 수를 count에 할당해도 제한된 갯수만 서버에서 반환됩니다.
var numLoadMessage = 25; //25개의 최근 메세지를 서버에서 받아옴
room.action.command('chatList', numLoadMessage);
action.command('changeInfo', json JSON)
자신의 정보를 바꿀수 있습니다. 일부 채팅방에서는 (특히 회원 연동이 작동되는 경우) 사용 불가할 수 있습니다.
인자로 넘어가는 JSON은 다음과 같은 구조를 가집니다:
{
'키_값': '바꿀 값'
}
room.action.command('changeInfo', { 'nick': '새로_바꿀_닉네임' });
action.command('notice', html STRING)
관리자가 공지사항을 전송할 때 사용됩니다. 해당 명령어를 사용하면 채팅방 내의 모든 접속자에게 메세지를 출력시킵니다. html은 출력할 내용으로, 단순 텍스트 및 HTML 둘 다를 지원합니다.
if(HTML로_보내고_싶으면)
room.action.commmand('notice', '<p>test</p><img src="1234">');
else
room.action.command('notice', '테스트 메세지 입니다.');
action.command('clearLog')
대화 로그를 지웁니다. 관리자 권한을 가지고 있으면 전체 유저의 화면을 지웁니다. 관리자 권한이 없다면 자신의 화면만 지웁니다.
action.command('op', target STRING)
관리자(금색 왕관)가 특정 유저에게 부관리자 권한(은색 왕관)을 줄 수 있습니다. target은 대상의 닉네임을 의미합니다.
room.action.command('op', '은색_왕관을_받을_유저_닉네임');
action.command('deop', target STRING)
관리자(금색 왕관)가 특정유저의 부관리자 권한을 뺏을수 있습니다. target은 부관리자중 권한을 회수할 대상의 닉네임 입니다.
room.action.command('op', '은색_왕관을_뺏을_유저_닉네임');
action.command('login', password STRING)
채팅방에 로그인 합니다. 로그인 가능한 채팅방에서만 사용 가능한 명령어로서, 로그인에 성공할 경우 관리자 권한을 받을 수 있습니다. password는 채팅방의 비밀번호 입니다.
room.action.command('login', '비밀번호1234');
action.command('adminPage')
관리 페이지를 띄웁니다. 관리자인 경우에만 사용 가능하며, 팝업 차단 시스템이 있으면 비정상적으로 작동할 수 있습니다,
room.action.command('adminPage');
user
v1 Object
유저 목록을 관리하는 모듈입니다.
user.list
v1 배열
유저 목록을 가지고 있습니다. io가 TRUE일 경우에만 user.list값이 정상적이다고 보장합니다. io가 FALSE일 경우, 배열의 값들이 업데이트가 되지 않거나, 배열이 아예 비어있을수도 있습니다.
user.get
v1 FUNCTION(nick)
특정 닉네임에 대한 접속자 정보를 리턴합니다.
접속해 있지 않는 유저에 대한 정보는 {nick: '유저닉네임', status: 'off'} 로 반환됩니다.
plugin
v1 Object
플러그인을 관리하는 오브젝트입니다.
plugin.TO_ALL
v1 상수
플러그인에 수신된 데이터의 종류를 확인하기 위해 사용됩니다. before.plugin
, after.plugin
와 아래의 플러그인 리시버에서 사용됩니다.
수신된 데이터의 type이 plugin.TO_ALL
이면 현재 채팅방에 접속한 전원에게 발송된 데이터임을 뜻합니다.
plugin.ONLY_ME
v1 상수
플러그인에 수신된 데이터의 종류를 확인하기 위해 사용됩니다. before.plugin
, after.plugin
와 아래의 플러그인 리시버에서 사용됩니다.
수신된 데이터의 type이 plugin.ONLY_ME
이면, 귓속말 처럼 본인에게만 발송된 데이터임을 뜻합니다.
plugin.list
v1 Object
플러그인의 목록을 가집니다.
plugin.add
v1 FUNCTION(name)
플러그인을 추가합니다. 플러그인을 추가할 경우, 해당 플러그인 전용 통신 채널를 할당받을 수 있습니다. 플러그인에 대한 정보는 인자로 전달하지 않고, return된 값에 대입하는것으로 이루어집니다.
room.plugin.add( '플러그인_이름' )
을 호출하면 다음과 같은 모듈(객체)가 리턴됩니다.
{
'id' : 'name',
'receiver' : [],
'parser' : [],
'send' : function( data ),
'onReceived': function( callback ),
'addParser': function( callback ),
'destory' : function(),
}
리턴된 객체를 이용하여 원하는 작업을 수행할 수 있습니다.
id
TEXT
플러그인의 이름(ID)입니다. 해당값은 수정하시면 안됩니다.
var plugin = room.plugin.add('testPlugin');
alert('플러그인이 등록되었습니다. 플러그인 ID: ' + plugin.id);
receiver
ARRAY
플러그인 전용 통신채널에서 메세지가 왔을때 일을 처리할 콜백들의 목록입니다. 직접 항목을 삭제·추가·수정을 하실 수 있으며, 이를 통해 메세지 송수신 콜백을 관리하실 수 있습니다.
parser
ARRAY
채팅방에서 플러그인 명령이 들어왔을때 실행될 콜백들의 목록입니다. 플러그인 명령은 채팅방에서 ![플러그인 ID] 인수1 인수2 ···
와 같은 구조로 메세지가 입력되면 발생합니다. !플러그인ID
는 고정값이며, 해당 문자열로 시작되는 메세지가 입력되면 parser 목록에 있는 모든 콜백들이 순차적으로 실행됩니다. 직접 항목을 삭제·추가·수정을 하실 수 있으며, 이를 통해 파서 콜백을 관리하실 수 있습니다.
send
FUNCTION( ARRAY )
플러그인 전용 통신채널에 메세지를 보냅니다. 보낸 메세지는 채팅방 내의 각 접속자들이 수신하게 되며, receiver가 이를 처리하게 됩니다.
함수의 인수로 배열만을 사용하실 수 있습니다.
var plugin = room.plugin.add('testPlugin');
plugin.send(['배열도', '보낼 수', '있습니다.']);
onReceived
FUNCTION( CALLBACK )
수신된 데이터를 처리할 콜백을 등록합니다. 콜백의 인자는 배열 하나가 사용됩니다.
var plugin = room.plugin.add('testPlugin');
plugin.onReceived(function(data){
});
onReceived의 함수에 사용된 data인자는 JSON으로서, 구조는 http://uchat.io/doc/2.2/이벤트#before-plugin를 참고하시길 바랍니다.
addParser
FUNCTION( CALLBACK )플러그인 명령어를 처리할 콜백을 등록합니다. 콜백의 인자는 배열 하나가 사용됩니다.
채팅방에서 !플러그인ID 인자1 인자2 인자3 인자4 ···
와 같은 구조로 이루어진 메세지가 입력되면 등록된 파서가 실행됩니다. 각 인자들은 콜백에 배열로 담겨 전달됩니다.
var plugin = room.plugin.add('testPlugin');
plugin.addParser(function(data){
//!testPlugin 테스트값 1234
//data => ['테스트값', '1234']
});
sendTo
FUNCTION(NICKNAME, ARRAY) 특정 대상에게 데이터를 보냅니다. 이 함수로 특정 대상에게만 데이터를 보내면 데이터의 타입에 room.plugin.ONLY_ME
가 설정됩니다.
destory
FUNCTION()이 플러그인을 삭제합니다. listener와 parser 모두 무력화됩니다. listener와 parser를 이용하기 위해서는 다시 플러그인을 초기화(등록)해 주셔야 합니다.
onReceived(callback)
를 통해 수신할 수도 있습니다.아직 특정 대상한테만 통신하는 기능은 구현되지 않았습니다.
send()
로 전송하면 채팅방 접속자 전부한테 메세지가 전송됩니다.
U.chat('*').on('after.create', function(room, data){
//window에 전역변수로 등록
testPlugin = room.plugin.add('testPlugin');
testPlugin.addParser(function(data){
//!testPlugin 만 입력된 경우
if(data.length == 0){
room.print('사용법: !testPlugin 전송 [숫자]');
return;
}
if(data[0] == '전송'){
testPlugin.send(data[1]);
}else if(data[0] == '상태'){
alert('등록된 파서 갯수:' + testPlugin.parser.length + '\r\n등록된 리시버' + testPlugin.receiver.length);
}
});
testPlugin.onReceived(function(data){
//data는 array 입니다.
room.print('메세지가 수신되었습니다.\r\n메세지 수:' + data.length + '\r\n첫번째 메세지:' + data[0]);
});
});
log
v1 JSON
스킨에서 임시로 저장하는 데이터들이 담겨있습니다.
wrap
v1 document (DOM)
채팅방이 설치된 <u-chat>
태그를 가르킵니다.