https://issuetracker.unity3d.com/issues/android-unity-prompts-for-an-update-to-api-level-36-when-api-level-34-is-used-to-build-for-android

 

Unity IssueTracker - [Android] Unity prompts for an update to API Level 36 when API Level 34 is used to build for Android

Reproduction steps: 1. Open the attached project “SDKProject” 2. Select API Level 34 in “Project Settings/Player/Other settings/Targ...

issuetracker.unity3d.com

있지도 않은 api 36으로 빌드하려고 하는 버그가 있다.

projectSettings/ProjectSetting.asset 에서 AndroidTargetSdkVersion 프로퍼티 값을 34 (설치돼있는 가장 최근 버전) 으로 바꾸기 

 

 

유니티용 vscode 셋팅 다 끝났다고 가정했을때 

 

while 이나 for 문의 자동완성 제안(suggestion)의 우선순위가 이상하게 되어 탭 눌러도 자동완성이 안되는 경우가 있다

아래 사진처럼 while 키워드 라고만 뜨는데 자동완성은 두번째의 While loop 라는 메뉴가 해주기 때문에 우선순위 설정이 잘못되어 자동완성을 쓸 수가 없었다.

 

해결책은 vscode의 설정(ctrl + , )의 검색창에서 editor.snippetSuggestions 라고 검색하면 나오는 항목에서

inline(기본값)으로 돼있는걸 top 으로 바꾸면 된다.

 

"editor.snippetSuggestions": "top"

 

자동완성이 최상단에 위치해있다. 해결 완료

 

이미지 선택창 미리보기에 이미지가 안뜨는 현상이 유니티에 나타나서 매우 불편을 겪던 중 

구글링하다 우연히 해결책을 발견함. 속이다 시원해서 공유차 올림

 

 

<해결책>

 

1. 프로젝트 뷰에서 아래 이미지처럼 도형 세개있는버튼 클릭 후, Sprite 선택

 

 

2. 프로젝트 뷰에 나온 Sprite 들 전부선택 ( 컨트롤 + a) 

- Sprite외에 다른 에셋이 섞이면 안됨(1번을 한 이유)

 

3. 왼쪽 인스펙터에서 점 3개짜리 버튼 클릭 후 Reset 

 

4. 이미지 선택창 띄워보면 모든 이미지가 전부 나타나 있음. 해결!

 

 

* 주의!!! 대량의 에셋을 한번에 리셋하기 전에 한두개로 꼭 테스트해봐야함. 후회할수 있음

 

출처 및 이미지 출처

https://discussions.unity.com/t/sprite-previews-are-missing-throughout-project/246363

 

unity에서 애드몹 광고 호출 시 이런 에러가 뜰 경우의 해결법이다.

애드몹에서 생성한 광고와 스크립트에서 사용하는 광고 유형이 다를때 뜨는 에러다.

 

애드몹 홈피에서는 "보상형 전면광고"를 만들어두고 스크립트에서는 "보상광고"를 호출하는 클래스를 쓰면 안된다.

RewardedAd.Load() 즉, 보상형 광고 클래스를 호출할거라면, 홈피에서 "Reward보상광고"를 만들어야하는 거다.

 

배너광고를 만들었다면, BannerView 클래스를 호출해야 함

 

홈피에서 만든 광고유형에 맞는 클래스를 이용하면 해결된다.

 

 

 

 

 

유니티같이 큰 파일이 있는 프로젝트를 깃헙에 푸쉬할때 문제가 생기는데,

 

터미널 or CMD 로 해당 프로젝트 폴더로 이동 후,

git config http.postBuffer 524288000

입력.

해보고 문제가 해결된다면 글로벌로 설정

git config --global http.postBuffer 524288000

이후 다시 Push 시도하면 좀 긴 딜레이가 걸리나 십더니 순간 푸쉬에 성공한다.

 

https://stackoverflow.com/questions/15240815/git-fatal-the-remote-end-hung-up-unexpectedly

 

 

해결이 안되는 경우)

github 클라이언트 사용중이라면 Help -> Show log  메뉴로 로그를 확인하다보면 여러가지 에러메시지를 볼수있으니 복붙으로 구글링해보자.

 

 

애드몹 플러그인 적용 후 바로 꺼지는 경우 logcat 으로 에러메세지를 보다가

