IOS-1455 sortedset and sorted set test IOS-1455
authorXavier Algarra <xavier@pep-project.org>
Tue, 19 Feb 2019 12:06:24 +0100
branchIOS-1455
changeset 7719dfaf8109cad7
parent 7714 3b863a450416
child 7720 911be7c30302
IOS-1455 sortedset and sorted set test
Submodules/Submodules/pEpIOSToolbox/pEpIOSToolbox/Other/Logger.swift
Submodules/pEpIOSToolbox/pEpIOSToolbox/Other/SortedSet.swift
pEpForiOS.xcodeproj/project.pbxproj
pEpForiOS.xcodeproj/xcshareddata/xcschemes/pEp.xcscheme
pEpForiOS/Util/SortedSet.swift
subModules/pEpIOSToolbox/pEpIOSToolbox.xcodeproj/project.pbxproj
subModules/pEpIOSToolbox/pEpIOSToolboxTests/SortedSetTest.swift
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/Submodules/Submodules/pEpIOSToolbox/pEpIOSToolbox/Other/Logger.swift	Tue Feb 19 12:06:24 2019 +0100
     1.3 @@ -0,0 +1,454 @@
     1.4 +//
     1.5 +//  Logger.swift
     1.6 +//  pEp
     1.7 +//
     1.8 +//  Created by Dirk Zimmermann on 18.12.18.
     1.9 +//  Copyright © 2018 p≡p Security S.A. All rights reserved.
    1.10 +//
    1.11 +
    1.12 +import Foundation
    1.13 +import os.log
    1.14 +import asl
    1.15 +
    1.16 +/**
    1.17 + Thin layer over `os_log` or `asl_logger` where not available.
    1.18 + The fallback to asl is only in effect for iOS 9, and currently
    1.19 + doesn't appear anywhere visible on that platform.
    1.20 + */
    1.21 +public class Logger {
    1.22 +    /**
    1.23 +     Map `os_log` levels.
    1.24 +     */
    1.25 +    public enum Severity {
    1.26 +        /**
    1.27 +         - Note: Not persisted by default, but will be written in case of errors.
    1.28 +         */
    1.29 +        case info
    1.30 +
    1.31 +        /**
    1.32 +         - Note: Not persisted by default, but will be written in case of errors.
    1.33 +         */
    1.34 +        case debug
    1.35 +
    1.36 +        /**
    1.37 +         This is the lowest priority that gets written to disk by default.
    1.38 +         Used like WARN in this logger.
    1.39 +         */
    1.40 +        case `default`
    1.41 +
    1.42 +        case error
    1.43 +
    1.44 +        /**
    1.45 +         - Note: As this is referring to inter-process problems, I don't see a use-case
    1.46 +         for iOS.
    1.47 +         */
    1.48 +        case fault
    1.49 +
    1.50 +        @available(iOS 10.0, macOS 10.12, tvOS 10.0, watchOS 3.0, *)
    1.51 +        public func osLogType() -> OSLogType {
    1.52 +            switch self {
    1.53 +            case .info:
    1.54 +                return .info
    1.55 +            case .debug:
    1.56 +                return .debug
    1.57 +            case .default:
    1.58 +                return .default
    1.59 +            case .error:
    1.60 +                return .error
    1.61 +            case .fault:
    1.62 +                return .fault
    1.63 +            }
    1.64 +        }
    1.65 +
    1.66 +        /**
    1.67 +         Maps the internal criticality of a log  message into a subsystem of ASL levels.
    1.68 +
    1.69 +         ASL has the following:
    1.70 +         * ASL_LEVEL_EMERG
    1.71 +         * ASL_LEVEL_ALERT
    1.72 +         * ASL_LEVEL_CRIT
    1.73 +         * ASL_LEVEL_ERR
    1.74 +         * ASL_LEVEL_WARNING
    1.75 +         * ASL_LEVEL_NOTICE
    1.76 +         * ASL_LEVEL_INFO
    1.77 +         * ASL_LEVEL_DEBUG
    1.78 +         */
    1.79 +        public func aslLevelString() -> String {
    1.80 +            switch self {
    1.81 +            case .default:
    1.82 +                return "ASL_LEVEL_NOTICE"
    1.83 +            case .info:
    1.84 +                return "ASL_LEVEL_INFO"
    1.85 +            case .debug:
    1.86 +                return "ASL_LEVEL_DEBUG"
    1.87 +            case .error:
    1.88 +                return "ASL_LEVEL_ERR"
    1.89 +            case .fault:
    1.90 +                return "ASL_LEVEL_CRIT"
    1.91 +            }
    1.92 +        }
    1.93 +    }
    1.94 +
    1.95 +    // move this loggers to the app
    1.96 +
    1.97 +    public static let frontendLogger = Logger(category: "frontend")
    1.98 +    public static let backendLogger = Logger(category: "backend")
    1.99 +    public static let utilLogger = Logger(category: "util")
   1.100 +    public static let htmlParsingLogger = Logger(category: "htmlParsing")
   1.101 +    public static let modelLogger = Logger(category: "model")
   1.102 +    public static let appDelegateLogger = Logger(category: "appDelegate")
   1.103 +
   1.104 +    public init(subsystem: String = "security.pEp.app.iOS", category: String) {
   1.105 +        self.subsystem = subsystem
   1.106 +        self.category = category
   1.107 +        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, watchOS 3.0, *) {
   1.108 +            osLogger = OSLog(subsystem: subsystem, category: category)
   1.109 +        } else {
   1.110 +            osLogger = nil
   1.111 +        }
   1.112 +    }
   1.113 +
   1.114 +    /**
   1.115 +     Logs to default.
   1.116 +     */
   1.117 +    public func log(function: String = #function,
   1.118 +                    filePath: String = #file,
   1.119 +                    fileLine: Int = #line,
   1.120 +                    _ message: StaticString,
   1.121 +                    _ args: CVarArg...) {
   1.122 +        saveLog(message: message,
   1.123 +                severity: .default,
   1.124 +                function: function,
   1.125 +                filePath: filePath,
   1.126 +                fileLine: fileLine,
   1.127 +                args: args)
   1.128 +    }
   1.129 +
   1.130 +    /**
   1.131 +     os_log doesn't have a warn per se, but default is coming close.
   1.132 +     This is the same as log.
   1.133 +     */
   1.134 +    public func warn(function: String = #function,
   1.135 +                     filePath: String = #file,
   1.136 +                     fileLine: Int = #line,
   1.137 +                     _ message: StaticString,
   1.138 +                     _ args: CVarArg...) {
   1.139 +        saveLog(message: message,
   1.140 +                severity: .default,
   1.141 +                function: function,
   1.142 +                filePath: filePath,
   1.143 +                fileLine: fileLine,
   1.144 +                args: args)
   1.145 +    }
   1.146 +
   1.147 +    /**
   1.148 +     Logs to info.
   1.149 +     */
   1.150 +    public func info(function: String = #function,
   1.151 +                     filePath: String = #file,
   1.152 +                     fileLine: Int = #line,
   1.153 +                     _ message: StaticString,
   1.154 +                     _ args: CVarArg...) {
   1.155 +        saveLog(message: message,
   1.156 +                severity: .info,
   1.157 +                function: function,
   1.158 +                filePath: filePath,
   1.159 +                fileLine: fileLine,
   1.160 +                args: args)
   1.161 +    }
   1.162 +
   1.163 +    /**
   1.164 +     Logs to debug.
   1.165 +     */
   1.166 +    public func debug(function: String = #function,
   1.167 +                      filePath: String = #file,
   1.168 +                      fileLine: Int = #line,
   1.169 +                      _ message: StaticString,
   1.170 +                      _ args: CVarArg...) {
   1.171 +        saveLog(message: message,
   1.172 +                severity: .debug,
   1.173 +                function: function,
   1.174 +                filePath: filePath,
   1.175 +                fileLine: fileLine,
   1.176 +                args: args)
   1.177 +    }
   1.178 +
   1.179 +    /**
   1.180 +     Logs to error.
   1.181 +     */
   1.182 +    public func error(function: String = #function,
   1.183 +                      filePath: String = #file,
   1.184 +                      fileLine: Int = #line,
   1.185 +                      _ message: StaticString,
   1.186 +                      _ args: CVarArg...) {
   1.187 +        saveLog(message: message,
   1.188 +                severity: .error,
   1.189 +                function: function,
   1.190 +                filePath: filePath,
   1.191 +                fileLine: fileLine,
   1.192 +                args: args)
   1.193 +    }
   1.194 +
   1.195 +    /**
   1.196 +     Logs to fault.
   1.197 +     */
   1.198 +    public func fault(function: String = #function,
   1.199 +                      filePath: String = #file,
   1.200 +                      fileLine: Int = #line,
   1.201 +                      _ message: StaticString,
   1.202 +                      _ args: CVarArg...) {
   1.203 +        saveLog(message: message,
   1.204 +                severity: .fault,
   1.205 +                function: function,
   1.206 +                filePath: filePath,
   1.207 +                fileLine: fileLine,
   1.208 +                args: args)
   1.209 +    }
   1.210 +
   1.211 +    public func errorAndCrash(function: String = #function,
   1.212 +                              filePath: String = #file,
   1.213 +                              fileLine: Int = #line,
   1.214 +                              _ message: StaticString,
   1.215 +                              _ args: CVarArg...) {
   1.216 +        saveLog(message: message,
   1.217 +                severity: .fault,
   1.218 +                function: function,
   1.219 +                filePath: filePath,
   1.220 +                fileLine: fileLine,
   1.221 +                args: args)
   1.222 +
   1.223 +        // This will omit the arguments, but it's still matchable
   1.224 +        SystemUtils.crash("\(message)")
   1.225 +    }
   1.226 +
   1.227 +    /**
   1.228 +     Logs an error.
   1.229 +     */
   1.230 +    public func log(function: String = #function,
   1.231 +                    filePath: String = #file,
   1.232 +                    fileLine: Int = #line,
   1.233 +                    error: Error) {
   1.234 +        // Error is not supported by "%@", because it doesn't conform to CVArg
   1.235 +        // and CVArg is only meant for internal types.
   1.236 +        // An alternative would be to use localizedDescription(),
   1.237 +        // but if they are indeed localized you end up with international
   1.238 +        // log messages.
   1.239 +        // So we wrap it into an NSError which does suppord CVArg.
   1.240 +        let nsErr = NSError(domain: subsystem, code: 0, userInfo: [NSUnderlyingErrorKey: error])
   1.241 +
   1.242 +        saveLog(message: "%{public}@",
   1.243 +                severity: .default,
   1.244 +                function: function,
   1.245 +                filePath: filePath,
   1.246 +                fileLine: fileLine,
   1.247 +                args: [nsErr])
   1.248 +    }
   1.249 +
   1.250 +    /**
   1.251 +     Testing only. If you want to test the fallback to ASL logging you may have to call
   1.252 +     this, as all the logging is deferred to a serial queue.
   1.253 +     */
   1.254 +    public func testFlush() {
   1.255 +        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, watchOS 3.0, *) {
   1.256 +            // no sense on these versions
   1.257 +        } else {
   1.258 +            aslLogQueue.sync {
   1.259 +                // nothing
   1.260 +            }
   1.261 +        }
   1.262 +    }
   1.263 +
   1.264 +    /**
   1.265 +     Since this kind of logging is used so often in the codebase, it has its
   1.266 +     own method.
   1.267 +     */
   1.268 +    public func lostMySelf() {
   1.269 +        errorAndCrash("Lost MySelf")
   1.270 +    }
   1.271 +
   1.272 +    private let subsystem: String
   1.273 +    private let category: String
   1.274 +
   1.275 +    private let osLogger: Any?
   1.276 +
   1.277 +    private func saveLog(message: StaticString,
   1.278 +                         severity: Severity,
   1.279 +                         function: String = #function,
   1.280 +                         filePath: String = #file,
   1.281 +                         fileLine: Int = #line,
   1.282 +                         args: [CVarArg]) {
   1.283 +        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, watchOS 3.0, *) {
   1.284 +            osLog(message: message,
   1.285 +                  severity: severity,
   1.286 +                  function: function,
   1.287 +                  filePath: filePath,
   1.288 +                  fileLine: fileLine,
   1.289 +                  args: args)
   1.290 +        } else {
   1.291 +            aslLog(message: message,
   1.292 +                   severity: severity,
   1.293 +                   function: function,
   1.294 +                   filePath: filePath,
   1.295 +                   fileLine: fileLine,
   1.296 +                   args: args)
   1.297 +        }
   1.298 +    }
   1.299 +
   1.300 +    /**
   1.301 +     - Note: If the number of arguments to the format string exceeds 10,
   1.302 +     the logging doesn't work correctly. Can be easily fixed though, if really needed.
   1.303 +     */
   1.304 +    @available(iOS 10.0, macOS 10.12, tvOS 10.0, watchOS 3.0, *)
   1.305 +    private func osLog(message: StaticString,
   1.306 +                       severity: Severity,
   1.307 +                       function: String = #function,
   1.308 +                       filePath: String = #file,
   1.309 +                       fileLine: Int = #line,
   1.310 +                       args: [CVarArg]) {
   1.311 +        let theLog = osLogger as! OSLog
   1.312 +        let theType = severity.osLogType()
   1.313 +
   1.314 +        // I haven't found a way of injecting `function` etc. into the original message for
   1.315 +        // just one call to `os_log`, so the 'position' is logged on a separate line.
   1.316 +        os_log("%@:%d %@:",
   1.317 +               log: theLog,
   1.318 +               type: theType,
   1.319 +               filePath,
   1.320 +               fileLine,
   1.321 +               function)
   1.322 +
   1.323 +        // We have to expand the array of arguments into positional ones.
   1.324 +        // There is no attempt of trying to format the string on our side
   1.325 +        // in order to make use of `os_log`'s fast 'offline' formatting
   1.326 +        // (that is, the work is delayed until actual log display).
   1.327 +        switch args.count {
   1.328 +        case 0:
   1.329 +            os_log(message,
   1.330 +                   log: theLog,
   1.331 +                   type: theType)
   1.332 +        case 1:
   1.333 +            os_log(message,
   1.334 +                   log: theLog,
   1.335 +                   type: theType,
   1.336 +                   args[0])
   1.337 +        case 2:
   1.338 +            os_log(message,
   1.339 +                   log: theLog,
   1.340 +                   type: theType,
   1.341 +                   args[0], args[1])
   1.342 +        case 3:
   1.343 +            os_log(message,
   1.344 +                   log: theLog,
   1.345 +                   type: theType,
   1.346 +                   args[0], args[1], args[2])
   1.347 +        case 4:
   1.348 +            os_log(message,
   1.349 +                   log: theLog,
   1.350 +                   type: theType,
   1.351 +                   args[0], args[1], args[2], args[3])
   1.352 +        case 5:
   1.353 +            os_log(message,
   1.354 +                   log: theLog,
   1.355 +                   type: theType,
   1.356 +                   args[0], args[1], args[2], args[3], args[4])
   1.357 +        case 6:
   1.358 +            os_log(message,
   1.359 +                   log: theLog,
   1.360 +                   type: theType,
   1.361 +                   args[0], args[1], args[2], args[3], args[4], args[5])
   1.362 +        case 7:
   1.363 +            os_log(message,
   1.364 +                   log: theLog,
   1.365 +                   type: theType,
   1.366 +                   args[0], args[1], args[2], args[3], args[4], args[5], args[6])
   1.367 +        case 8:
   1.368 +            os_log(message,
   1.369 +                   log: theLog,
   1.370 +                   type: theType,
   1.371 +                   args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7])
   1.372 +        case 9:
   1.373 +            os_log(message,
   1.374 +                   log: theLog,
   1.375 +                   type: theType,
   1.376 +                   args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7],
   1.377 +                   args[8])
   1.378 +        case 10:
   1.379 +            os_log(message,
   1.380 +                   log: theLog,
   1.381 +                   type: theType,
   1.382 +                   args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7],
   1.383 +                   args[8], args[9])
   1.384 +        default:
   1.385 +            os_log("Using more than 10 parameters",
   1.386 +                   log: theLog,
   1.387 +                   type: .error)
   1.388 +            os_log(message,
   1.389 +                   log: theLog,
   1.390 +                   type: theType,
   1.391 +                   args)
   1.392 +        }
   1.393 +    }
   1.394 +
   1.395 +    private func aslLog(message: StaticString,
   1.396 +                        severity: Severity,
   1.397 +                        function: String = #function,
   1.398 +                        filePath: String = #file,
   1.399 +                        fileLine: Int = #line,
   1.400 +                        args: [CVarArg]) {
   1.401 +        aslLogQueue.async { [weak self] in
   1.402 +            if let theSelf = self {
   1.403 +                let logMessage = asl_new(UInt32(ASL_TYPE_MSG))
   1.404 +
   1.405 +                theSelf.checkASLSuccess(asl_set(logMessage, ASL_KEY_SENDER, theSelf.subsystem))
   1.406 +
   1.407 +                theSelf.checkASLSuccess(asl_set(logMessage, ASL_KEY_FACILITY, theSelf.category))
   1.408 +
   1.409 +                theSelf.checkASLSuccess(asl_set(
   1.410 +                    logMessage,
   1.411 +                    ASL_KEY_MSG,
   1.412 +                    "\(filePath):\(fileLine) \(function): \(message) \(args)"))
   1.413 +
   1.414 +                theSelf.checkASLSuccess(asl_set(logMessage, ASL_KEY_LEVEL, "ASL_LEVEL_ERROR"))
   1.415 +
   1.416 +                let nowDate = Date()
   1.417 +                let dateString = "\(Int(nowDate.timeIntervalSince1970))"
   1.418 +                theSelf.checkASLSuccess(asl_set(logMessage, ASL_KEY_TIME, dateString))
   1.419 +
   1.420 +                theSelf.checkASLSuccess(asl_set(logMessage, ASL_KEY_READ_UID, "-1"))
   1.421 +
   1.422 +                theSelf.checkASLSuccess(asl_send(theSelf.consoleLogger(), logMessage))
   1.423 +
   1.424 +                asl_free(logMessage)
   1.425 +            }
   1.426 +        }
   1.427 +    }
   1.428 +
   1.429 +    private var consoleClient: aslclient?
   1.430 +
   1.431 +    private lazy var aslLogQueue = DispatchQueue(label: "security.pEp.asl.log")
   1.432 +
   1.433 +    private let sender = "security.pEp.app.iOS"
   1.434 +
   1.435 +    private func createConsoleLogger() -> asl_object_t {
   1.436 +        return asl_open(self.sender, subsystem, 0)
   1.437 +    }
   1.438 +
   1.439 +    private func consoleLogger() -> aslclient? {
   1.440 +        if consoleClient == nil {
   1.441 +            consoleClient = createConsoleLogger()
   1.442 +        }
   1.443 +        return consoleClient
   1.444 +    }
   1.445 +
   1.446 +    deinit {
   1.447 +        if consoleClient != nil {
   1.448 +            asl_free(consoleClient)
   1.449 +        }
   1.450 +    }
   1.451 +
   1.452 +    private func checkASLSuccess(_ result: Int32, comment: String = "no comment") {
   1.453 +        if result != 0 {
   1.454 +            print("*** error: \(comment)")
   1.455 +        }
   1.456 +    }
   1.457 +}
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/Submodules/pEpIOSToolbox/pEpIOSToolbox/Other/SortedSet.swift	Tue Feb 19 12:06:24 2019 +0100
     2.3 @@ -0,0 +1,219 @@
     2.4 +//
     2.5 +//  SortedSet.swift
     2.6 +//  pEp
     2.7 +//
     2.8 +//  Created by Andreas Buff on 02.10.17.
     2.9 +//  Copyright © 2017 p≡p Security S.A. All rights reserved.
    2.10 +//
    2.11 +
    2.12 +import UIKit
    2.13 +
    2.14 +/// Automatically keeps containted objects sorted to the criteria of a given sort block.
    2.15 +/// The implementation is completely trival and unperformant.
    2.16 +/// Has to be improved if this causes performance issue in the app.
    2.17 +public class SortedSet<T: Equatable>: Sequence {
    2.18 +    // MARK: - Public API
    2.19 +
    2.20 +    public typealias SortBlock = (_ first: T,_  second: T) -> ComparisonResult
    2.21 +
    2.22 +    public var count: Int {
    2.23 +        return set.count
    2.24 +    }
    2.25 +    
    2.26 +    public init(array: [T], sortBlock block: @escaping SortBlock) {
    2.27 +        set = NSMutableOrderedSet(array: array)
    2.28 +        sortBlock = block
    2.29 +        sort()
    2.30 +    }
    2.31 +    
    2.32 +    /// Inserts an object keeping the Set sorted. Returns the index it has been inserted to.
    2.33 +    ///
    2.34 +    /// - Parameter object: object to insert
    2.35 +    /// - Returns: index the object has been inserted to
    2.36 +    @discardableResult public func insert(object: T) -> Int {
    2.37 +        objc_sync_enter(self)
    2.38 +        defer { objc_sync_exit(self) }
    2.39 +
    2.40 +        let idx = indexOfObjectIfInserted(obj: object)
    2.41 +        set.insert(object, at: idx)
    2.42 +        return idx
    2.43 +    }
    2.44 +    
    2.45 +    public func remove(object: T) {
    2.46 +        objc_sync_enter(self)
    2.47 +        defer { objc_sync_exit(self) }
    2.48 +
    2.49 +        set.remove(object)
    2.50 +    }
    2.51 +    
    2.52 +    public func removeObject(at index: Int) {
    2.53 +        objc_sync_enter(self)
    2.54 +        defer { objc_sync_exit(self) }
    2.55 +
    2.56 +        guard isValidIndex(index) else {
    2.57 +            Logger.frontendLogger.errorAndCrash("Index out of range")
    2.58 +            return
    2.59 +        }
    2.60 +        set.removeObject(at: index)
    2.61 +    }
    2.62 +    
    2.63 +    public func replaceObject(at index: Int, with object: T) {
    2.64 +        objc_sync_enter(self)
    2.65 +        defer { objc_sync_exit(self) }
    2.66 +
    2.67 +        guard isValidIndex(index) else {
    2.68 +            Logger.frontendLogger.errorAndCrash("Index out of range")
    2.69 +            return
    2.70 +        }
    2.71 +        set.replaceObject(at: index, with: object)
    2.72 +    }
    2.73 +
    2.74 +    public func object(at index: Int) -> T? {
    2.75 +        objc_sync_enter(self)
    2.76 +        defer { objc_sync_exit(self) }
    2.77 +
    2.78 +        guard isValidIndex(index) else {
    2.79 +            Logger.frontendLogger.errorAndCrash("Index out of range")
    2.80 +            return nil
    2.81 +        }
    2.82 +
    2.83 +        return set.object(at: index) as? T
    2.84 +    }
    2.85 +
    2.86 +    /**
    2.87 +     - Returns: The index of `object` or nil.
    2.88 +     */
    2.89 +    public func index(of object: T) -> Int? {
    2.90 +        let idx = indexOrNotFound(of: object)
    2.91 +        if idx != NSNotFound {
    2.92 +            return idx
    2.93 +        } else {
    2.94 +            return nil
    2.95 +        }
    2.96 +    }
    2.97 +
    2.98 +    /**
    2.99 +     - Returns: The index of `object` or NSNotFound.
   2.100 +     */
   2.101 +    public func indexOrNotFound(of object: T) -> Int {
   2.102 +        objc_sync_enter(self)
   2.103 +        defer { objc_sync_exit(self) }
   2.104 +
   2.105 +        for i in 0..<set.count {
   2.106 +            guard let testee = set.object(at: i) as? T else {
   2.107 +                Logger.frontendLogger.errorAndCrash("error casting")
   2.108 +                return NSNotFound
   2.109 +            }
   2.110 +            if testee == object {
   2.111 +                return i
   2.112 +            }
   2.113 +        }
   2.114 +        return NSNotFound
   2.115 +    }
   2.116 +    
   2.117 +    public func removeAllObjects() {
   2.118 +        objc_sync_enter(self)
   2.119 +        defer { objc_sync_exit(self) }
   2.120 +        set.removeAllObjects()
   2.121 +    }
   2.122 +
   2.123 +    // MARK: - Array Support
   2.124 +
   2.125 +    public func array() -> [T] {
   2.126 +        objc_sync_enter(self)
   2.127 +        defer { objc_sync_exit(self) }
   2.128 +
   2.129 +        if let theArray = set.array as? [T] {
   2.130 +            return theArray
   2.131 +        } else {
   2.132 +            return []
   2.133 +        }
   2.134 +    }
   2.135 +
   2.136 +    public subscript(safe index: Int) -> T? {
   2.137 +        objc_sync_enter(self)
   2.138 +        defer { objc_sync_exit(self) }
   2.139 +
   2.140 +        if index >= set.count {
   2.141 +            return nil
   2.142 +        }
   2.143 +
   2.144 +        if let obj = set.object(at: index) as? T {
   2.145 +            return obj
   2.146 +        } else {
   2.147 +            return nil
   2.148 +        }
   2.149 +    }
   2.150 +
   2.151 +    // MARK: - Sequence
   2.152 +
   2.153 +    public typealias Iterator = SortedSetIterator<T>
   2.154 +
   2.155 +    public func makeIterator() -> SortedSet<T>.SortedSetIterator<T> {
   2.156 +        return SortedSetIterator.init(elements: set.array as! [T])
   2.157 +    }
   2.158 +
   2.159 +    // MARK: - Iterator
   2.160 +
   2.161 +    public struct SortedSetIterator<T>: IteratorProtocol {
   2.162 +        public typealias Element = T
   2.163 +
   2.164 +        private let elements: [T]
   2.165 +        private var index = 0
   2.166 +        private let maxIndex: Int
   2.167 +
   2.168 +        public init(elements: [T]) {
   2.169 +            self.elements = elements
   2.170 +            maxIndex = elements.count - 1
   2.171 +        }
   2.172 +
   2.173 +        public mutating func next() -> SortedSetIterator.Element? {
   2.174 +            if index > maxIndex {
   2.175 +                return nil
   2.176 +            } else {
   2.177 +                let e = elements[index]
   2.178 +                index += 1
   2.179 +                return e
   2.180 +            }
   2.181 +        }
   2.182 +    }
   2.183 +
   2.184 +    // MARK: -
   2.185 +    
   2.186 +    private var set = NSMutableOrderedSet()
   2.187 +    private var sortBlock: SortBlock
   2.188 +
   2.189 +    private func sort()  {
   2.190 +        set.sort { (first: Any, second: Any) -> ComparisonResult in
   2.191 +            guard let firstT = first as? T,
   2.192 +                let secondT = second as? T else {
   2.193 +                    Logger.frontendLogger.errorAndCrash("Error casting.")
   2.194 +                    return .orderedSame
   2.195 +            }
   2.196 +            return sortBlock(firstT, secondT)
   2.197 +        }
   2.198 +    }
   2.199 +    
   2.200 +    private func indexOfObjectIfInserted(obj: T) -> Int {
   2.201 +        for i in 0..<set.count {
   2.202 +            guard let testee = set.object(at: i) as? T else {
   2.203 +                Logger.frontendLogger.errorAndCrash("Error casing")
   2.204 +                return 0
   2.205 +            }
   2.206 +            if set.count == 0 {
   2.207 +                //set is empty
   2.208 +                return 0
   2.209 +            }
   2.210 +            if sortBlock(obj, testee) == .orderedAscending {
   2.211 +                // following object found
   2.212 +                return i
   2.213 +            }
   2.214 +        }
   2.215 +        // we would insert as the last object
   2.216 +        return Swift.max(0, set.count)
   2.217 +    }
   2.218 +
   2.219 +    private func isValidIndex(_ idx: Int) -> Bool {
   2.220 +        return idx >= 0 && idx < set.count
   2.221 +    }
   2.222 +}
     3.1 --- a/pEpForiOS.xcodeproj/project.pbxproj	Mon Feb 18 16:55:14 2019 +0100
     3.2 +++ b/pEpForiOS.xcodeproj/project.pbxproj	Tue Feb 19 12:06:24 2019 +0100
     3.3 @@ -532,12 +532,12 @@
     3.4  		B74F81021EB0E20000519FCC /* LoginViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B74F81011EB0E20000519FCC /* LoginViewModel.swift */; };
     3.5  		B75FF00B1EFD420F00C57289 /* EmailListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B75FF00A1EFD420F00C57289 /* EmailListViewModel.swift */; };
     3.6  		B76CF8B320D2739B002429A8 /* MoveToFolderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B76CF8B220D2739B002429A8 /* MoveToFolderViewModel.swift */; };
     3.7 +		B7745839221C191600664282 /* SecretUITestData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7745838221C191600664282 /* SecretUITestData.swift */; };
     3.8  		B78309C81EAA09040051A2E0 /* AccountCreation.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B78309C61EAA09040051A2E0 /* AccountCreation.storyboard */; };
     3.9  		B78CF8251E76D706008C1739 /* FilterTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B78CF8241E76D706008C1739 /* FilterTableViewController.swift */; };
    3.10  		B78CF8291E76E0F1008C1739 /* FilterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B78CF8281E76E0F1008C1739 /* FilterViewModel.swift */; };
    3.11  		B78CF82B1E76E146008C1739 /* FilterCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B78CF82A1E76E146008C1739 /* FilterCellViewModel.swift */; };
    3.12  		B7D1EEC81E8BEC8D00F190E3 /* CollapsibleTableViewHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7D1EEC71E8BEC8D00F190E3 /* CollapsibleTableViewHeader.swift */; };
    3.13 -		B7DB7FB522148585003968DA /* SecretUITestData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7DB7FB422148585003968DA /* SecretUITestData.swift */; };
    3.14  		B7DB7FC42215C4FF003968DA /* UINavigationController+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7DB7FC32215C4FF003968DA /* UINavigationController+Extensions.swift */; };
    3.15  		B7DB7FC72215C57F003968DA /* UIView+Autolayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7DB7FC52215C57F003968DA /* UIView+Autolayout.swift */; };
    3.16  		B7DB7FC82215C57F003968DA /* UIView+Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7DB7FC62215C57F003968DA /* UIView+Util.swift */; };
    3.17 @@ -1154,12 +1154,12 @@
    3.18  		B74F81011EB0E20000519FCC /* LoginViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginViewModel.swift; sourceTree = "<group>"; };
    3.19  		B75FF00A1EFD420F00C57289 /* EmailListViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmailListViewModel.swift; sourceTree = "<group>"; };
    3.20  		B76CF8B220D2739B002429A8 /* MoveToFolderViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoveToFolderViewModel.swift; sourceTree = "<group>"; };
    3.21 +		B7745838221C191600664282 /* SecretUITestData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretUITestData.swift; sourceTree = "<group>"; };
    3.22  		B78309C71EAA09040051A2E0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/AccountCreation.storyboard; sourceTree = "<group>"; };
    3.23  		B78CF8241E76D706008C1739 /* FilterTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FilterTableViewController.swift; path = Filter/FilterTableViewController.swift; sourceTree = "<group>"; };
    3.24  		B78CF8281E76E0F1008C1739 /* FilterViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FilterViewModel.swift; path = Filter/ViewModel/FilterViewModel.swift; sourceTree = "<group>"; };
    3.25  		B78CF82A1E76E146008C1739 /* FilterCellViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FilterCellViewModel.swift; path = Filter/ViewModel/FilterCellViewModel.swift; sourceTree = "<group>"; };
    3.26  		B7D1EEC71E8BEC8D00F190E3 /* CollapsibleTableViewHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CollapsibleTableViewHeader.swift; path = Folder/CollapsibleTableViewHeader.swift; sourceTree = "<group>"; };
    3.27 -		B7DB7FB422148585003968DA /* SecretUITestData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretUITestData.swift; sourceTree = "<group>"; };
    3.28  		B7DB7FC32215C4FF003968DA /* UINavigationController+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UINavigationController+Extensions.swift"; sourceTree = "<group>"; };
    3.29  		B7DB7FC52215C57F003968DA /* UIView+Autolayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Autolayout.swift"; sourceTree = "<group>"; };
    3.30  		B7DB7FC62215C57F003968DA /* UIView+Util.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Util.swift"; sourceTree = "<group>"; };
    3.31 @@ -2244,13 +2244,13 @@
    3.32  		43980E481CBD0BCA00A7FC3C /* pEpForiOSUITests */ = {
    3.33  			isa = PBXGroup;
    3.34  			children = (
    3.35 +				B7745838221C191600664282 /* SecretUITestData.swift */,
    3.36  				43B0443A20067D25007BCE3F /* UITestDataProtocol.swift */,
    3.37  				43B0443820067CC7007BCE3F /* UIAccount.swift */,
    3.38  				43980E4B1CBD0BCA00A7FC3C /* Info.plist */,
    3.39  				43DA52671CEF1B4F0023D540 /* NewAccountSetupUITest.swift */,
    3.40  				431E65621EEAE65200B8BBFC /* HandshakeUITest.swift */,
    3.41  				434C051A20F8BAB6009B271D /* XCUIElement+Extension.swift */,
    3.42 -				B7DB7FB422148585003968DA /* SecretUITestData.swift */,
    3.43  			);
    3.44  			path = pEpForiOSUITests;
    3.45  			sourceTree = "<group>";
    3.46 @@ -3654,7 +3654,7 @@
    3.47  				434C051B20F8BAB6009B271D /* XCUIElement+Extension.swift in Sources */,
    3.48  				431E65631EEAE65200B8BBFC /* HandshakeUITest.swift in Sources */,
    3.49  				43B0443B20067D25007BCE3F /* UITestDataProtocol.swift in Sources */,
    3.50 -				B7DB7FB522148585003968DA /* SecretUITestData.swift in Sources */,
    3.51 +				B7745839221C191600664282 /* SecretUITestData.swift in Sources */,
    3.52  			);
    3.53  			runOnlyForDeploymentPostprocessing = 0;
    3.54  		};
     4.1 --- a/pEpForiOS.xcodeproj/xcshareddata/xcschemes/pEp.xcscheme	Mon Feb 18 16:55:14 2019 +0100
     4.2 +++ b/pEpForiOS.xcodeproj/xcshareddata/xcschemes/pEp.xcscheme	Tue Feb 19 12:06:24 2019 +0100
     4.3 @@ -223,6 +223,16 @@
     4.4                 ReferencedContainer = "container:pEpForiOS.xcodeproj">
     4.5              </BuildableReference>
     4.6           </TestableReference>
     4.7 +         <TestableReference
     4.8 +            skipped = "NO">
     4.9 +            <BuildableReference
    4.10 +               BuildableIdentifier = "primary"
    4.11 +               BlueprintIdentifier = "B7DB7F56221315BD003968DA"
    4.12 +               BuildableName = "pEpIOSToolboxTests.xctest"
    4.13 +               BlueprintName = "pEpIOSToolboxTests"
    4.14 +               ReferencedContainer = "container:subModules/pEpIOSToolbox/pEpIOSToolbox.xcodeproj">
    4.15 +            </BuildableReference>
    4.16 +         </TestableReference>
    4.17        </Testables>
    4.18        <MacroExpansion>
    4.19           <BuildableReference
     5.1 --- a/pEpForiOS/Util/SortedSet.swift	Mon Feb 18 16:55:14 2019 +0100
     5.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.3 @@ -1,219 +0,0 @@
     5.4 -//
     5.5 -//  SortedSet.swift
     5.6 -//  pEp
     5.7 -//
     5.8 -//  Created by Andreas Buff on 02.10.17.
     5.9 -//  Copyright © 2017 p≡p Security S.A. All rights reserved.
    5.10 -//
    5.11 -
    5.12 -import UIKit
    5.13 -
    5.14 -/// Automatically keeps containted objects sorted to the criteria of a given sort block.
    5.15 -/// The implementation is completely trival and unperformant.
    5.16 -/// Has to be improved if this causes performance issue in the app.
    5.17 -public class SortedSet<T: Equatable>: Sequence {
    5.18 -    // MARK: - Public API
    5.19 -
    5.20 -    public typealias SortBlock = (_ first: T,_  second: T) -> ComparisonResult
    5.21 -
    5.22 -    public var count: Int {
    5.23 -        return set.count
    5.24 -    }
    5.25 -    
    5.26 -    public init(array: [T], sortBlock block: @escaping SortBlock) {
    5.27 -        set = NSMutableOrderedSet(array: array)
    5.28 -        sortBlock = block
    5.29 -        sort()
    5.30 -    }
    5.31 -    
    5.32 -    /// Inserts an object keeping the Set sorted. Returns the index it has been inserted to.
    5.33 -    ///
    5.34 -    /// - Parameter object: object to insert
    5.35 -    /// - Returns: index the object has been inserted to
    5.36 -    @discardableResult public func insert(object: T) -> Int {
    5.37 -        objc_sync_enter(self)
    5.38 -        defer { objc_sync_exit(self) }
    5.39 -
    5.40 -        let idx = indexOfObjectIfInserted(obj: object)
    5.41 -        set.insert(object, at: idx)
    5.42 -        return idx
    5.43 -    }
    5.44 -    
    5.45 -    public func remove(object: T) {
    5.46 -        objc_sync_enter(self)
    5.47 -        defer { objc_sync_exit(self) }
    5.48 -
    5.49 -        set.remove(object)
    5.50 -    }
    5.51 -    
    5.52 -    public func removeObject(at index: Int) {
    5.53 -        objc_sync_enter(self)
    5.54 -        defer { objc_sync_exit(self) }
    5.55 -
    5.56 -        guard isValidIndex(index) else {
    5.57 -            Logger.frontendLogger.errorAndCrash("Index out of range")
    5.58 -            return
    5.59 -        }
    5.60 -        set.removeObject(at: index)
    5.61 -    }
    5.62 -    
    5.63 -    public func replaceObject(at index: Int, with object: T) {
    5.64 -        objc_sync_enter(self)
    5.65 -        defer { objc_sync_exit(self) }
    5.66 -
    5.67 -        guard isValidIndex(index) else {
    5.68 -            Logger.frontendLogger.errorAndCrash("Index out of range")
    5.69 -            return
    5.70 -        }
    5.71 -        set.replaceObject(at: index, with: object)
    5.72 -    }
    5.73 -
    5.74 -    public func object(at index: Int) -> T? {
    5.75 -        objc_sync_enter(self)
    5.76 -        defer { objc_sync_exit(self) }
    5.77 -
    5.78 -        guard isValidIndex(index) else {
    5.79 -            Logger.frontendLogger.errorAndCrash("Index out of range")
    5.80 -            return nil
    5.81 -        }
    5.82 -
    5.83 -        return set.object(at: index) as? T
    5.84 -    }
    5.85 -
    5.86 -    /**
    5.87 -     - Returns: The index of `object` or nil.
    5.88 -     */
    5.89 -    public func index(of object: T) -> Int? {
    5.90 -        let idx = indexOrNotFound(of: object)
    5.91 -        if idx != NSNotFound {
    5.92 -            return idx
    5.93 -        } else {
    5.94 -            return nil
    5.95 -        }
    5.96 -    }
    5.97 -
    5.98 -    /**
    5.99 -     - Returns: The index of `object` or NSNotFound.
   5.100 -     */
   5.101 -    public func indexOrNotFound(of object: T) -> Int {
   5.102 -        objc_sync_enter(self)
   5.103 -        defer { objc_sync_exit(self) }
   5.104 -
   5.105 -        for i in 0..<set.count {
   5.106 -            guard let testee = set.object(at: i) as? T else {
   5.107 -                Logger.frontendLogger.errorAndCrash("error casting")
   5.108 -                return NSNotFound
   5.109 -            }
   5.110 -            if testee == object {
   5.111 -                return i
   5.112 -            }
   5.113 -        }
   5.114 -        return NSNotFound
   5.115 -    }
   5.116 -    
   5.117 -    public func removeAllObjects() {
   5.118 -        objc_sync_enter(self)
   5.119 -        defer { objc_sync_exit(self) }
   5.120 -        set.removeAllObjects()
   5.121 -    }
   5.122 -
   5.123 -    // MARK: - Array Support
   5.124 -
   5.125 -    public func array() -> [T] {
   5.126 -        objc_sync_enter(self)
   5.127 -        defer { objc_sync_exit(self) }
   5.128 -
   5.129 -        if let theArray = set.array as? [T] {
   5.130 -            return theArray
   5.131 -        } else {
   5.132 -            return []
   5.133 -        }
   5.134 -    }
   5.135 -
   5.136 -    public subscript(safe index: Int) -> T? {
   5.137 -        objc_sync_enter(self)
   5.138 -        defer { objc_sync_exit(self) }
   5.139 -
   5.140 -        if index >= set.count {
   5.141 -            return nil
   5.142 -        }
   5.143 -
   5.144 -        if let obj = set.object(at: index) as? T {
   5.145 -            return obj
   5.146 -        } else {
   5.147 -            return nil
   5.148 -        }
   5.149 -    }
   5.150 -
   5.151 -    // MARK: - Sequence
   5.152 -
   5.153 -    public typealias Iterator = SortedSetIterator<T>
   5.154 -
   5.155 -    public func makeIterator() -> SortedSet<T>.SortedSetIterator<T> {
   5.156 -        return SortedSetIterator.init(elements: set.array as! [T])
   5.157 -    }
   5.158 -
   5.159 -    // MARK: - Iterator
   5.160 -
   5.161 -    public struct SortedSetIterator<T>: IteratorProtocol {
   5.162 -        public typealias Element = T
   5.163 -
   5.164 -        private let elements: [T]
   5.165 -        private var index = 0
   5.166 -        private let maxIndex: Int
   5.167 -
   5.168 -        public init(elements: [T]) {
   5.169 -            self.elements = elements
   5.170 -            maxIndex = elements.count - 1
   5.171 -        }
   5.172 -
   5.173 -        public mutating func next() -> SortedSetIterator.Element? {
   5.174 -            if index > maxIndex {
   5.175 -                return nil
   5.176 -            } else {
   5.177 -                let e = elements[index]
   5.178 -                index += 1
   5.179 -                return e
   5.180 -            }
   5.181 -        }
   5.182 -    }
   5.183 -
   5.184 -    // MARK: -
   5.185 -    
   5.186 -    private var set = NSMutableOrderedSet()
   5.187 -    private var sortBlock: SortBlock
   5.188 -
   5.189 -    private func sort()  {
   5.190 -        set.sort { (first: Any, second: Any) -> ComparisonResult in
   5.191 -            guard let firstT = first as? T,
   5.192 -                let secondT = second as? T else {
   5.193 -                    Logger.frontendLogger.errorAndCrash("Error casting.")
   5.194 -                    return .orderedSame
   5.195 -            }
   5.196 -            return sortBlock(firstT, secondT)
   5.197 -        }
   5.198 -    }
   5.199 -    
   5.200 -    private func indexOfObjectIfInserted(obj: T) -> Int {
   5.201 -        for i in 0..<set.count {
   5.202 -            guard let testee = set.object(at: i) as? T else {
   5.203 -                Logger.frontendLogger.errorAndCrash("Error casing")
   5.204 -                return 0
   5.205 -            }
   5.206 -            if set.count == 0 {
   5.207 -                //set is empty
   5.208 -                return 0
   5.209 -            }
   5.210 -            if sortBlock(obj, testee) == .orderedAscending {
   5.211 -                // following object found
   5.212 -                return i
   5.213 -            }
   5.214 -        }
   5.215 -        // we would insert as the last object
   5.216 -        return Swift.max(0, set.count)
   5.217 -    }
   5.218 -
   5.219 -    private func isValidIndex(_ idx: Int) -> Bool {
   5.220 -        return idx >= 0 && idx < set.count
   5.221 -    }
   5.222 -}
     6.1 --- a/subModules/pEpIOSToolbox/pEpIOSToolbox.xcodeproj/project.pbxproj	Mon Feb 18 16:55:14 2019 +0100
     6.2 +++ b/subModules/pEpIOSToolbox/pEpIOSToolbox.xcodeproj/project.pbxproj	Tue Feb 19 12:06:24 2019 +0100
     6.3 @@ -73,7 +73,7 @@
     6.4  		B7A46C5D220DBAF00027CCB5 /* OperationQueue+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "OperationQueue+Extension.swift"; sourceTree = "<group>"; };
     6.5  		B7A46C61220DCEA80027CCB5 /* NSAttributedString+Parsing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+Parsing.swift"; sourceTree = "<group>"; };
     6.6  		B7DB7F4F22130DE9003968DA /* Weak.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Weak.swift; sourceTree = "<group>"; };
     6.7 -		B7DB7F512213120B003968DA /* SortedSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SortedSet.swift; path = ../../../../pEpForiOS/Util/SortedSet.swift; sourceTree = "<group>"; };
     6.8 +		B7DB7F512213120B003968DA /* SortedSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SortedSet.swift; sourceTree = "<group>"; };
     6.9  		B7DB7F57221315BD003968DA /* pEpIOSToolboxTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = pEpIOSToolboxTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
    6.10  		B7DB7F5B221315BD003968DA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
    6.11  		B7DB7F8322144E4E003968DA /* SortedSetTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SortedSetTest.swift; sourceTree = "<group>"; };
    6.12 @@ -115,7 +115,6 @@
    6.13  				B7DB7F4F22130DE9003968DA /* Weak.swift */,
    6.14  				B7A46C5D220DBAF00027CCB5 /* OperationQueue+Extension.swift */,
    6.15  				B7465DBD22119D39008A1708 /* Thread+Extension.swift */,
    6.16 -				B7DB7F512213120B003968DA /* SortedSet.swift */,
    6.17  				B7465DC522119EB1008A1708 /* Array+SortingAndSearching.swift */,
    6.18  			);
    6.19  			path = Foundation;
    6.20 @@ -178,6 +177,7 @@
    6.21  				B70A3A75220091D400EDCE61 /* Logger.swift */,
    6.22  				B75390852212E20500B1FCF9 /* Collection+Extensions.swift */,
    6.23  				B7465DCB2211BEE9008A1708 /* Tuple.swift */,
    6.24 +				B7DB7F512213120B003968DA /* SortedSet.swift */,
    6.25  			);
    6.26  			path = Other;
    6.27  			sourceTree = "<group>";
     7.1 --- a/subModules/pEpIOSToolbox/pEpIOSToolboxTests/SortedSetTest.swift	Mon Feb 18 16:55:14 2019 +0100
     7.2 +++ b/subModules/pEpIOSToolbox/pEpIOSToolboxTests/SortedSetTest.swift	Tue Feb 19 12:06:24 2019 +0100
     7.3 @@ -8,8 +8,6 @@
     7.4  
     7.5  import XCTest
     7.6  
     7.7 -@testable import pEpForiOS
     7.8 -
     7.9  
    7.10  struct TestObject: Equatable {
    7.11      let date: Date