디바이스 토큰 (NSData)을 NSString으로 어떻게 변환 할 수 있습니까?


157

푸시 알림을 구현하고 있습니다. APNS 토큰을 문자열로 저장하고 싶습니다.

- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)newDeviceToken
{
    NSString *tokenString = [NSString stringWithUTF8String:[newDeviceToken bytes]]; //[[NSString alloc]initWithData:newDeviceToken encoding:NSUTF8StringEncoding];
    NSLog(@"%@", tokenString);
    NSLog(@"%@", newDeviceToken);
}

첫 번째 코드 줄은 null을 인쇄합니다. 두 번째는 토큰을 인쇄합니다. newDeviceToken을 NSString으로 어떻게 얻을 수 있습니까?


두 번째의 출력 무엇입니까 NSLog, 인쇄 그 하나 newDeviceToken?
rob mayoff


설명을 사용하지 마십시오
Fattie

답변:


40

이것을 사용하십시오 :

NSString * deviceTokenString = [[[[deviceToken description]
                         stringByReplacingOccurrencesOfString: @"<" withString: @""] 
                        stringByReplacingOccurrencesOfString: @">" withString: @""] 
                       stringByReplacingOccurrencesOfString: @" " withString: @""];

NSLog(@"The generated device token string is : %@",deviceTokenString);

134
설명을 사용하는 것은 좋지 않은 생각입니다. iOS의 이후 버전이이 호출의 구현 및 결과를 변경하지는 않습니다.
madewulf

16
실제로 이것은 정말 나쁜 생각입니다.
David Snabel-Caunt

21
이 사용 설명에 그런 끔찍한 생각이 얼마나 @madewulf 당신의 아주 좋은 지적을 ... 당신은 심지어 더 좋은 제안했을 경우의 대안
abbood

6
여기 [deviceToken bytes]의 해결책은 청구서에 적합합니다.
madewulf

37
Swift 3 / iOS 10에서 밝혀졌습니다. 장치 토큰에 대한 설명은 "32 바이트"를 반환합니다. 예, 이것을 사용하지 마십시오.
Victor Luft

231

누군가 Swift 에서이 작업을 수행하는 방법을 찾고 있다면 :

func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
    let tokenChars = UnsafePointer<CChar>(deviceToken.bytes)
    var tokenString = ""

    for i in 0..<deviceToken.length {
        tokenString += String(format: "%02.2hhx", arguments: [tokenChars[i]])
    }

    print("tokenString: \(tokenString)")
}

편집 : 스위프트 3

Swift 3는 Data값 의미론을 가진 유형을 소개합니다 . 를 deviceToken문자열 로 변환하려면 다음과 같이하십시오.

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
    print(token)
}

118
이것이 왜 그렇게 복잡해야 하는가? OS가 왜 우리에게 문자열을 제공하는 데 문제가 있는가? 이 솔루션에 감사드립니다.
Piwaf 2016 년

3
@Sascha 나는 당신이 당신의 매우 유용한 답변에 내 편집을 승인하기를 바랍니다 :)
jrturton

16
리팩토링 : let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined() qiita.com/mono0926/items/3cf0dca3029f32f54a09
mono

2
.description을 사용하는 것은 권장되지 않으므로 사용하지 않는 것이 좋습니다. 내 대답을 확인하십시오 : stackoverflow.com/questions/9372815/…
swift taylor

7
당신은 무엇을 설명 할 수 있습니까 "%02.2hhx?
Honey

155

누군가 나를 도와주었습니다.

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {

    const unsigned *tokenBytes = [deviceToken bytes];
    NSString *hexToken = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x",
                         ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
                         ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
                         ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];

    [[MyModel sharedModel] setApnsToken:hexToken];
}

5
이 encondig 16 진수로 바이트 이후, 가장 좋은 방법입니다 당신이 그것을 믿을 수 있음을 의미한다)
loretoparisi