아래와 같은 메시지가 있는 경우가 있었다. 분명 맞는 광고id 입력했는데?

 

자세히보니 광고id 형식이 다른 것이었다. 

 

앱 ID 형식(뒷부분 물결 문자) : ca-app-pub-3940256099942544~3347511713

유닛 ID  형식 (뒷부분 슬래시 문자): ca-app-pub-3940256099942544/3347511713

 

앱ID: 하나의 앱을 상징 ( 안드로이드 마켓 앱, 게임 1개)

유닛 ID: 그 앱에서 여러개의 광고 유닛이 존재함 ( 전면광고, 보상광고, 배너광고 등..)

 

유니티 애드몹 플러그인 입력할때(인스펙터에서) 는 앱 ID만 입력해야하고,

스크립트 내에서 광고를 열때는 열고자 하는 광고의 유닛ID를 사용해야한다.

 

처음 해보면 헷갈릴수 있다. (나도 잘못할고있다가 글 수정함)

 

 

2023/06/05 17:39:29.760 16702 16702 Error AndroidRuntime * Invalid application ID. Follow instructions here:                          *
2023/06/05 17:39:29.760 16702 16702 Error AndroidRuntime * https://googlemobileadssdk.page.link/admob-android-update-manifest *
2023/06/05 17:39:29.760 16702 16702 Error AndroidRuntime * to find your app ID.                                                       *
2023/06/05 17:39:29.760 16702 16702 Error AndroidRuntime * Google Ad Manager publishers should follow instructions here:              *
2023/06/05 17:39:29.760 16702 16702 Error AndroidRuntime * https://googlemobileadssdk.page.link/ad-manager-android-update-manifest. *

유니티에서 앱 자동업데이트 (AppUpdateManager) 기능 통합하려할때 발생.

 

해결책 (solution)

 

필드 초기화에 딜레이를 주면 된다.

The error has disappeared, when I make some delay by coroutine before the initialization. After the loading of the scene completed.


Ienumberator Init(){
    yield return new Wait(0.5f);

    AppUpdateManager   aum = new AppUpdateManager();
}

 

이 부분을 코루틴으로 wait 딜레이를 줘 씬 로딩완료된 다음 호출하면 에러가 사라진다.

 

 

 

https://developer.android.com/guide/playcore/in-app-updates/unity?hl=ko&authuser=1

 

크래시의 원인: 애드몹은 유니티 메인 Thread가 아닌 별도의 Thread에서 돌아가기 때문에 Callback에서 TMPro 등 유니티 요소를 건드릴 경우 에러가 뜨며 앱이 꺼진다. 유니티 요소는 메인스레드에서만 건드리는게 원칙(?)이기 때문이다.

 

해결책: 보상 받는 admob 의 콜백 또는 AdClosed() 콜백에서 바로 건드리지 말고, 

아래 코드처럼 0.1f 초 딜레이를 준다.

 

// 애드몹 내부의 콜백메서드

void OnAdFullScreenContentClosed(){
      StartCoroutine(GetReward());
}

// 딜레이 줘서 유니티 메인스레드로 합류되도록 
IEnumerate GetReward(){

     yield return new Wait(0.1f);

    // 이후 보상처리 ( 게임 코드)
    popup.gameObject.SetActive(true); // 등등
}

 

 

 

 

Google play console에서 google play games service 설정 중, google cloud를 이용한 OAuth 사용자 동의화면 구성을 했음에도 플레이 콘솔 단계가 안넘어가는 경우의 해결책.

 

 

 

구글계정 여러개 로그인 돼있는 경우, 구글 콘솔 개발자 계정만 로그인하고 나머진 로그아웃해라. (크롬에서도)
구글 콘솔에서 개발자 계정 로그인된 경우에도 구글 클라우드 넘어가면서 메인계정으로 바뀌어서 제대로 진행이 안되기 때문이다.

 

타 계정 로그아웃 후 진행하면 아래스샷의 네모를 누르면 자동으로 동의화면 OAuth 가 생성되고 순조롭게 진행된다.

구글의 계정전환이 문제였다.

 

 

 

이후 Refresh(새로고침) 누르면 해결.

 

 

구글플레이게임즈 전반적인 인증 및 세팅 방법은 이 영상을 참고하자

 

https://www.youtube.com/watch?v=0AtXxdvdKcQ 

 

