반응형

안녕하세요

리스트 박스를 만드는 방법에 대해 알아보도록 하겠습니다.

1. 오브젝트 추가

일단 다음과 같이 오브젝트를 생성합니다.

2. 오브젝트 설정

각 오브젝트는 다음과 같이 설정합니다.

1) Panel

Panel 오브젝트는 크기만 조정했습니다.

Panel

 

2) ScrollRect

ScrollRect오브젝트는 처음에 빈 게임 오브젝트를 생성해준 후 거기에 Scroll Rect 컴포넌트와 Rect Mask 2D 컴포넌트를 추가합니다. 

ScrollRect 컴포넌트의 Content에는 ButtonGroup 오브젝트를 넣어줍니다.

그리고 Horizontal(수평)을 체크를 해제하여 수평(좌우)으로 ButtonGroup 오브젝트가 움직이지 않도록 합니다.

Rect Mask 2D 컴포넌트는 ScrollRect범위내에 ButtonGroup가 넘어갈 경우 안 보이도록 처리됩니다.

ScrollRect 오브젝트에서는 ButtonGroup 오브젝트가 움직일 수 있는 범위를 width와 Height만큼으로 지정합니다.

빨간색 부분이 ScrollRect, 파란색 부분이 ButtonGroup의 범위가 됩니다.

ButtonGroup은 ScrollRect범위의 각 변을 벗어날 수 없게 됩니다.

각 변을 다음과 같이 번호를 매기면, 이동 시 5번 변이 1번 변보다 아래로 내려갈 수 없고(위로는 올라갈 수 있습니다.),  7번 변이 3번 변보다 위로 올라갈 수 없습니다(아래로 내려갈 수 없습니다.).

아래위로 이렇게 제한됩니다.

3) ButtonGroup

Grid Layout Group 컴포넌트를 추가해서 버튼들의 크기를 지정해줄 수 있습니다.

Cell Size를 정하면 하위 버튼들이 크기에 맞게 변합니다.

Width와 Height는 버튼 개수에 따라 맞춰서 지정하면 됩니다.

저는 Y size가 100인 버튼이 6개를 추가했기 때문에 600으로 지정했습니다.

3. 결과물

반응형
반응형

안녕하세요.

Player Settings에서 Target API Level을 API level 29로 설정을 한 후 GoolglePlayServices에서 오류가 발생되었습니다.

 

다음 에러입니다.

Stopped polling job due to exception: System.NullReferenceException: Object reference not set to an instance of an object
  at GooglePlayServices.UnityCompat.VersionFromAndroidSDKVersionsEnum (System.String enumName, System.String fallbackPrefKey, System.Int32 fallbackValue) [0x00000] in /Users/smiles/dev/src/unity-jar-resolver/source/PlayServicesResolver/src/UnityCompat.cs:58 
  at GooglePlayServices.UnityCompat.GetAndroidTargetSDKVersion () [0x00015] in /Users/smiles/dev/src/unity-jar-resolver/source/PlayServicesResolver/src/UnityCompat.cs:116 
  at GooglePlayServices.PlayServicesResolver.CanEnableJetifierOrPromptUser (System.String titlePrefix) [0x000ae] in /Users/smiles/dev/src/unity-jar-resolver/source/PlayServicesResolver/src/PlayServicesResolver.cs:2314 
  at GooglePlayServices.PlayServicesResolver.ResolveUnsafe (System.Action`1[T] resolutionComplete, System.Boolean forceResolution, System.Boolean isAutoResolveJob, System.Boolean closeWindowOnCompletion) [0x00014] in /Users/smiles/dev/src/unity-jar-resolver/source/PlayServicesResolver/src/PlayServicesResolver.cs:1635 
  at GooglePlayServices.PlayServicesResolver+<ScheduleResolve>c__AnonStorey1E.<>m__3F () [0x00000] in /Users/smiles/dev/src/unity-jar-resolver/source/PlayServicesResolver/src/PlayServicesResolver.cs:1604 
  at GooglePlayServices.PlayServicesResolver.ExecuteNextResolveJob () [0x00069] in /Users/smiles/dev/src/unity-jar-resolver/source/PlayServicesResolver/src/PlayServicesResolver.cs:1461 
  at GooglePlayServices.PlayServicesResolver.ScheduleResolve (System.Boolean forceResolution, System.Boolean closeWindowOnCompletion, System.Action`1[T] resolutionCompleteWithResult, System.Boolean isAutoResolveJob) [0x000a7] in /Users/smiles/dev/src/unity-jar-resolver/source/PlayServicesResolver/src/PlayServicesResolver.cs:1617 
  at GooglePlayServices.PlayServicesResolver.AutoResolve (System.Action resolutionComplete) [0x00017] in /Users/smiles/dev/src/unity-jar-resolver/source/PlayServicesResolver/src/PlayServicesResolver.cs:1134 
  at GooglePlayServices.PlayServicesResolver.<ScheduleAutoResolve>m__47 () [0x00016] in /Users/smiles/dev/src/unity-jar-resolver/source/PlayServicesResolver/src/PlayServicesResolver.cs:1113 
  at Google.RunOnMainThread.ExecutePollingJobs () [0x0004a] in /Users/smiles/dev/src/unity-jar-resolver/source/VersionHandlerImpl/src/RunOnMainThread.cs:300 
UnityEngine.Debug:LogError(Object)
Google.RunOnMainThread:ExecutePollingJobs() (at /Users/smiles/dev/src/unity-jar-resolver/source/VersionHandlerImpl/src/RunOnMainThread.cs:303)
Google.RunOnMainThread:<ExecuteAll>m__A() (at /Users/smiles/dev/src/unity-jar-resolver/source/VersionHandlerImpl/src/RunOnMainThread.cs:414)
Google.RunOnMainThread:RunAction(Action) (at /Users/smiles/dev/src/unity-jar-resolver/source/VersionHandlerImpl/src/RunOnMainThread.cs:234)
Google.RunOnMainThread:ExecuteAll() (at /Users/smiles/dev/src/unity-jar-resolver/source/VersionHandlerImpl/src/RunOnMainThread.cs:406)
UnityEditor.EditorApplication:Internal_CallUpdateFunctions() (at C:/buildslave/unity/build/Editor/Mono/EditorApplication.cs:303)