4
XCode 5에서 deviceToken을 컴파일하여 컴파일해야했습니다. const unsigned * tokenBytes = (const unsigned *) [deviceToken bytes];
Ponytech

3
토큰은 곧 32 바이트보다 커질 것이므로 하드 코딩 된 8 개의 정수 대신 각 바이트에 대한 루프 여야합니다.
Tom Dalling

5
이것이 더 나은 해결책입니까? const unsigned *tokenBytes = [deviceToken bytes]; NSMutableString *hexToken = [NSMutableString string]; for (NSUInteger byteCount = 0; byteCount * 4 < [deviceToken length]; byteCount++) { [hexToken appendFormat:@"%08x", ntohl(tokenBytes[byteCount])]; }
Harro

9
Important: APNs device tokens are of variable length. Do not hard-code their size.애플은 말한다.
erkanyildiz

141

이것을 사용할 수 있습니다

- (NSString *)stringWithDeviceToken:(NSData *)deviceToken {
    const char *data = [deviceToken bytes];
    NSMutableString *token = [NSMutableString string];

    for (NSUInteger i = 0; i < [deviceToken length]; i++) {
        [token appendFormat:@"%02.2hhX", data[i]];
    }

    return [token copy];
}

11
사용하는 것보다 훨씬 안전하기 때문에 이것이 대답으로 받아 들여 져야합니다 description.
DrMickeyLauer

8
이것은 Objective-C의 유일한 정답으로 향후 토큰 크기 증가를 처리합니다.
Tom Dalling 5

특정 토큰 크기 / 길이를 가정하지 않기 때문에 이것이 가장 안전한 방법 일 것입니다.
Ryan H.

iOS 10에서 작동합니다.
Tjalsma

2
[token appendFormat:@"%02.2hhx", data[i]];Amazon SNS는 소문자가 필요하므로 사용 했습니다.
Manuel Schmitzberger

43

Swift 3 에서 가장 쉬운 방법 을 원하는 사람들을 위해

func extractTokenFromData(deviceToken:Data) -> String {
    let token = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
    return token.uppercased();
}

1
나는 같은 코드를 썼다 :) 이것은 가장 신속한 버전이며, 이것 만이 작동합니다
Quver

1
@Anand이 코드에서 무엇이 멈췄는지 설명해 주시겠습니까?deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
Ramakrishna

1
데이터를 16 진수 문자열로 직렬화 한 다음 문자열로 직렬화하는 신속한 기능 감소를 사용합니다. 함수 축소에 대한 자세한 내용을 보려면 useyourloaf.com/blog/swift-guide-to-map-filter-reduce
Anand

15

%02.2hhx높은 투표 답변 에 대한 설명 :

  • %: x변환 지정자를 소개 합니다.
  • 02: 변환 된 값의 최소 너비는 2입니다. 변환 된 값의 필드 너비보다 바이트 수가 적은 0경우 왼쪽에 채워집니다 .
  • .2: x변환 지정자 에 표시 할 최소 자릿수를 제공 합니다.
  • hh: x변환 지정자가 부호있는 char 또는 부호없는 char 인수에 적용되도록 지정합니다 (인수는 정수 승격에 따라 승격되지만 값은 인쇄하기 전에 부호있는 char 또는 부호없는 char로 변환됩니다).
  • x: 부호없는 인수는 "dddd"스타일의 부호없는 16 진수 형식으로 변환됩니다. 문자 "abcdef"가 사용됩니다. 정밀도는 표시 할 최소 자릿수를 지정합니다. 변환되는 값을 더 적은 자릿수로 표시 할 수 있으면 앞에 오는 0으로 확장됩니다. 기본 정밀도는 1입니다. 명시 적 정밀도 0으로 0을 변환 한 결과는 문자가 아닙니다.

자세한 내용은 IEEE printf 사양을 참조하십시오 .


위의 설명을 바탕으로, 나는 변화에 더 나은 생각 %02.2hhx%02x하거나 %.2x.

Swift 5의 경우 다음 방법을 모두 사용할 수 있습니다.