[GPGS 세팅할때 도움되는 참고 링크]

https://developer.thebackend.io/unity3d/guide/federation/gpgs/

https://github.com/playgameservices/play-games-plugin-for-unity

 

사용자 동의화면(OAuth consent screen) - Scope 설정할때 위의 것들이 안뜨는 경우 해결책이다.

 

1) Enable API & services 로 들어간다음

2) 상단에 +ENABEL API AND SERVICES 클릭 후, 

3) 아래쪽에, 구글 플레이 게임즈 누르고 활성화 하면,

4) OAuth consent screen 설정(edit) 다시 들어가서 scope 에 뜬다.

 

 

 

 IEnumerator checkInternetConnection(Action<bool> action){
     WWW www = new WWW("http://google.com");
     yield return www;
     if (www.error != null) {
         action (false);
     } else {
         action (true);
     }
 } 
 void Start(){
     StartCoroutine(checkInternetConnection((isConnected)=>{
         // handle connection status here
     }));
 }

https://answers.unity.com/questions/567497/how-to-100-check-internet-availability.html?childToView=744803#answer-744803

스크립트 파일은 꼭 유니티 에디터 안에서만 이동시켜야한다.

윈도우 탐색기나 비주얼 스튜디오 등 외부에서 스크립트 파일을 이동하는 경우 유니티 내부의 연결구조가 끊어져 missing script 가 뜨게된다. 

이때 해당 스크립트 붙은 오브젝트, 프리팹을 찾아 일일이 다시 연결해야하는데 상당히 번거롭다.

꼭, 유니티 안에서만 스크립트 파일을 이동시키자

 

 

Interface 가 붙은 gameObject를 널체크할때 항상 true가 리턴되는 문제가 있다.

유니티 gameObject는 Destroy 되면 실제 null이 아닌 fake null 을 넣기때문에, null체크시 항상 유니티Object의 오버라이딩 된 == 를 사용해야 한다.

그러나 인터페이스로 참조된 gameObject는 fake null이 들어갔지만 연산자 == 를 c# 꺼로 사용해서 항상 true가 나오는 것

 

아래 코드를보자. (작동하는 코드는 아니고 개념만 보는용도)

 

public interface Unit
{
}

public class Monster : Monobehavior, Unit
{
}


void Start()
{
	var monster = Instanciate(monsterPrefab);
    Unit unit = (Unit)monster;
    
    Destroy(monster.gameObject); // 여기서 fake null이 들어감

	if(unit == null){ // 항상 true. c#의 == 연산자 사용
    	 
    }
    
    if((UnityEngine.Object)unit == null){ // 올바른 null 체크법. 유니티 Object의 오버라이딩된 == 연산자 사용
    	
    }
}

 

UnityEngine.Object 로 캐스팅해서 오버라이딩 된 유니티 == 연산자를 쓰도록 하면 된다.

 

 

 

분명히 PlayFabSharedSettings 에 입력 제대로 했는데 에러가 뜨는경우 해결법

 

상단 메뉴 - Edit - Project settings - Editor - Enter Player mode Option을 끄고 컴파일 후 실행해본다.

 

뭔가가 리프레쉬가 되지 않아 생기는 문제로 보인다. 뭔가 원인을 알수없는 문제의 상당수가 플레이 모드 옵션에서 생기는것 같다. 

 

또 A Native Collection has not been disposed, resulting in a memory leak 에러도 플레이모드와 연관 있는게 아닌가 의심된다.

 

 

주로 2D sprite 애니메이션 전환할때 헤메는 부분이다.

 

애니메이션 트랜지션(전환)에서 Exit time 이라고 적힌건 초(sec)가 아니라 애니메이션 클립 길이의 퍼센티지(%) 비율이다.

위 짤에서 attack에서 walk로 넘어가는데 Exit time이 1이란 것은 attack 클립의 전체를 보고 walk로 넘어가겠다는 의미이다.

이 값이 0.75 면 attack 클립의 뒷부분 25%는 짤리고, 1.25 면 attack 클립이 한번 + 첫부분 25% 추가로 재생된 후 전환된다.

초(sec)로 이해해서 많이 헤맸으나, normalized time 이란거 보고 뒤늦게 깨달음. 한동안 안하면 또 까먹을거같다

 

 

 

 

유니티