검색을 해보니, Play Services Resolver를 업데이트 해야 해결된다고 합니다.

 

이리저리해보다가 안되서... API level 28로 낮춘 후 재시작하고, 다시 타겟 API 레벨을 상위로 올렸습니다.

 

근본적인 문제해결하면 다시 올리겠습니다.

반응형
반응형

안녕하세요

포맷 후 앱을 빌드하다가 Target Android SDK installed 에러가 발생했습니다.

내용은 Android SDK does not include your Target SDK of 29. Please use the Android SDK Manager to install your target SDK version. Restart Unity after SDK installation for the changes to take effect. 였습니다.

번역하면 "Android SDK에는 Target SDK 29가 포함되어 있지 않습니다. Android SDK Manager를 사용하여 대상 SDK 버전을 설치하십시오. 변경 사항을 적용하려면 SDK 설치 후 Unity를 다시 시작하세요" 입니다.

target 버전의 SDK가 설치가 안되었다는 뜻인데, 설치하려면 안드로이드 스튜디오로 들어가서 File - Settings로 들어갑니다.

좌측에 SDK를 선택해주고 해당 안드로이드 SDK를 설치합니다.

 

설치가 완료되면 unity를 재시작한 후 빌드를 합니다.

 

반응형
반응형

안녕하세요.

개발을 하다 보면 터치 혹은 마우스 클릭으로 오브젝트를 선택해야 하는 경우가 있습니다.

1. 3D 오브젝트 선택하기 

새로 프로젝트를 만들고 3D 오브젝트를 생성해줍니다.

저는 Cube, Capsule, Sphere, Cyinder를 생성한 후 적당한 위치로 이동시켜봅니다.

그리고 빈 오브젝트를 하나 생성해서 스크립트를 다음과 같이 작성합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class SelectObjectManager : MonoBehaviour
{
    Vector3 m_vecMouseDownPos;
 
    void Update()
    {
#if UNITY_EDITOR
        // 마우스 클릭 시
        if (Input.GetMouseButtonDown(0))
#else
        // 터치 시
        if (Input.touchCount > 0)
#endif
        {
 
#if UNITY_EDITOR
            m_vecMouseDownPos = Input.mousePosition;
#else
            m_vecMouseDownPos = Input.GetTouch(0).position;
            if(Input.GetTouch(0).phase != TouchPhase.Began)
                return;
#endif
            // 카메라에서 스크린에 마우스 클릭 위치를 통과하는 광선을 반환합니다.
            Ray ray = Camera.main.ScreenPointToRay(m_vecMouseDownPos);
            RaycastHit hit;
 
            // 광선으로 충돌된 collider를 hit에 넣습니다.
            if(Physics.Raycast(ray, out hit))
            {
                // 어떤 오브젝트인지 로그를 찍습니다.
                Debug.Log(hit.collider.name);
 
                // 오브젝트 별로 코드를 작성할 수 있습니다.
                if (hit.collider.name == "Cube")
                    Debug.Log("Cube Hit");
                else if (hit.collider.name == "Capsule")
                    Debug.Log("Capsule Hit");
                else if (hit.collider.name == "Sphere")
                    Debug.Log("Sphere Hit");
                else if (hit.collider.name == "Cylinder")
                    Debug.Log("Cylinder Hit");
            }
 
        }
    }
}
 
cs

실행하면 오브젝트를 클릭할 때마다 로그가 찍히는 것을 확인할 수 있습니다.

 

2. 2D 오브젝트 선택하기

같은 방식으로 2D 오브젝트를 Square, Circle, Capsule을 생성해줍니다.

2D 오브젝트는 생성할 때 기본적으로 Collider가 없기 때문에 오브젝트에 맞게 Collider를 넣어줘야 합니다.

Square에는 Box Collider 2D를 넣습니다.
Circle에는 Circle Collider 2D를 넣어줍니다.
Capsule에는 Capsule Collider 2D를 넣어줍니다.

그리고 스크립트를 넣을 빈 오브젝트도 생성한 후 다음 스크립트를 넣어줍니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class SelectObjectManager : MonoBehaviour
{
    Vector3 m_vecMouseDownPos;
 
    void Update()
    {
#if UNITY_EDITOR
        // 마우스 클릭 시
        if (Input.GetMouseButtonDown(0))
#else
        // 터치 시
        if (Input.touchCount > 0)
#endif
        {
 
#if UNITY_EDITOR
            m_vecMouseDownPos = Input.mousePosition;
#else
            m_vecMouseDownPos = Input.GetTouch(0).position;
            if(Input.GetTouch(0).phase != TouchPhase.Began)
                return;
#endif
            
 
            // 마우스 클릭 위치를 카메라 스크린 월드포인트로 변경합니다.
            Vector2 pos = Camera.main.ScreenToWorldPoint(m_vecMouseDownPos);
 
            // Raycast함수를 통해 부딪치는 collider를 hit에 리턴받습니다.
            RaycastHit2D hit = Physics2D.Raycast(pos, Vector2.zero);
 
            if (hit.collider != null)
            {
                // 어떤 오브젝트인지 로그를 찍습니다.
                Debug.Log(hit.collider.name);
 
                // 오브젝트 별로 코드를 작성할 수 있습니다.
                if (hit.collider.name == "Square")
                    Debug.Log("Square Hit");
                else if (hit.collider.name == "Circle")
                    Debug.Log("Circle Hit");
                else if (hit.collider.name == "Capsule")
                    Debug.Log("Capsule Hit");
            }
 
        }
    }
}
 
cs

클릭할 때마다 로그가 찍히는 것을 확인할 수 있습니다.

 

3. 2D오브젝트가 선택이 제대로 안될 때

카메라 설정에 Projection이 "Perspective"로 되어있으면 제대로 선택이 안됩니다.

꼭 2D 일 때는 "Orthographic"로 설정해야 합니다.

Perspective : 원근감이 적용됩니다. (주로 3D)
Orthographic : 직각 투영으로 원근감이 없습니다.(주로 2D)

반응형
반응형

안녕하세요

윈도우 11 설치하셨나요??

저는 얼마 전에 윈도우 11을 설치하셨습니다.