deviceToken.map({String(format: "%02x", $0)}).joined()
deviceToken.map({String(format: "%.2x", $0)}).joined()
deviceToken.reduce("", {$0 + String(format: "%02x", $1)})
deviceToken.reduce("", {$0 + String(format: "%.2x", $1)})

테스트는 다음과 같습니다.

let deviceToken = (0..<32).reduce(Data(), {$0 + [$1]})
print(deviceToken.reduce("", {$0 + String(format: "%.2x", $1)}))
// Print content:
// 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f

이 답변에 감사드립니다. iOS 12에서도 작동합니까? 아니면 Swift 버전에만 의존합니까?
Markus

1
@Markus iOS 12에서 작동하며 Swift 버전에만 의존합니다.
jqgsninimo

14

내 솔루션이며 내 앱에서 잘 작동합니다.

    NSString* newToken = [[[NSString stringWithFormat:@"%@",deviceToken] 
stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]] stringByReplacingOccurrencesOfString:@" " withString:@""];
  • 변환 NSDataNSStringstringWithFormat
  • "<>"트림
  • 공백을 제거하십시오

10
이것은 암시 적으로을 호출 -description하므로 허용되는 답변보다 안전하지 않습니다.
jszumski

소스를 연결해 주시겠습니까? 어디서나 정보를 찾을 수 없습니다. 고마워.
Zeb

그것을 발견! 조금 다르다고 생각합니다. description 속성은 향후 버전에서 변경 될 수 있으므로 직접 사용하는 것은 안전하지 않지만 NSString 메서드를 통해 사용하면 거의 문제가 없습니다.
Zeb

5
이것은 실제로 descriptionjszumski가 말하는 것처럼 deviceToken을 호출하지 않습니다 .
Jonny

1
@Zeb description반환 된 문자열의 형식은 언제든지 변경 될 수 있으므로 직접 호출하는지 또는 다른 방법을 통해 사용하는지 에 의존하는 것은 안전하지 않습니다 . 올바른 해결책은 여기에 있습니다 : stackoverflow.com/a/16411517/108105
톰 Dalling

10

deviceToken을 16 진수 바이트 문자열로 변환하는 것은 의미가 없다고 생각합니다. 왜? 백엔드로 보내면 APNS로 푸시하기 위해 바이트로 다시 변환됩니다. 따라서 NSData 의 방법 base64EncodedStringWithOptions을 사용하여 서버로 푸시 한 다음 역방향 base64 디코딩 데이터를 사용하십시오. :) 훨씬 쉽습니다. :)

NSString *tokenString = [tokenData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];

@ jeet.chanchawat 다른 사용자의 답변에 코드를 추가하지 마십시오. 우리는 특히 Objective-C 답변에 Swift를 추가 할 때 입에 단어를 넣고 싶지 않습니다. 대신 자신의 답변을 추가하십시오.
JAL

2
나는 @Oleg Shanyuk의 대답을 plagiarise하고 싶지 않았습니다. 그것은 그의 대답에 기초한 다른 언어로의 번역 일 뿐이므로 미래의 투표권을받을 자격이 있습니다. 다른 답변을 추가하면 다른 사람을 연구하는 답변에 대한 찬성이 나에게 전달됩니다. 이것이 EDIT을 정당화하기를 바랍니다.
jeet.chanchawat

10

iOS 13에서는 description고장이므로 이것을 사용하십시오.

let deviceTokenString = deviceToken.map { String(format: "%02x", $0) }.joined()

명확하게하기 위해 이것을 분해하고 각 부분을 설명합시다.

map 메소드는 시퀀스의 각 요소에서 작동합니다. Data는 Swift에서 일련의 바이트이므로 전달 된 클로저는 deviceToken의 각 바이트에 대해 평가됩니다. String (format :) 이니셜 라이저는 % 02x 형식 지정자를 사용하여 데이터의 각 바이트 (익명 매개 변수 $ 0로 표시)를 평가하여 바이트 / 8 비트 정수의 0으로 채워진 2 자리 16 진수 표현을 생성합니다. map 메소드로 작성된 각 바이트 표시를 수집 한 후, join ()은 각 요소를 단일 문자열로 연결합니다.