SendMessage cannot be called during Awake, CheckConsistency, or OnValidate (back: OnCanvasHierarchyChanged)

이라는 경고 메시지가 게임 Run 할때마다 발생함(에디터 상에서)

 

본인은 캐릭터 hp 바를 별도의 Canvas 에 각각 넣어줬는데 그 Canvas 의 overrideSorting 체크하니까 경고 사라짐

얼떨결에 해결

 

 

이번에 mediation 도입하면서 삽질한 내용 정리.

 

1. 빌드시 아래 에러메세지 뜨면서 빌드가 안되는 현상 

The SDK has resolved to an incompatible version with the Package. 어쩌구... include mainTemplate.gradle file by ...

일단 캔슬 빌드 누르고,

 

 

2. Edit > Project settings > Player > publishing setting에 들어가서 아래 스샷처럼 main Gradle 과 custom gradle properties templet 체크해주기 (파란 네모)

 

 

3. 위 스샷의 빨간네모의 경로의 gradleTemplate.properties 파일을 열어서 아래 내용 있는지 확인. 없으면 추가하고 저장

 

android.useAndroidX=true
android.enableJetifier=true

 

4. 이후 빌드시 exception 뜨면서 빌드가 중지되는데 에러메세지 잘 읽어보면 아래와 같은 내용이 나오는 경우의 해결책에 해당한다. 클래스가 중복된다면서 UnityAds 가 엄청 많이 겹치나보다... 

 

Execution failed for task ':launcher:checkReleaseDuplicateClasses'."

 

5. [해결책] 패키지 매니저에서 설치된 구형 Advertisement 를 remove 해야한다!!! (mediation 아닌 그냥 ad)

 

6. 일단 나는 둘다 삭제하고Advertisement with Mediation 만 다시 설치했다

 

7. 그 후에 유니티 상단 메뉴에서 Asset-> External Dependency manager -> android -> resolve 예의상 돌려주고 빌드하니 문제해결!

 

.

.

.

신형 광고인 미디에이션과 구형 광고의 클래스들이 충돌해서 벌어진 일인것 같다. Service - Ads 에 Install 패키지 떡 하니 써 놓아서 마치 무조건 설치해야하는 인상을 주는데 알고보니 역대급 함정... 무개념 유니티 하....

 

어쨌든 오늘도 해결했다.

 

 

<참고 링크>

https://stackoverflow.com/questions/69736807/gradle-failed-to-fetch-dependencies-for-unity-mediation-firebase-and-google-pl

https://answers.unity.com/questions/1711904/android-apk-build-failing-execution-failed-for-tas.html

 

 

 

 

 

 

 

유니티

 

Immediat mode 스크립트로 그린 그림이 에디터에선 되는데 빌드 시 아예 안나오는 경우

 

1. 아래 링크 지시대로 clean 및 reinstall 작업을 한다 (그냥 지우고 재 import 하는게 아님)

https://shapes.userecho.com/knowledge-bases/2/articles/290-how-to-do-a-clean-reinstall-of-shapes

 

2. Shapes -> 설정(option?) -> Gpu instancing 체크해제 

 

기타) option에서 렌더 pipeline 파일에 Shapes 관련 컴포넌트? 추가하기

-- 난 혹시 몰라서 안쓰는 파이프라인 파일 모두에도 추가했다. 큰 상관은 없는듯

 

 

위 방법으로도 안된다면 아래 링크 샅샅히 뒤져가며 해결해보자... 장담은 못함

https://shapes.userecho.com/communities/1/topics/385-shapes-not-rendering-in-builds-investigation-megathread

유니티 에디터가 아닌 타 플랫폼 빌드시에만 위 에러 뜨는 경우

 


#if UNITY_EDITOR

<< 여기에 Serialized 된 필드가 없어야한다 >>

#endif

위와같이 #if 와 #endif 전처리기 구문 사이에 public 이나 [SerializedField] 구문으로 선언된 필드가 없어야한다.

원리는 모르겠으나 드러난(serialized) 구조가 변경되면 에러를 뿜는것 같다.

#if 문을 변수들 잘 피해서 옮긴 후 테스트 해보자.

 

크기를 유지한채 애니메이션 개별 이미지들 동시에 자르는 법

 

https://motivation.tistory.com/959

 