win 11 좋은 점도 많고 디자인도 예쁘지만 불편한 점을 발견했습니다. 불편한 점은 마우스로 클릭하지 않고 가져다 대기만 해도 위젯이 활성화되기 때문이죠.

그래서 오늘 준비한 내용은 윈도우 11에서 위젯 비활성화, 제거 방법입니다. 

윈도우 11에서 위젯 비활성화 방법

1. window+i를 눌러 시스템 설정창을 열어줍니다. 

2. 설정에서 개인설정> 작업표시줄을 클릭합니다. 

 

3. 작업 표시줄 항목에서 widget 토글스위치를 꺼줍니다.

 

 

위젯 삭제하기

비활성해도 앱이 백그라운드에서 실행되면 리소스를 사용하게 됩니다. 

위젯을 삭제하려면 다음과 같이합니다.

1. 윈도우버튼을 누르거나 윈도우KEY+Q를 눌러줍니다.

2. Windows PowerShell을 검색 후 관리자 권한으로 실행합니다.

3. Windows PowerShell에서 
winget uninstall "windows web experience pack"명령어를 입력 후에  Enter키를 누릅니다.

5. msstore 원본을  사용하려면 다음 계약을 확인해야 합니다.  "모든 원본 사용 약관에 동의하십니까? "라는 메시지가 출력되며 계속 진행을 하겠다면 Y 키 를 입력 후   Enter를 눌러 줍니다.

6.  [MicrosoftWindows.Client.WebExperience_cw5n1h2txyewy]
패키지 제거 과정이 잠시 진행되면 삭제 절차가 모두 완료됩니다.

 

감사합니다.

 

반응형
반응형

안녕하세요. 오늘은 작업시간을 효과적으로 줄여주는 Window10 단축키를 

공유하겠습니다. 


복사, 붙여넣기 및 기타 일반적인 바로 가기 키

Ctrl + X 선택한 항목을 잘라냅니다.
Ctrl + C(또는 Ctrl + Insert) 선택한 항목을 복사합니다.
Ctrl + V (또는 Shift + Insert) 선택한 항목을 붙여넣습니다.
Ctrl + Z 작업을 실행 취소합니다.
Alt + Tab 열려 있는 앱 간에 전환합니다.
Alt + F4 활성 항목을 닫거나 활성 앱을 종료합니다.
Windows 로고 키  + L PC를 잠급니다.
Windows 로고 키  + D 바탕 화면을 표시하거나 숨깁니다.
F2 선택한 항목의 이름을 바꿉니다.
F3 파일 탐색기에서 파일 또는 폴더를 검색합니다.
F4 파일 탐색기에서 주소 표시줄 목록을 표시합니다.
F5 활성 창을 새로 고칩니다.
F6 창이나 바탕 화면의 화면 요소들을 순환합니다.
F10 활성 앱의 메뉴 모음을 활성화합니다.
Alt + F8 로그인 화면에서 암호를 표시합니다.
Alt + Esc 열린 순서대로 항목을 순환합니다.
Alt + 밑줄이 그어진 문자 해당 문자에 대한 명령을 수행합니다.
Alt + Enter 선택한 항목의 속성을 표시합니다.
Alt + 스페이스바 활성 창에 대한 바로 가기 메뉴를 엽니다.
Alt + 왼쪽 화살표 뒤로 이동합니다.
Alt + 오른쪽 화살표 앞으로 이동합니다.
Alt + Page Up 한 화면 위로 이동합니다.
Alt + Page Down 한 화면 아래로 이동합니다.
Ctrl + F4 활성 문서를 닫습니다(전체 화면이어서 여러 개의 문서를 동시에 열 수 있는 앱).
Ctrl + A 문서나 창에 있는 모든 항목을 선택합니다.
Ctrl + D (또는 Delete) 선택한 항목을 삭제하고 휴지통으로 이동합니다.
Ctrl + R (또는 F5) 활성 창을 새로 고칩니다.
Ctrl + Y 작업을 다시 실행합니다.
Ctrl + 오른쪽 화살표 커서를 다음 단어의 시작 부분으로 이동합니다.
Ctrl + 왼쪽 화살표 커서를 이전 단어의 시작 부분으로 이동합니다.
Ctrl + 아래쪽 화살표 커서를 다음 단락의 시작 부분으로 이동합니다.
Ctrl + 위쪽 화살표 커서를 이전 단락의 시작 부분으로 이동합니다.
Ctrl + Alt + Tab 화살표 키를 사용하여 열려 있는 모든 앱 사이를 전환합니다.
Alt + Shift + 화살표 키 시작 메뉴에서 그룹이나 타일에 포커스가 놓이면 지정된 방향으로 이를 이동합니다.
Ctrl + Shift + 화살표 키 시작 메뉴에서 타일에 포커스가 놓으면 이를 다른 타일로 이동하여 폴더를 만듭니다.
Ctrl + 화살표 키 시작 메뉴가 열려 있으면 크기를 조정합니다.
Ctrl + 화살표 키(항목으로 이동이 목적) + 스페이스바 창이나 바탕 화면에서 여러 개의 개별 항목을 선택합니다.
Ctrl + Shift + 화살표 키 텍스트 블록을 선택합니다.
Ctrl + Esc 시작 메뉴를 엽니다.
Ctrl + Shift + Esc 작업 관리자를 엽니다.
Ctrl + Shift 여러 개의 자판 배열을 사용할 수 있을 때 해당 자판 배열을 전환합니다.
Ctrl + 스페이스바 중국어 IME(입력기)를 켜거나 끕니다.
Shift + F10 선택한 항목에 대한 바로 가기 메뉴를 표시합니다.
Shift + 모든 화살표 키 창이나 바탕 화면에서 둘 이상의 항목을 선택하거나 문서에서 텍스트를 선택합니다.
Shift + Delete 선택한 항목을 휴지통으로 먼저 이동하지 않은 상태에서 삭제합니다.
오른쪽 화살표 오른쪽에 있는 다음 메뉴를 열거나 하위 메뉴를 엽니다.
왼쪽 화살표 왼쪽에 있는 다음 메뉴를 열거나 하위 메뉴를 닫습니다.
Esc 현재 작업을 중지하거나 나갑니다.
PrtScn 전체 화면의 스크린샷을 생성하고 클립보드에 복사합니다. 
참고

 

 

 

