   var kCGDisplayPixelsWide = 3840;
   var kCGDisplayResolution = 1;
   var kCGDisplayVerticalResolution = 163;
+  var frequency:Int?
 }
 // use the object as key in a later process of mode filtering/winnowing
-extension CGDisplayModeFromJSON: Hashable & Equatable {
+extension CGDisplayModeFromJSON: Hashable & Equatable & Comparable {
+  enum StringOrDouble: Decodable {
+    case double(Double)//,string(String)
+    
+    init(from decoder: Decoder) throws {
+      // RefreshRate is a String with quotation marks but representing a Double
+      if let string = try? decoder.singleValueContainer().decode(String.self) {
+        self = .double(Double(string) ?? 0)
+        return
+      }
+      // RefreshRate is 0 without quotation marks, and will decode into a Double
+      if let double = try? decoder.singleValueContainer().decode(Double.self) {
+        self = .double(double)
+        return
+      }
+      throw Error.couldNotFindStringOrDouble
+    }
+    enum Error: Swift.Error {
+      case couldNotFindStringOrDouble
+    }
+  }
+
   func hash(into hasher: inout Hasher) {
     hasher.combine(Width)
     hasher.combine(Height)
     hasher.combine(kCGDisplayPixelsWide)
     hasher.combine(kCGDisplayPixelsHigh)
   }
+  func debug() -> String {
+    return "s:\(self["scale"]),w:\(self.Width),h:\(self.Height)"
+  }
   static func == (lhs: Self, rhs: Self) -> Bool {
     return lhs.Width == rhs.Width && lhs.kCGDisplayPixelsWide == rhs.kCGDisplayPixelsWide &&
           lhs.Height == rhs.Height && lhs.kCGDisplayPixelsHigh == rhs.kCGDisplayPixelsHigh
+  }
+  static func ~=(lhs: Self, rhs: Self) -> Bool {
+    return lhs == rhs && lhs["frequency"] == rhs["frequency"] && 
+      lhs["kCGDisplayHorizontalResolution"] == rhs["kCGDisplayHorizontalResolution"]
+  }
+
+  static func < (lhs: Self, rhs: Self) -> Bool {
+    let ls = lhs["scale"]
+    let rs = rhs["scale"]
+    return ls != rs ? ls < rs : lhs.Width < rhs.Width
   }
 
   // for property loop in mode filtering

        case "DepthFormat": return self.DepthFormat
        case "BitsPerSample": return self.BitsPerSample
        case "scale":  return self.kCGDisplayPixelsWide / self.Width
        case "frequency": 
          switch self.RefreshRate {
          case StringOrDouble.string(let s):
              return Int( Double(s)?.rounded() ?? 0)
          case StringOrDouble.double(let d):
            return Int( d.rounded() )
          }
        default: return 0
      }
    }
  }

  // this is a hack to read private members in CGDisplayMode
  static func decode(from modes:[CGDisplayMode]) -> [CGDisplayModeFromJSON]? {
    do {
      // first we operate the string to make it look like JSON String
      let jsonStyleModes = try CGDisplayModeFromJSON.replaces(in: "\(modes)", replacement: self.replacement)

      // then we try to decode it as JSON
      let decoder = JSONDecoder()
      let modesObject = try decoder.decode([CGDisplayModeFromJSON].self, from: jsonStyleModes.data(using: .utf8)!)

      // preliminary integrity check
      guard modesObject.count == modes.count else { return nil }

    if rhs.scale != nil { bool = bool && rhs.scale == lhs.scale }
    return bool
  }

}


// DisplayMode & DisplayID management center
class DisplayManager {