PS는 설명을 사용하지 않으며 iOS 12 및 iOS 13에서 다른 문자열을 제공하며 향후 범위에 따라 안전하지 않습니다. 개발자는 객체 설명에 특정 형식을 사용해서는 안됩니다.

// iOS 12
(deviceToken as NSData).description // "<965b251c 6cb1926d e3cb366f dfb16ddd e6b9086a 8a3cac9e 5f857679 376eab7C>"

// iOS 13
(deviceToken as NSData).description // "{length = 32, bytes = 0x965b251c 6cb1926d e3cb366f dfb16ddd ... 5f857679 376eab7c }"

자세한 내용은 This 를 참조하십시오 .


10

iOS 13에서는 설명 형식이 다릅니다. 아래 코드를 사용하여 장치 토큰을 가져옵니다.

- (NSString *)fetchDeviceToken:(NSData *)deviceToken {
    NSUInteger len = deviceToken.length;
    if (len == 0) {
        return nil;
    }
    const unsigned char *buffer = deviceToken.bytes;
    NSMutableString *hexString  = [NSMutableString stringWithCapacity:(len * 2)];
    for (int i = 0; i < len; ++i) {
        [hexString appendFormat:@"%02x", buffer[i]];
    }
    return [hexString copy];
}

iOS를위한 완벽한 솔루션 13. Thanks Vishnu
Manish

1
현재 컴파일되지 않습니다 lengthfor 루프에서로 변경해야합니다 len. 내가 편집하기에 너무 작은 변화 인 것 같습니다. 그러나 완벽하게 작동합니다!
Anders Friis

당신은 생명의 은인입니다
Moeez Akram

3

이것은 조금 더 짧은 해결책입니다.

NSData *token = // ...
const uint64_t *tokenBytes = token.bytes;
NSString *hex = [NSString stringWithFormat:@"%016llx%016llx%016llx%016llx",
                 ntohll(tokenBytes[0]), ntohll(tokenBytes[1]),
                 ntohll(tokenBytes[2]), ntohll(tokenBytes[3])];

3

기능적 스위프트 버전

짧막 한 농담:

let hexString = UnsafeBufferPointer<UInt8>(start: UnsafePointer(data.bytes),
count: data.length).map { String(format: "%02x", $0) }.joinWithSeparator("")

재사용 가능한 자체 문서화 확장 양식이 있습니다.

extension NSData {
    func base16EncodedString(uppercase uppercase: Bool = false) -> String {
        let buffer = UnsafeBufferPointer<UInt8>(start: UnsafePointer(self.bytes),
                                                count: self.length)
        let hexFormat = uppercase ? "X" : "x"
        let formatString = "%02\(hexFormat)"
        let bytesAsHexStrings = buffer.map {
            String(format: formatString, $0)
        }
        return bytesAsHexStrings.joinWithSeparator("")
    }
}

또는 동료가 기능 마스터로 보지 reduce("", combine: +)않고 대신 사용 joinWithSeparator("")하십시오.


편집 : 한 자리 숫자는 패딩 0이 필요하기 때문에 String ($ 0, radix : 16)을 String (format : "% 02x", $ 0)으로 변경했습니다.

(아직 질문을 이 다른 질문과 중복으로 표시하는 방법을 모르므로 답을 다시 게시했습니다.)


나를 위해 일한다, 고마워.
Hasya

3

2020

텍스트로 토큰 ...

let tat = deviceToken.map{ data in String(format: "%02.2hhx", data) }.joined()

또는 원하는 경우

let tat2 = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()

(결과는 같습니다)


2

더미에 내 대답을 던지기. 문자열 구문 분석을 사용하지 마십시오. 문서에서 NSData.description이 항상 그런 식으로 작동한다고 보장하지는 않습니다.