윈도우 + 바로가기 단축키

Windows 로고 키 시작 메뉴를 열거나 닫습니다.
Windows 로고 키   + A 알림 센터를 엽니다.
Windows 로고 키  + B 알림 영역에 포커스를 설정합니다.
Windows 로고 키  + C 듣기 모드로 Cortana를 엽니다.

참고

  • 이 바로 가기는 기본적으로 꺼져 있습니다. 켜려면 시작  > 설정  > Cortana를 선택하고 Windows 로고 키 + C를 누르면 Cortana에서 내 명령 수신에서 토글을 켭니다.
  • Cortana는 특정 국가/지역에서만 사용 가능하며, 일부 Cortana 기능은 일부 국가/지역에서 사용 불가능할 수 있습니다. Cortana를 사용할 수 없거나 Cortana가 꺼져 있는 경우에도 계속 검색을 사용할 수 있습니다.
Windows 로고 키 + Shift + C 참 메뉴를 엽니다.
Windows 로고 키  + D 바탕 화면을 표시하거나 숨깁니다.
Windows 로고 키  + Alt + D 바탕 화면에서 날짜 및 시간을 표시하거나 숨깁니다.
Windows 로고 키  + E 파일 탐색기를 엽니다.
Windows 로고 키  + F 피드백 허브를 열고 스크린샷을 생성합니다.
Windows 로고 키  + G 게임이 열려 있을 때 게임 바를 엽니다.
Windows 로고 키  + H 받아쓰기를 시작합니다.
Windows 로고 키  + I 설정을 엽니다.
Windows 로고 키  + J Windows 팁이 있는 경우 그곳에 포커스를 설정합니다.

Windows 팁이 표시되면 그 팁에 포커스를 가져갑니다.  바로 가기 키를 다시 눌러서 Windows 팁이 고정된 화면의 요소에 포커스를 가져갑니다.
Windows 로고 키  + K 연결 바로 가기를 엽니다.
Windows 로고 키  + L PC를 잠그거나 계정을 전환합니다.
Windows 로고 키  + M 모든 창을 최소화합니다.
Windows 로고 키  + O 장치 방향을 잠급니다.
Windows 로고 키  + P 프레젠테이션 표시 모드를 선택합니다.
Windows logo key  + Ctrl + Q 빠른 지원을 엽니다.
Windows 로고 키  + R 실행 대화 상자를 엽니다.
Windows 로고 키  + S 검색을 엽니다.
Windows 로고 키  + Shift + S 화면 부분의 스크린샷을 생성합니다.
Windows 로고 키  + T 작업 표시줄의 앱을 순환합니다.
Windows 로고 키  + U 접근성 센터를 엽니다.
   
Windows 로고 키  + Shift + V 알림을 순환합니다.
Windows 로고 키  + X 빠른 링크 메뉴를 엽니다.
Windows 로고 키  + Y Windows Mixed Reality와 데스크톱 간 입력을 전환합니다.
Windows 로고 키  + Z 전체 화면 모드에서 앱에서 사용 가능한 명령을 표시합니다.
Windows 로고 키  + 마침표(.) 또는 세미콜론(;) 이모지 패널을 엽니다.
Windows 로고 키  + 쉼표(,) 바탕 화면에서 임시로 미리 봅니다.
Windows 로고 키  + Pause 시스템 속성 대화 상자를 표시합니다.
Windows 로고 키  + Ctrl + F PC를 검색합니다(네트워크에 연결되어 있을 경우).
Windows 로고 키  + Shift + M 바탕 화면에서 최소화된 창을 복원합니다.
Windows 로고 키  + 숫자 바탕 화면을 열고 번호로 표시된 위치에서 작업 표시줄에 고정된 앱을 시작합니다. 앱을 이미 실행 중인 경우에는 해당 앱으로 전환합니다.
Windows 로고 키  + Shift + 숫자 바탕 화면을 열고, 번호로 표시된 위치에서 작업 표시줄에 고정된 앱의 새 인스턴스를 시작합니다.
Windows 로고 키  + Ctrl + 숫자 바탕 화면을 열고, 번호로 표시된 위치에서 작업 표시줄에 고정된 앱의 마지막 활성 창으로 전환합니다.
Windows 로고 키  + Alt + 숫자 바탕 화면을 열고, 번호로 표시된 위치에서 작업 표시줄에 고정된 앱의 점프 목록을 엽니다.
Windows 로고 키  + Ctrl + Shift + 숫자 바탕 화면을 열고, 관리자로서 작업 표시줄에서 해당 위치에 있는 앱의 새 인스턴스를 엽니다.
Windows 로고 키  + Tab 작업 보기를 엽니다.
Windows 로고 키  + 위쪽 화살표 창을 최대화합니다.
Windows 로고 키  + 아래쪽 화살표 화면에서 현재 앱을 제거하거나, 바탕 화면 창을 최소화합니다.
Windows 로고 키  + 왼쪽 화살표 앱이나 바탕 화면 창을 화면의 왼쪽으로 최대화합니다.
Windows 로고 키  + 오른쪽 화살표 앱이나 바탕 화면 창을 화면의 오른쪽으로 최대화합니다.
Windows 로고 키  + Home 활성 바탕 화면 창을 제외한 모든 창을 최소화합니다(두 번째 스트로크에서 모든 창 복원).
Windows 로고 키  + Shift + 위쪽 화살표 바탕 화면 창을 화면 위쪽 및 아래쪽으로 벌립니다.
Windows 로고 키  + Shift + 아래쪽 화살표 너비를 유지하면서 활성 바탕 화면 창을 세로로 복원/최소화합니다.
Windows 로고 키  + Shift +왼쪽 화살표 또는 오른쪽 화살표 모니터 간에 바탕 화면의 앱이나 창을 이동합니다.
Windows 로고 키  + 스페이스바 입력 언어 및 자판 배열을 전환합니다.
Windows 로고 키  + Ctrl + 스페이스바 이전에 선택한 입력으로 변경합니다.
Windows 로고 키  + Ctrl + Enter 내레이터를 켭니다.
Windows 로고 키  + 더하기(+) 돋보기를 엽니다.
Windows 로고 키  + 슬래시(/) IME 재변환을 시작합니다.
Windows 로고 키  + Ctrl + V 숄더 탭을 엽니다.
Windows 로고 키  + Ctrl + Shift + B 비어 있거나 검은색 화면의 PC를 절전 모드에서 해제합니다.

