Skip to content
Open
1 change: 1 addition & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import PackageDescription

let package = Package(
name: "Yams",
platforms: [.iOS(.v13), .macOS(.v13), .tvOS(.v13), .watchOS(.v6)],
products: [
.library(name: "Yams", targets: ["Yams"])
],
Expand Down
1 change: 1 addition & 0 deletions Package@swift-6.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import PackageDescription

let package = Package(
name: "Yams",
platforms: [.iOS(.v13), .macOS(.v13), .tvOS(.v13), .watchOS(.v6)],
products: [
.library(name: "Yams", targets: ["Yams"])
],
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,11 @@ and a third one for a [Yams-native](#yamsnode) representation.
`Data`.

```swift
#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif
import Yams

struct S: Codable {
Expand Down Expand Up @@ -184,7 +188,11 @@ When Apple's Combine framework is available, `YAMLDecoder` conforms to the

```swift
import Combine
#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif
import Yams

func fetchBook(from url: URL) -> AnyPublisher<Book, Error> {
Expand Down
14 changes: 14 additions & 0 deletions Sources/Yams/Anchor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@
// Created by Adora Lynch on 8/9/24.
// Copyright (c) 2024 Yams. All rights reserved.

#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif

/// A representation of a YAML tag see: https://yaml.org/spec/1.2.2/
/// Types interested in Encoding and Decoding Anchors should
/// conform to YamlAnchorProviding and YamlAnchorCoding respectively.
public final class Anchor: RawRepresentable, ExpressibleByStringLiteral, Codable, Hashable {

#if !canImport(FoundationEssentials)
/// A CharacterSet containing only characters which are permitted by the underlying cyaml implementation
public static let permittedCharacters = CharacterSet.lowercaseLetters
.union(.uppercaseLetters)
Expand All @@ -22,6 +27,15 @@ public final class Anchor: RawRepresentable, ExpressibleByStringLiteral, Codable
public static func is_cyamlAlpha(_ string: String) -> Bool {
Anchor.permittedCharacters.isSuperset(of: .init(charactersIn: string))
}
#else
/// An Set containing only characters which are permitted by the underlying cyaml implementation
public static let permittedCharacters = Set( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_")

/// Returns true if and only if `string` contains only characters which are also in `permittedCharacters`
public static func is_cyamlAlpha(_ string: String) -> Bool {
Anchor.permittedCharacters.isSuperset(of: .init(string))
}
#endif

public let rawValue: String

Expand Down
57 changes: 31 additions & 26 deletions Sources/Yams/Constructor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
// Copyright (c) 2016 Yams. All rights reserved.
//

#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif

/// Constructors are used to translate `Node`s to Swift values.
public final class Constructor {
Expand Down Expand Up @@ -175,24 +179,19 @@
///
/// - returns: An instance of `Date`, if one was successfully extracted from the scalar.
public static func construct(from scalar: Node.Scalar) -> Date? {
let range = NSRange(location: 0, length: scalar.string.utf16.count)
guard let result = timestampPattern.firstMatch(in: scalar.string, options: [], range: range),
result.range.location != NSNotFound else {
guard let result = try! timestampPattern.firstMatch(in: scalar.string) else {

Check failure on line 182 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'firstMatch(in:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 182 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'firstMatch(in:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 182 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'firstMatch(in:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 182 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'firstMatch(in:)' is only available in application extensions for macOS 13.0 or newer
return nil
}
let components = (1..<result.numberOfRanges).map {
scalar.string.substring(with: result.range(at: $0))
}

var datecomponents = DateComponents()
datecomponents.calendar = gregorianCalendar
datecomponents.year = components[0].flatMap { Int($0) }
datecomponents.month = components[1].flatMap { Int($0) }
datecomponents.day = components[2].flatMap { Int($0) }
datecomponents.hour = components[3].flatMap { Int($0) }
datecomponents.minute = components[4].flatMap { Int($0) }
datecomponents.second = components[5].flatMap { Int($0) }
let nanoseconds: TimeInterval? = components[6].flatMap { fraction in
datecomponents.year = result["year"]?.substring.flatMap { Int($0) }

Check failure on line 188 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

getter for 'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 188 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 188 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

getter for 'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 188 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 188 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

getter for 'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 188 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 188 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

getter for 'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 188 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'subscript(_:)' is only available in application extensions for macOS 13.0 or newer
datecomponents.month = result["month"]?.substring.flatMap { Int($0) }

Check failure on line 189 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

getter for 'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 189 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 189 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

getter for 'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 189 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 189 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

getter for 'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 189 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 189 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

getter for 'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 189 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'subscript(_:)' is only available in application extensions for macOS 13.0 or newer
datecomponents.day = result["day"]?.substring.flatMap { Int($0) }

Check failure on line 190 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

getter for 'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 190 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 190 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

getter for 'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 190 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 190 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

getter for 'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 190 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 190 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

getter for 'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 190 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'subscript(_:)' is only available in application extensions for macOS 13.0 or newer
datecomponents.hour = result["hour"]?.substring.flatMap { Int($0) }

Check failure on line 191 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

getter for 'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 191 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 191 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

getter for 'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 191 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 191 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

getter for 'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 191 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 191 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

getter for 'subscript(_:)' is only available in application extensions for macOS 13.0 or newer

Check failure on line 191 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'subscript(_:)' is only available in application extensions for macOS 13.0 or newer
datecomponents.minute = result["minute"]?.substring.flatMap { Int($0) }
datecomponents.second = result["second"]?.substring.flatMap { Int($0) }
let nanoseconds: TimeInterval? = result["fraction"]?.substring.flatMap { fraction in
let length = fraction.count
let nanoseconds: Int?
if length < 9 {
Expand All @@ -206,13 +205,13 @@
}
datecomponents.timeZone = {
var seconds = 0
if let hourInSecond = components[9].flatMap({ Int($0) }).map({ $0 * 60 * 60 }) {
if let hourInSecond = result["tz_hour"]?.substring.flatMap({ Int($0) }).map({ $0 * 60 * 60 }) {
seconds += hourInSecond
}
if let minuteInSecond = components[10].flatMap({ Int($0) }).map({ $0 * 60 }) {
if let minuteInSecond = result["tz_minute"]?.substring.flatMap({ Int($0) }).map({ $0 * 60 }) {
seconds += minuteInSecond
}
if components[8] == "-" { // sign
if result["tz_sign"]?.substring == "-" { // sign
seconds *= -1
}
return TimeZone(secondsFromGMT: seconds)
Expand All @@ -222,17 +221,17 @@

private static let gregorianCalendar = Calendar(identifier: .gregorian)

private static let timestampPattern: NSRegularExpression = pattern([
"^([0-9][0-9][0-9][0-9])", // year
"-([0-9][0-9]?)", // month
"-([0-9][0-9]?)", // day
private static let timestampPattern: Regex<AnyRegexOutput> = pattern([

Check failure on line 224 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'Regex' is only available in application extensions for watchOS 9.0 or newer

Check failure on line 224 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'Regex' is only available in application extensions for macOS 13.0 or newer

Check failure on line 224 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'Regex' is only available in application extensions for macOS 13.0 or newer

Check failure on line 224 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'Regex' is only available in application extensions for macOS 13.0 or newer

Check failure on line 224 in Sources/Yams/Constructor.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'Regex' is only available in application extensions for macOS 13.0 or newer
"^(?<year>[0-9][0-9][0-9][0-9])", // year
"-(?<month>[0-9][0-9]?)", // month
"-(?<day>[0-9][0-9]?)", // day
"(?:(?:[Tt]|[ \\t]+)",
"([0-9][0-9]?)", // hour
":([0-9][0-9])", // minute
":([0-9][0-9])", // second
"(?:\\.([0-9]*))?", // fraction
"(?:[ \\t]*(Z|([-+])([0-9][0-9]?)", // tz_sign, tz_hour
"(?::([0-9][0-9]))?))?)?$" // tz_minute
"(?<hour>[0-9][0-9]?)", // hour
":(?<minute>[0-9][0-9])", // minute
":(?<second>[0-9][0-9])", // second
"(?:\\.(?<fraction>[0-9]*))?", // fraction
"(?:[ \\t]*(Z|(?<tz_sign>[-+])(?<tz_hour>[0-9][0-9]?)", // tz_sign, tz_hour
"(?::(?<tz_minute>[0-9][0-9]))?))?)?$" // tz_minute
].joined()
)
}
Expand Down Expand Up @@ -394,6 +393,12 @@

// MARK: - Types that can't conform to ScalarConstructible

#if !canImport(ObjectiveC) && canImport(FoundationEssentials)
public struct NSNull: Hashable {
public init() {}
}
#endif

extension NSNull/*: ScalarConstructible*/ {
/// Construct an instance of `NSNull`, if possible, from the specified scalar.
///
Expand Down
4 changes: 4 additions & 0 deletions Sources/Yams/Decoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
// Copyright (c) 2017 Yams. All rights reserved.
//

#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif

/// `Codable`-style `Decoder` that can be used to decode a `Decodable` type from a given `String` and optional
/// user info mapping. Similar to `Foundation.JSONDecoder`.
Expand Down
4 changes: 4 additions & 0 deletions Sources/Yams/Emitter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ internal import CYaml
@_implementationOnly import CYaml
#endif
#endif
#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif

/// Produce a YAML string from objects.
///
Expand Down
4 changes: 4 additions & 0 deletions Sources/Yams/Node.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
// Copyright (c) 2016 Yams. All rights reserved.
//

#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif

/// YAML Node.
public enum Node: Hashable {
Expand Down
4 changes: 4 additions & 0 deletions Sources/Yams/Parser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ internal import CYaml
@_implementationOnly import CYaml
#endif
#endif
#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif

/// Parse all YAML documents in a String
/// and produce corresponding Swift objects.
Expand Down
4 changes: 4 additions & 0 deletions Sources/Yams/Representer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
// Copyright (c) 2017 Yams. All rights reserved.
//

#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif

public extension Node {
/// Initialize a `Node` with a value of `NodeRepresentable`.
Expand Down
34 changes: 19 additions & 15 deletions Sources/Yams/Resolver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,21 @@
// Copyright (c) 2016 Yams. All rights reserved.
//

#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif

/// Class used to resolve nodes to tags based on customizable rules.
public final class Resolver: Sendable {
/// Rule describing how to resolve tags from regex patterns.
public struct Rule: Sendable {
/// The tag name this rule applies to.
public let tag: Tag.Name
fileprivate let regexp: NSRegularExpression
fileprivate let regexp: Regex<AnyRegexOutput>

Check failure on line 21 in Sources/Yams/Resolver.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'Regex' is only available in application extensions for watchOS 9.0 or newer
/// The regex pattern used to resolve this rule.
public var pattern: String { return regexp.pattern }
public let pattern: String

/// Create a rule with the specified tag name and regex pattern.
///
Expand All @@ -26,7 +30,8 @@
/// - throws: Throws an error if the regular expression pattern is invalid.
public init(_ tag: Tag.Name, _ pattern: String) throws {
self.tag = tag
self.regexp = try .init(pattern: pattern, options: [])
self.regexp = try .init(pattern)
self.pattern = pattern
}
}

Expand Down Expand Up @@ -85,7 +90,10 @@
}

func resolveTag(from string: String) -> Tag.Name {
for rule in rules where rule.regexp.matches(in: string) {
let rule = rules.first { rule in
try! rule.regexp.firstMatch(in: string) != nil
}
if let rule {
return rule.tag
}
return .str
Expand Down Expand Up @@ -156,20 +164,16 @@
// swiftlint:enable force_try
}

func pattern(_ string: String) -> NSRegularExpression {
func pattern(_ string: String) -> Regex<AnyRegexOutput> {

Check failure on line 167 in Sources/Yams/Resolver.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'Regex' is only available in application extensions for watchOS 9.0 or newer
do {
return try .init(pattern: string, options: [])
return try .init(string)
} catch {
fatalError("unreachable")
}
}

private extension NSRegularExpression {
func matches(in string: String) -> Bool {
let range = NSRange(location: 0, length: string.utf16.count)
if let match = firstMatch(in: string, options: [], range: range) {
return match.range.location != NSNotFound
}
return false
}
}
#if swift(>=6.0)
extension Regex: @retroactive @unchecked Sendable {}
#else
extension Regex: @unchecked Sendable {}

Check failure on line 178 in Sources/Yams/Resolver.swift

View workflow job for this annotation

GitHub Actions / macOS 13 with Xcode 14.3

'Regex' is only available in application extensions for watchOS 9.0 or newer
#endif
4 changes: 4 additions & 0 deletions Sources/Yams/String+Yams.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
// Copyright (c) 2016 Yams. All rights reserved.
//

#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif

extension String {
typealias LineNumberColumnAndContents = (lineNumber: Int, column: Int, contents: String)
Expand Down
4 changes: 4 additions & 0 deletions Sources/Yams/YamlError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ internal import CYaml
@_implementationOnly import CYaml
#endif
#endif
#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif

/// Errors thrown by Yams APIs.
public enum YamlError: Error {
Expand Down
4 changes: 4 additions & 0 deletions Tests/YamsTests/ConstructorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
// Copyright (c) 2016 Yams. All rights reserved.
//

#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif
import XCTest
import Yams

Expand Down
4 changes: 4 additions & 0 deletions Tests/YamsTests/EncoderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
// Copyright (c) 2017 Yams. All rights reserved.
//

#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif
import XCTest
import Yams

Expand Down
4 changes: 4 additions & 0 deletions Tests/YamsTests/NodeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
// Copyright (c) 2016 Yams. All rights reserved.
//

#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif
import XCTest
import Yams

Expand Down
4 changes: 4 additions & 0 deletions Tests/YamsTests/PerformanceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
// Copyright (c) 2016 Yams. All rights reserved.
//

#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif
import XCTest
import Yams

Expand Down
4 changes: 4 additions & 0 deletions Tests/YamsTests/RepresenterTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
// Copyright (c) 2017 Yams. All rights reserved.
//

#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif
import XCTest
import Yams

Expand Down
Loading
Loading