스위프트 3 구현 :

extension Data {
    func hexString() -> String {
        var bytesPointer: UnsafeBufferPointer<UInt8> = UnsafeBufferPointer(start: nil, count: 0)
        self.withUnsafeBytes { (bytes) in
            bytesPointer = UnsafeBufferPointer<UInt8>(start: UnsafePointer(bytes), count:self.count)
        }
        let hexBytes = bytesPointer.map { return String(format: "%02hhx", $0) }
        return hexBytes.joined()
    }
}

1

나는 형식 두 가지 방법을 테스트 해봤 "%02.2hhx""%02x"

    var i :Int = 0
    var j: Int = 0
    let e: Int = Int(1e4)
    let time = NSDate.timeIntervalSinceReferenceDate
    while i < e {
        _ =  deviceToken.map { String(format: "%02x", $0) }.joined()
        i += 1
    }
    let time2 = NSDate.timeIntervalSinceReferenceDate
    let delta = time2-time
    print(delta)

    let time3 = NSDate.timeIntervalSinceReferenceDate
    while j < e {
        _ =  deviceToken.reduce("", {$0 + String(format: "%02x", $1)})
        j += 1
    }
    let time4 = NSDate.timeIntervalSinceReferenceDate
    let delta2 = time4-time3
    print(delta2)

결과는 "%02x"축소 버전의 경우 가장 빠른 것이 평균 2.0 대 2.6입니다.

deviceToken.reduce("", {$0 + String(format: "%02x", $1)})

1

updateAccumulatingResult를 사용하는 것은 여기에있는 다양한 다른 접근법보다 효율적이므로 바이트 를 문자열로 묶는 스위프 방법입니다 Data.

func application(_ application: UIApplication,
                 didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    let token = deviceToken.reduce(into: "") { $0 += String(format: "%.2x", $1) }
    print(token)
}

Alex, % 02.2hhx가 아님
Fattie

0

스위프트

var characterSet: NSCharacterSet = NSCharacterSet( charactersInString: "<>" )
    var deviceTokenString: String = ( deviceToken.description as NSString )
    .stringByTrimmingCharactersInSet( characterSet )
    .stringByReplacingOccurrencesOfString( " ", withString: "" ) as String

println( deviceTokenString )

0

한 줄 솔루션은 어떻습니까?

목표 C

NSString *token = [[data.description componentsSeparatedByCharactersInSet:[[NSCharacterSet alphanumericCharacterSet]invertedSet]]componentsJoinedByString:@""];

빠른

let token = data.description.componentsSeparatedByCharactersInSet(NSCharacterSet.alphanumericCharacterSet().invertedSet).joinWithSeparator("")

2
이것은 간단하고 최상의 솔루션입니다. 감사합니다
Emmy

0

Xamarin.iOS에서 수행하는 방법은 다음과 같습니다.

public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
    var tokenStringBase64 = deviceToken.GetBase64EncodedString(NSDataBase64EncodingOptions.None);
    //now you can store it for later use in local storage
}

-1
NSString *tokenString = [[newDeviceToken description] stringByReplacingOccurrencesOfString:@"[<> ]" withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(0, [[newDeviceToken description] length])];

훌륭한 솔루션 오늘날, 그것은 credentials.token.description.replacingOccurrences (of : "[<>]", "", 옵션 : .regularExpression, 범위 : nil)
Frank

-1

빠른:

let tokenString = deviceToken.description.stringByReplacingOccurrencesOfString("[ <>]", withString: "", options: .RegularExpressionSearch, range: nil)