명령프롬프트 바로가기키

 

Ctrl + C(또는 Ctrl + Insert) 선택한 텍스트를 복사합니다.
Ctrl + V (또는 Shift + Insert) 선택한 텍스트를 붙여넣습니다.
Ctrl + M 표시 모드로 들어갑니다.
Alt + 선택 키 블록 모드에서 선택을 시작합니다.
화살표 키 지정된 방향으로 커서를 이동합니다.
Page up 커서를 한 페이지 위로 이동합니다.
Page Down 커서를 한 페이지 아래로 이동합니다.
Ctrl + Home (표시 모드) 커서를 버퍼의 시작 부분으로 이동합니다.
Ctrl + End(표시 모드) 커서를 버퍼의 끝부분으로 이동합니다.
Ctrl + 위쪽 화살표 출력 기록에서 한 줄 위로 이동합니다.
Ctrl + 아래쪽 화살표 출력 기록에서 한 줄 아래로 이동합니다.
Ctrl + Home(기록 탐색) 명령줄이 비어 있으면 버퍼의 맨 위로 뷰포트 이동 그렇지 않은 경우, 명령줄에서 커서 왼쪽으로 모든 문자들을 삭제
Ctrl + End(기록 탐색) 명령줄이 비어 있으면 그 명령줄로 뷰포트를 이동합니다. 그렇지 않은 경우, 그 명령줄에서 커서 오른쪽에 있는 모든 문자들을 삭제합니다.

대화상자 바로 가기키

 

F4 활성 목록에 해당 항목을 표시합니다.
Ctrl + Tab 탭에서 앞으로 이동합니다.
Ctrl + Shift + Tab 탭에서 뒤로 이동합니다.
Ctrl + 숫자(숫자 1–9) n번째 탭으로 이동합니다.
Tab 옵션에서 앞으로 이동합니다.
Shift + Tab 옵션에서 뒤로 이동합니다.
Alt + 밑줄이 그어진 문자 해당 문자에서 사용되는 명령을 수행합니다(또는 옵션 선택).
스페이스바 활성 옵션이 확인란인 경우에는 확인란을 선택하거나 선택 취소합니다.
백스페이스 다른 이름으로 저장 또는 열기 대화 상자에서 폴더가 선택된 경우, 폴더를 한 수준 위로 엽니다.
화살표 키 활성 옵션이 옵션 단추 그룹인 경우에는 단추를 선택합니다.

파일 탐색기 바로가기키

Alt + D 주소 표시줄을 선택합니다.
Ctrl + E 검색 상자를 선택합니다.
Ctrl + F 검색 상자를 선택합니다.
Ctrl + N 새 창을 엽니다.
Ctrl + W 활성 창을 닫습니다.
Ctrl + 마우스 스크롤 휠 파일 및 폴더 아이콘의 크기와 모양을 변경합니다.
Ctrl + Shift + E 선택한 폴더 위에 있는 모든 폴더를 표시합니다.
Ctrl + Shift + N 새 폴더를 만듭니다.
Num Lock + 별표(*) 선택한 폴더 아래에 있는 모든 하위 폴더를 표시합니다.
Num Lock + 더하기(+) 선택한 폴더의 내용을 표시합니다.
Num Lock + 빼기(-) 선택한 폴더를 축소합니다.
Alt + P 미리 보기 창을 표시합니다.
Alt + Enter 선택한 항목에 대한 속성 대화 상자를 엽니다.
Alt + 오른쪽 화살표 다음 폴더를 봅니다.
Alt + 위쪽 화살표 폴더가 있었던 폴더를 봅니다.
Alt + 왼쪽 화살표 이전 폴더를 봅니다.
백스페이스 이전 폴더를 봅니다.
오른쪽 화살표 현재 선택한 폴더를 표시하거나(축소된 경우) 첫 번째 하위 폴더를 선택합니다.
왼쪽 화살표 현재 선택한 폴더를 축소하거나(확장된 경우) 폴더가 있었던 폴더를 선택합니다.
End 활성 창의 맨 아래를 표시합니다.
Home 활성 창의 맨 위를 표시합니다.
F11 활성 창을 최대화하거나 최소화합니다.

 

가상 데스크톱바로가기키

 

Windows 로고 키  + Tab 작업 보기를 엽니다.
Windows 로고 키  + Ctrl + D 가상 데스크톱을 추가합니다.
Windows 로고 키  + Ctrl + 오른쪽 화살표 오른쪽에서 생성한 가상 데스크톱 간에 전환합니다.
Windows 로고 키  + Ctrl + 왼쪽 화살표 왼쪽에서 생성한 가상 데스크톱 간에 전환합니다.
Windows 로고 키  + Ctrl + F4 사용 중인 가상 데스크톱을 닫습니다.

 

작업표시줄 키 바로가기키

Shift + 작업 표시줄 단추 클릭 앱을 열거나, 앱의 또 다른 인스턴스를 빨리 엽니다.
Ctrl + Shift + 작업 표시줄 단추 클릭 앱을 관리자 권한으로 엽니다.
Shift + 작업 표시줄 단추를 마우스 오른쪽 단추로 클릭 앱의 창 메뉴를 표시합니다.
Shift + 그룹화된 작업 표시줄 단추를 마우스 오른쪽 단추로 클릭 그룹의 창 메뉴를 표시합니다.
Ctrl + 그룹화된 작업 표시줄 단추 클릭 그룹의 창을 순환합니다.

바로가기 키 설정

Windows 로고 키  + I 설정을 엽니다.
백스페이스 설정 홈 페이지로 돌아갑니다.
검색 상자를 통해 페이지에 입력 설정을 검색합니다.
반응형
반응형

갑작스레 OS 업데이트로 인해 휴대폰이 재시작되면서 USIM핀 번호를 입력하는 창이 나왔습니다.



3번의 기회가 주어지는데, 도통 기억이 나질 않습니다.

2번 틀리고 마지막 1번남았을 때 핀번호를 맞췄습니다.

오랜만에 심장이 쫄깃해졌네요..