위 링크를 참고하되 마지막에 PNG 옵션에서 Trim layer는 꺼주도록 한다

빈 공간을 자르면 애니메이션 중심이 흐트리지기 때문이다.

 

 

 

unity 

 

내 경우에는 에디터상에서는 별 이상없었으나 안드로이드 빌드한 경우 위의 경고메시지가 뜨면서 로딩이 작동하지 않았다. 몇가지 해결책을 정리해본다.

 

1) 세이브파일 삭제하고 다시 세이브

https://docs.moodkie.com/easy-save-3/es3-api/es3-methods/es3-deletefile/

 

2) 수동 레퍼런스 추가

유니티 프로젝트 뷰에서 해당 파일들 다 선택한후 우클릭 -> Easy save3 -> Add references to manager

원래 자동으로 파일참조를 업뎃하는데 문제가 발생했기에 수동으로 추가해주는 과정이다. 안드로이드 에러는 이걸로 해결했다.

 

3) 이지세이브 포럼에서 검색

https://moodkie.com/forum/search.php?keywords=Reference+with+ID+could+not+be+found

영어가 된다면 직접 문의하거나 다른사람의 사례를 참고하면 좋다

 

 

유니티 내장 Pool을 쓰면서 재사용 시 초기화 순서가 많이 헷갈려 원하는대로 컨트롤이 힘들었다.

로그를 찍어가면서 확인한 결과 알게된 것을 정리해본다.

 

[최초 생성 시] ObjectPool.Get()   Awake() OnEnable() ActionOnGet() Start()

 

[재활용 시] ObjectPool.Get() ActionOnGet() 안에서 gameObject.SetActive(true)하면 즉시 OnEnable()

 

유니티에서 setActive(true) 호출하면 OnEnable()이 호출되는 것을 알고있어야한다.

최초생성시에는 Get()과 동시에 생성되면서 gameObject의 awake -> OnEnable 사이클을 타지만,

재활용 시에는 ActionOnGet 먼저 호출되고 그 안에서 SetActive() 호출 시 -> OnEnable()이 호출되는 흐름을 타게된다. 최초생성시와는 다르게 이미 생성된 오브젝트를 재사용하는거라 Start()는 호출되지 않는다.

물론 이 순서도 ActionOn--() 안에서 SetActive()을 쓰지 않으면 바뀐다.

 

대개 ObjectPool.Get() 이후에 transform pos나 rotation 값을 넣어주는데 이 부분은 사이클의 맨 마지막에 들어오기 때문에 ActionOnGet(), OnEnable()에서 아무리 바꿔도 소용이 없는 것이다.

 

아래 코드를 보자.

 

 

 

Pool.Get() 에서 연달아 호출되는 메서드에서 position을 정해도 다음 줄에서 Vector3.zero로 바뀌는 모습이다.

주의해서 사용하자

 

 

 

 

 

 

#unity

유니티 허브에 프로젝트를 열거나 Program files 에 설치된 유니티 에디터를 직접 열려고 시도해도 아무런 반응없이 로딩 원만 빙빙돌다 무반응되는 경우가 있다. 아무런 에러메시지도 없어서 해결하기 난감하다.

 

라이센스 문제일 확률이 매우 높다

 

유니티 허브 -> 톱니바퀴 -> 라이선스 에서 새로고침을 눌러본다. 새로고침 실패가 뜬다면

추가 -> 무료 라이센스 받기를 눌러보고 껐다켜기를 반복하다보니 갑자기 라이선스 새로고침이 되고 프로젝트도 잘 열 수 있었다. 에러메시지 없이 안열리는 경우 라이선스를 확인해보자. 인터넷 없는 환경에서 열려고 시도했을때 라이선스가 꼬인게 아닌가 생각된다. 별거 아닌데 원인을 몰라 삽질 후에 작성

 

 

 

#unity

particle/standard unlit 셰이더가 검은색부분을 알파채널로 인식하기 때문에 일어나는 현상이다.

 

해당 파티클 머티리얼을 선택한 후 Shader를 Alpha Blended로 해주면 된다.

 

유니티 파티클 제작중에 선택된 파티클 오브젝트를 재생시키면 경계(테두리)에

주황색 라인이 굵게 생겨, 제대로 알아보기 힘들때가 있다.

 