-2
-(NSString *)deviceTokenWithData:(NSData *)data
{
    NSString *deviceToken = [[data description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
    deviceToken = [deviceToken stringByReplacingOccurrencesOfString:@" " withString:@""];
    return deviceToken;
}

-2

빠른

    // make sure that we have token for the devie on the App
    func application(application: UIApplication
        , didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {

            var tokenStr = deviceToken.description
            tokenStr = tokenStr.stringByReplacingOccurrencesOfString("<", withString: "", options: [], range: nil)
            tokenStr = tokenStr.stringByReplacingOccurrencesOfString(">", withString: "", options: [], range: nil)
            tokenStr = tokenStr.stringByReplacingOccurrencesOfString(" ", withString: "", options: [], range: nil)



            print("my token is: \(tokenStr)")

    }

-2

우수한 카테고리를 사용하십시오!

// .h 파일

@interface NSData (DeviceToken)

- (NSString *)stringDeviceToken;

@end    

// .m 파일

#import "NSData+DeviceToken.h"

@implementation NSData (DeviceToken)

- (NSString *)stringDeviceToken {
    const unsigned *deviceTokenBytes = [deviceToken bytes];
    NSString *deviceToken = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x",
                     ntohl(deviceTokenBytes[0]), ntohl(deviceTokenBytes[1]), ntohl(deviceTokenBytes[2]),
                     ntohl(deviceTokenBytes[3]), ntohl(deviceTokenBytes[4]), ntohl(deviceTokenBytes[5]),
                     ntohl(deviceTokenBytes[6]), ntohl(deviceTokenBytes[7])];
    return deviceToken;
}

@종료

// AppDelegate.m

#import "NSData+DeviceToken.h"

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    NSString *token = deviceToken.stringDeviceToken;
}

잘 작동합니다!


"설명"을 사용하지 마십시오. 형식은 나중에 변경 될 수 있습니다. 표시 용입니다.
Michael Peterson

-3

스위프트 3 :

Swift 3에서 장치 토큰을 얻는 방법을 찾고 있다면 아래 수정 된 스 니펫을 사용하십시오.

    let characterSet: CharacterSet = CharacterSet( charactersIn: "<>" )

    let deviceTokenString: String = (deviceToken.description as NSString)
        .trimmingCharacters(in: characterSet as CharacterSet)
        .replacingOccurrences(of: " ", with: "")
        .uppercased()

    print(deviceTokenString)

2
.description을 사용하지 않는 것이 좋습니다. 그대로 유지되는 것은 아닙니다. 내 답변보기 here : stackoverflow.com/questions/9372815/…
swift taylor

-4
var token: String = ""
for i in 0..<deviceToken.count {
    token += String(format: "%02.2hhx", deviceToken[i] as CVarArg)
}

print(token)

1
설명을 사용하는 것은 앞으로 동일한 결과를 보장하지 않으므로 안전하지 않습니다.
Sahil Kapoor

-4

@kulss 솔루션은 우아함은 없지만 간단 함의 미덕을 가지고 있지만 iOS 13에서는 더 이상 작동하지 않습니다 .NSData에서는 description다르게 작동하기 때문입니다. 그래도 사용할 수 있습니다 debugDescription.

NSString * deviceTokenString = [[[[deviceToken debugDescription]
                     stringByReplacingOccurrencesOfString: @"<" withString: @""] 
                    stringByReplacingOccurrencesOfString: @">" withString: @""] 
                   stringByReplacingOccurrencesOfString: @" " withString: @""];

-7

데이터가 null로 끝나지 않는 한이 방법을 사용하십시오.

NSString* newStr = [[NSString alloc] initWithData:newDeviceToken encoding:NSUTF8StringEncoding];


나는 그것을 시도했지만 작동하지 않습니다. 내 코드 스 니펫에 주석 처리했습니다.
Sheehan Alam

@SheehanAlam이 사람은 그것을 통해 만들었습니다. 어떻게 문자열로 변환하는지 살펴보십시오. stackoverflow.com/questions/4994302/…
Naveed Ahmad

-9
NSString *tokenstring = [[NSString alloc] initWithData:token encoding:NSUTF8StringEncoding];

이것은 데이터가 문자열 일 때 작동하지만 deviceToken은 문자열이 아닙니다.
Simon Epskamp 11
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.