그래서 나중에 PIN번호를 또 잊었을 경우를 대비해 검색해봤습니다.

3번 이상 틀리면 유심을 구매할 때 유심을 꽂고 있는 플라스틱 카드(?)에 적혀있는 PUK을 입력해야 합니다.

보통 그 플라스틱 카드(?)를 오랫동안 보관하기는 어려울 것 같습니다.

USIM 번호를 기억 못 하는데, PUK를 기억할리 없습니다.

PUK를 모르니 대리점 가서 처리를 해야 한다고 생각했는데, 각 통신사 홈페이지에 들어가면 PUK를 조회할 수 있습니다.

공동 인증서 / 아이핀 인증이 필요합니다.

통신사 별 조회방법

SKT 
T월드홈페이지(https://www.tworld.co.kr/)
myT>나의가입정보>나의가입정보>유심 잠금 해제코드(PUK 번호) 조회

KT
KT홈페이지(https://www.kt.com/)
"PUK"로 검색 > PUK번호 조회 > USIM PIN 초기화 비빌번호 > PUK 번호 조회

LG U+
LG U+ 홈페이지PC(https://www.uplus.co.kr/)
내정보관리 > 가입서비스 조회 및 변경 > 내 가입정보 > 휴대폰가입정보 > 유심 잠금 해제코드(PUK 번호) 조회

기타 통신사
통신사 고객센터에 연락

 


자세한 방법은 SKT만 남겨놓겠습니다.

T월드 홈페이지에 접속합니다.(https://www.tworld.co.kr/)

좌측에 myT 버튼을 누른 후 나의 가입정보를 클릭합니다.

다시 또 나의 가입정보 클릭합니다.

유심 잠금 해제 코드(PUK 번호) 조회에서 조회하기 버튼을 눌러줍니다.

 

공동 인증서로 인증합니다.

 

PUK번호가 조회되었습니다.

 PIN번호를 3번 틀렸을 때 조회한 PUK번호를 넣으면 됩니다.

반응형
반응형

안녕하세요.

지난 시간에 이어서 디스코드 봇 만들기를 위한 코드작성에 대해 알아보도록 하겠습니다.

 

디스코드 봇 만들기(1) - 봇생성

안녕하세요. 디스코드 봇을 만드는 법에 대해 알아보도록 하겠습니다. 일단 디스코드 사이트로 들어갑니다. https://discord.com/ Discord | Your Place to Talk and Hang Out Discord is the easiest way to talk..

scvtwo.tistory.com

언어는 여러가지가 있지만, 파이썬을 이용해 보겠습니다.

discord.py 라이브러리 패키지를 설치가 필요합니다.

콘솔창에서 다음 명령어를 입력합니다.

pip install discord.py

그리고 다음과 같이 코드를 작성합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import discord
from discord.ext import commands
 
bot = commands.Bot(command_prefix='#')
 
@bot.event
async def on_ready():
    print(f'Login bot: {bot.user}')
 
@bot.command()
async def hello(message):
    await message.channel.send('Hi!')
 
bot.run('#OTY5MTUyNz')
cs

코드를 설명하면, 4번째 줄은 어떤 봇을 만들것인지 설정합니다. "command_prefix='#'"은 '#'을 앞에 넣어서 명령어를 실행하겠다는 의미입니다.(ex. #info, #hi 등등)

@bot.event는 이벤트 함수를 만들겠다는 것이고 함수 앞에 async가 붙는건 비동기로 실행되는 함수라는 의미입니다.

on_ready함수는 봇이 시작될 때 실행되는 이벤트함수입니다.

@bot.command은 command함수를 만들겠다는 의미입니다. def hello함수는 "#hello"를 대화창에 입력했을 경우 실행되는 함수 입니다. 

"message.channel.send('Hi!')"는 메세지가 온 채널에 'Hi!'라는 내용을 보내줍니다. 채팅창에 #hello를 사용자가 보내면 "Hi!" 메세지를 봇이 보내게됩니다.

bot.run('#OTY5MTUyNz')은 token값인 #OTY5MTUyNz 대신 봇을 생성할 때 만들어진 토큰값을 넣어주면 됩니다.

토큰값을 잃어버렷다면, 디스코드의 개발자 페이지에 들어가서 Reset Token을 버튼을 누르면 다시 생성 할 수 있습니다.

실행하면 bot이 온라인 상태로 변경되는 것을 확인할 수 있습니다.

반응형
반응형

안녕하세요.

디스코드 봇을 만드는 법에 대해 알아보도록 하겠습니다.

일단 디스코드 개발자 포털로 들어갑니다.

https://discord.com/developers/applications

 

Discord Developer Portal — API Docs for Bots and Developers

Integrate your service with Discord — whether it's a bot or a game or whatever your wildest imagination can come up with.

discord.com

 

그 후 좌측에 있는 Applications을 클릭합니다.

 

이제 로그인하려고 뜹니다.

아직 회원가입을 안했다면, 회원가입을 하고 로그인을 합니다.

 

그럼 이제 Applications페이지로 들어가게 됩니다.

새로운 Application을 생성해야하기 때문에 "New Application" 버튼을 클릭합니다.

 

이름을 넣어주고 "Create"버튼을 클릭합니다.

아직 봇이 생성된 것은 아닙니다.

좌측에 "Bot"을 클릭합니다.

클릭 후 나온 페이지에서 "Add Bot"버튼을 클릭합니다.

봇을 추가한다는 메세지가 나오는데, "Yes, do it!" 버튼을 클릭합니다.

 

이제 봇이 추가되었습니다.

추후에 코드에서 생성된 봇을 연결하기위해서는 토큰이 필요합니다.

"Reset Token"버튼 클릭하여 토큰 값을 얻습니다.

 

다음 메세지창에서 "Yes, do it!"버튼을 클릭합니다.

토큰은 나중에 코드상에서 봇에 접속하기 위한 고유키이므로, OTY5...로 시작하는 토큰을 복사하고 따로 잘보관해둡니다.(토큰이 유출되면 다른 PC에서도 접근할 수 있습니다)

 

봇을 디스코드 서버에 초대해야 합니다.

다음과 같이해서 URL을 생성합니다.

좌측에 "OAuth2"를 클릭 후 "bot"을 체크하고 아래 BOT 권한을 체크하면 URL이 생성됩니다.

URL을 복사하여 주소창에 넣으면 디스코드 어느 서버 초대할지 선택하라고 합니다.

초대하기 전에 미리 서버를 추가해야합니다.

 

오프라인으로 봇이 서버에 입장했습니다.

오프라인인 봇을 온라인으로 만드는 방법은 다음 페이지를 참조해주세요.

 

디스코드 봇 만들기(2) - 코드(python)

안녕하세요. 지난 시간에 이어서 디스코드 봇 만들기를 위한 코드작성에 대해 알아보도록 하겠습니다. 언어는 여러가지가 있지만, 파이썬을 이용해 보겠습니다. discord.py 라이브러리 패키지를

scvtwo.tistory.com

 

반응형
반응형

안녕하세요.

거의 노트북에 키보드와 마우스 꽂아서 사용해서 터치패드를 사용할 일이 없었는데, 카페나 기타 휴대용으로 노트북을 사용할 일 있어서, 키보드 없이 마우스만 꽂고 사용하게 되면 자꾸 터치패드가 타자를 칠 때 걸리적거립니다.

보통 Fn+F1(제 노트북 기준)을 누르면 비활성화가 되었는데, 컴퓨터 포맷 후에는 먹지 않습니다.

설정에서 쉽게 바꿀 수 있습니다.

단축키로 윈도우 + i를 사옹할 수 있습니다.

윈도우 버튼을 클릭 후 톱니바퀴 모양으로 설정을 실행할 수 있습니다.

설정창에서 터치를 검색하면 바로 터치 설정이 나옵니다.

터치 패드 항목을 클릭하면 키고 끄기 가능합니다.

 

반응형
반응형

안드로이드에서 Webview로 웹사이트를 호출하면 err_cleartext_not_permitted 에러가 발생했습니다.

http://로 시작하는 웹페이지에 접근할 때 보안문제로 인해 발생하게 됩니다.

Android 9.0이상(API 수준 28)에서 발생합니다.

 

가장 빠른 해결 방법은 app\manifests\AndroidManifest.xml에 항목을 다음 항목을 추가하면 됩니다.

android:usesCleartextTraffic="true"

 

반응형
반응형

안녕하세요. 

Vpn을 실행하려고하는데 다음에러가 발생했습니다.

"The security certificate for this site has been revoked. This site should not be trusted(이 사이트에 대한 보안 인증서가 해지되었습니다. 이 사이트는 신뢰할 수 없습니다)" 오류 발생 시 해결방법에 대해 알아보도록 하겠습니다.

보안 프로그램이나 네트워크상에 연결을 할 때 많이 발생하는 것 같습니다.

해결 방법은 Internet Explorer를 실행시켜야합니다.

시작에서 "Internet Explorer"를 검색하여 실행합니다.

 

그 후 오른쪽에 톱니바퀴모양 아이콘을 클릭합니다.

 

인터넷 옵션창이 나오면 고급탭을 선택 한 후 "서버의 인증서 해지 확인*" 항목을 체크해제합니다.

 

확인을 누른 후 처음에 에러메세지 발생했던 프로그램을 재실행시켜줍니다.

보안경고가 뜨지만 신뢰할 수 있는 프로그램이거나 연결이면 예를 눌러서 연결합니다.

반응형
반응형

Apple 정품 아이폰 16 자급제, 핑크, 256GB

구매 방법

요즘 핸드폰 시장이 빙하기이기 때문에 

3가지를 제안드립니다. 

1.  공기계 +알뜰폰 조합

요금제>

15,470*24=371,280원

기계>

공기계를 쿠팡에서 카드할인 받으면

1,057,300원 - 1,057,30원(카드할인) = 951,570 원

공기계를 쿠팡에서 카드할인+ 선물하기 할인까지 받으면 본인 쿠팡으로 결재하고

가족한테 보내기로하면 싸게 구매가능합니다.

951,570 원 - 10,573( 선물하기)=940,997원

2년 사용 총 요금 > 940,997원 + 371,280원=1,312,277원

 

2. 가족결합한분들은! = 공기계+(skt/kt/lg) 통신사

기계값>

공기계를 쿠팡에서 카드할인 받으면

1,057,300원 - 1,057,30원(카드할인) = 951,570 원

951,570 원 - 10,573( 선물하기)=940,997원

거기에 요금제>

가족할인 30%할인+선택약정 20%할인이 들어갑니다.

따라서 총 50%로 할인이 들어갑니다.

예를 들어 T플랜 세이브로 보시면

만약에 T플랜 세이브로 2년을 쓰신다면

기기값> 1,057,300- 105,730원(카드할인10%) - 10,573원( 선물하기)=940,997원

요 금 > 14,850  * 24=356,400원

2년 사용 총 요금 > 940,997원 + 356,400원=1,297,397 원

 

3. 요금 많이 쓰는 분들(9만원이상)은 성지+(skt/kt/lg) 통신사

성지에서는 거의 시세가

비싼 요금제(89요금제6개월+5개 부가서비스) +싼 기기값(50~70)으로 하는데 

요금제를많이 쓰시는 분들은 이게 더 좋은 방법 일 수 있습니다.

아이폰13/128GB기준

기기값530,000원

+ 89요금제6개월(89,000*6=534,000원)

+lte세이브18개월(33000*18=594,000원)

2년 사용 총 요금 =1,658,000

 

공기계는 쿠팡 추천드립니다. 

Apple 정품 아이폰 16 자급제, 핑크, 256GB

이번에 제 핸드폰을 사면서 정리해보았습니다. 

글을 잘보셨다면 위 배너를 눌러 구입해주세요.^^

소정의 금액이 큰힘이 됩니다.

감사합니다. 

 

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."

반응형
반응형

안녕하세요.

Unity와 Firebase를 연동한 후 Firebase기능 중 하나인 데이터베이스를 연동해보도록 하겠습니다.

 

1. Firebase셋팅

Firebase Colsole에 접속합니다.

https://console.firebase.google.com/?hl=ko 

 

로그인 - Google 계정

하나의 계정으로 모든 Google 서비스를 Google 계정으로 로그인

accounts.google.com

 

프로젝트를 추가합니다.

프로젝트 이름을 입력한 후 계속 버튼을 클릭해줍니다.

 

애널리틱스 사용여부를 확인한 후 계속 버튼을 클릭합니다.

애널리틱스 계정 선택을 하라고 나옵니다.

따로 계정이 있다면 설정해주고, 없다면 Default Account for Firebase를 선택한 후 프로젝트 만들기를 클릭합니다.

잠시 기다린 후 준비되었다는 화면이 나오면 계속 버튼을 클릭합니다.

 

프로젝트 창으로 이동되는데, 여기서 Unity마크를 클릭합니다.

 

앱을 등록합니다.

IOS, Android를 각각 등록합니다.

 

유니티 ProjectSettings에 패키지네임을 적으면 됩니다.

 

IOS번들ID와 Android 패키지이름을 넣으면 앱등록 버튼이 활성화됩니다. 

클릭해줍니다.

google-services.json, GoogleService-Info.plist 구성 파일 다운로드를 해서 Unity프로젝트의 Assets폴더에 넣어줘야합니다.

넣어준 후 다음 버튼을 클릭합니다.

Firebase SDK 추가를 합니다.

Firebase Unity SDK(Zip)파을 다운로드 받은 후 압축을 풀어줍니다.

압축을 풀어주면 추후에 변경될지도 모르겠지만, 지금 제가 받은 파일에 dotnet3, dotnet4폴더로 구성되어있는데

버전에 따라 다른 패키지를 임포트합니다.(Unity 5.x버전은 dotnet3 패키지, Unity 2017.x이상에서는 dotnet4 패키지)

애널리틱스를 위에서 사용하기로 했으므로 FirebaseAnalytics.unitypackage를 임포트한 후 Database를 사용하기 위해 FirebaseDatabase.unitypackage도 임포트합니다. 기타 필요한 패키지를 임포트합니다.

 Assets(애셋) - Import Package(패키지 가져오기) - Custom Package(커스텀 패키지)로 추가 가능합니다.

그 후 Firebase Colsole로 돌아와서 다음을 클릭합니다.

이제 설정이 끝났습니다.

콘솔로 이동을 클릭합니다.

 

2. Firebase에서 Database추가

이제 Database를 추가해줍니다.

Realtime Database를 클릭합니다.

 

데이터 베이스 만들기를 클릭합니다.

다음으로 위치설정이있는데, 대한민국은 없기 때문에 미국으로 설정합니다.

테스트를 위해 테스트 모드에서 시작으로 설정합니다.

이제 데이터 베이스를 추가할 수 있도록 셋팅되었습니다.

 

3. 유니티(Unity)에 적용

간단하게 유니티에서 데이터 저장과 로드를 적용해보도록 하겠습니다.

빈오브젝트를 생성하고 스크립트를 넣습니다.

CFirebase.cs 코드는 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Firebase;
using Firebase.Database;
using Firebase.Extensions;
 
public class CFirebase : MonoBehaviour
{
    DatabaseReference m_Reference;
    
    void Start()
    {
        m_Reference = FirebaseDatabase.DefaultInstance.RootReference;
 
        //WriteUserData("0", "aaaa");
        //WriteUserData("1", "bbbb");
        //WriteUserData("2", "cccc");
        //WriteUserData("3", "dddd");
 
        ReadUserData();
 
 
    }
 
    void ReadUserData()
    {
        FirebaseDatabase.DefaultInstance.GetReference("users")
            .GetValueAsync().ContinueWithOnMainThread(task =>
        {
            if (task.IsFaulted)
            {
                // Handle the error...
            }
            else if (task.IsCompleted)
            {
                DataSnapshot snapshot = task.Result;
                // Do something with snapshot...
            for ( int i = 0; i < snapshot.ChildrenCount; i++)
                Debug.Log(snapshot.Child(i.ToString()).Child("username").Value);
              
            }
        });
    }
 
    void WriteUserData(string userId, string username)
    {
        m_Reference.Child("users").Child(userId).Child("username").SetValueAsync(username);
    }
 
}
 
cs

 

WriteUserData함수를 통한 데이터를 저장하면, Database는 다음과 같이 저장됩니다. 

ReadUserData함수를 통해 데이터를 로드하면 디버그로그로 다음과 같이 출력되는 것을 확인할 수 있습니다.

반응형
반응형

안녕하세요.

유니티에서 빌드해서 apk를 생성 후 블루스택에서 확인하려고 했지만 실행되지 않는 문제가 발생하여, 공유하려고 합니다.

Unity 2020.3.19f1에서 발생한 문제였습니다.

휴대폰에 넣었을 때는 문제가 발생하지 않는데 블루스택에 설치하면 까만 화면만 나오고 더 이상 진행되지 않았습니다.

휴대폰에 넣어서 확인하면 되긴 하지만, 아무래도 블루스택에서 다양한 해상도나 환경을 만들 수 있기 때문에 해결하고 싶었습니다.

제가 가지고 있는 이전버전(2019.2.9f1)으로 할 때는 발생하지 않은 문제였습니다.

그래서 시험삼아 2019.2.9f1로 프로젝트를 새로 생성한 후 2020.3.19f1로 업그레이드해서 빌드를 해보았습니다.

그랬더니 정상적으로 블루스택에서 실행이 되었습니다.

먼가 설정문제인 것 같아서 두 프로젝트의 Project Setting을 확인했습니다.

처음부터 2020.3.19f1로 생성한 프로젝트에만 Optimized Frame Pacing이 체크되어있었습니다.

그래서 체크 해제를 한 후 다시 빌드하니 정상적으로 블루스택에서 실행되었습니다.

2019.2 버전부터 지원하는 기능이었는데, 보통 꺼져있는 것이 디폴트 값이었는데, 2020.3.19f1에서는 켜지는 것이 디폴드 값으로 변한 것 같습니다.

https://unity.com/kr/releases/2019-2/platforms-and-editor#optimized-frame-pacing-android

 

플랫폼과 에디터 | Unity

플랫폼과 일반 에디터 워크플로에 대한 Unity 2019.2의 새로운 기능에 대해 알아보세요. AR 파운데이션에 대한 업데이트와 모바일 개발자들을 위한 추가 툴이 새롭게 제공됩니다.

unity.com

 

반응형

+ Recent posts