이때 유니티 씬뷰 오른쪽 위 기즈모 버튼을 눌러 Selection Outline 체크 해제하면 된다.

이제 파티클 편집이 수월해졌다.

 

#unity

 

유니티 공식문서에 의외로 상당히 좋은 내용이 있어 공유한다.

아래와 같은 내용을 포함하고 있다. 

 

  • 배열에서 랜덤항목 선택
  • 확률이 다른항목 선택(각각 숫자 지정 후 확률 배정)
  • 연속 랜덤 가중치 지정( Animation curve 이용)
  • 리스트 순서 섞기 (셔플)
  • 아이템 집합에서 중복없이 선택
  • 공간 안의 랜덤 포인트( 큐브 안의 랜덤한 점 선택, 원 안의 랜덤 점 선택)

 

이미 많이 쓰던것부터 생소하지만 효율적인 방법까지 전부 나와있으므로

덱빌딩게임 혹은 랜덤이 필요한 모든 게임에 유용하게 쓰일 것 같다.

 

 

https://docs.unity3d.com/kr/2019.4/Manual/RandomNumbers.html

 

랜덤 게임플레이 요소 추가 - Unity 매뉴얼

여러 게임에서 임의로 선택되는 항목 및 값은 중요합니다. 이 섹션에서는 Unity에 내장된 랜덤 함수를 사용하여 일반적인 게임 역학을 구현하는 방법에 대해 알아봅니다.

docs.unity3d.com

 

 

 

#unity

 

특정 아이콘 등 선택된 자식을 앞으로 나오게 해야하는데 순서를 바꾸면 실제 레이아웃(grid ,horizontal 등) 내의 위치마저 바뀌는 문제가 생긴다.

 

이때는 자식에 Canvas 컴포넌트를 붙여주고 Override Sorting 을 체크해준 후 Order in Layer를 스크립트 등으로 sort를 컨트롤 해주면 된다. 즉, Canvas - layout 오브젝트 - 자식(Canvas)

 

Layout이 붙어있는 부모의 자식(icon이라고 가정)에 Canvas를 붙여주면 그 자식의 자식들도 자동으로 부모인 icon을 따라서 sort 된다.

 

** 버튼 등 상호작용을 위해 아래 그림과같이 Graphic Raycaster도 오브젝트에 붙여줘야한다.

 

 

 

https://www.reddit.com/r/Unity3D/comments/7psox8/ui_element_render_order_in_grid_layout/

 

 

아래와 같이 로그를 찍으면 현재 클래스명과 함수명을 출력해준다. 

디버깅 용도로 좋다.

using System.Reflection;

void Start()
{
	Debug.Log(this.GetType().Name + ": " + MethodBase.GetCurrentMethod().Name);
}

에러메시지 뜰때 해결법

 

1. 유니티를 끈다

2. 프로젝트 폴더/Temp/  안에있는 PropertyDatabase_ 로 시작하는 파일을 지운다

3. 유니티 재실행 하면 메시지가 사라져있다.

 

 

https://forum.unity.com/threads/the-property-database-library-search-propertydatabase-db-is-already-opened.1285634/

해상도에 대응하는 코드는 여러 블로그에 있는데, 적용하던 중 레터박스 쪽에 파란색으로 깜빡거리는 현상이 발생했다.(테스트 기종: 갤럭시s10)

첫 실행시에는 문제없어도 백그라운드로 내리고 다시 키면 깜빡임 현상이 재현되는 경우도 있었다.

 

검색 중에 아래 블로그를 발견

https://blog.naver.com/kj426/222131335427

 

읽어보면 URP에만 나타나는 문제같다.

 

적용 방법

1. 카메라에 스크립트 하나 생성 후, 위 블로그 코드를 붙여넣는다.
2. Start() 함수 안에 onSetting() 을 넣어준다(작성자가 깜빡한듯? ) 

<이하는 내 Canvas 세팅>

3. Canvas 오브젝트에 Canvas Scaler를 붙여주고, mode를 Scale with screen size,
레퍼런스 resolution을 내가 개발할때 켜두는 기준 화면해상도로 변경. Match는 가로게임인 경우 Height로 설정
4. Canvas Render mode를 Screen Space - Camera로 설정해줌

 

빌드 후 실행해보면 해상도 대응되면서 flickering 문제도 해결되었음을 알수있다.

 

 

 

+ Recent posts