Giter Site home page Giter Site logo

gottagetswifty / codablewrappers Goto Github PK

View Code? Open in Web Editor NEW
567.0 12.0 36.0 224 KB

A Collection of PropertyWrappers to make custom Serialization of Swift Codable Types easy

License: Apache License 2.0

Swift 99.42% Dockerfile 0.06% Ruby 0.52%
swift ios property-wrappers swift5-1 codable swift-package-manager

codablewrappers's Introduction

CodableWrappers

Simplified Serialization with Property Wrappers

Move your Codable and (En/De)coder customization to annotations!

struct YourType: Codable {
    @MillisecondsSince1970DateCoding
    var millisecondsDate: Date
    @Base64Coding
    var someData: Data
    @OmitCoding
    var temporaryProperty
}

2.0's released! Release Notes


Installation

Swift Package Manager *Preferred*

URL:

https://github.com/GottaGetSwifty/CodableWrappers.git

Manifest:

dependencies: [
    .package(url: "https://github.com/GottaGetSwifty/CodableWrappers.git", .upToNextMajor(from: "2.0.0" )),
]

CocoaPods

pod 'CodableWrappers', '~> 2.0.0'

Info

Available Property Wrappers

Other Customization

Additional Links


Advantages

  • Declarative
  • Extendable
  • Declare once for all Encoders and Decoders. (e.g. JSONEncoder and PropertyListEncoder)
  • Custom (de/en)coding without overriding encode(to: Encoder) or init(with decoder) for your whole Type
  • Varied (de/en)coding strategies allowed
  • Cross Platform

Compatibility

2.x has a Swift 5.2 as it's minimum. 5.1 is available on 1.x


@EncodeNulls

For a Property that should encode null for nil values

struct MyType: Codable {
    @EncodeNulls
    var myText: String? // Will not be omitted when nil, e.g. will encode to `null` in JSON and `$null` in PLISTs
}

Lossy Collections

@LossyArrayDecoding
@LossyDictionaryDecoding
@LossySetDecoding

Filters null values during decoding without throwing an Error

private struct LossyCollectionModel: Codable, Equatable {
    @LossyArrayDecoding
    var array: [String] // Ignores null values without throwing an Error
    @LossyDictionaryDecoding
    var dictionary: [String:String] // Ignores null values without throwing an Error
    @LossySetDecoding
    var set: Set<String> // Ignores null values without throwing an Error
}

Empty Defaults

When you want to encode/decode an empty value rather than decoding nil or omitting encoding

struct MyType: Codable {
    @FallbackEncoding<EmptyInt>
    var int: Int? // will encode `0` when nil
    @FallbackDecoding<EmptyString>
    var string: String // will decode to "" when value was missing/nil
    @FallbackCoding<EmptyArray>
    var array: [Int]? // will encode/decode to [] when missing/nil
}
All Empty Values
EmptyBool
EmptyString
EmptyInt
EmptyInt16
EmptyInt32
EmptyInt64
EmptyInt8
EmptyUInt
EmptyUInt16
EmptyUInt32
EmptyUInt64
EmptyUInt8
EmptyCGFloat
EmptyDouble
EmptyFloat
EmptyFloat16
EmptyArray
EmptyDictionary
EmptySet

Empty defaults are available for most typical Foundation Types

Other Fallbacks

Any other kind of default can be provided by a custom FallbackValueProvider

public struct DistantFutureDateProvider: FallbackValueProvider {
    public static var defaultValue: Date { Date.distantFuture }
}

struct MyType: Codable {
    @FallbackEncoding<DistantFutureDateProvider>
    var updatedDate: Date?
}

@OmitCoding

For a Property you want to be ignore when (en/de)coding

struct MyType: Codable {
    @OmitCoding
    var myText: String? // Never encodes and ignores a value if one is in decoded data.
}

@Base64Coding

For a Data property that should be serialized to a Base64 encoded String

struct MyType: Codable {
    @Base64Coding
    var myData: Data // Now encodes to a Base64 String
}

@SecondsSince1970DateCoding

For a Date property that should be serialized to SecondsSince1970

struct MyType: Codable {
    @SecondsSince1970DateCoding
    var myDate: Date // Now encodes to SecondsSince1970
}

@MillisecondsSince1970DateCoding

For a Date property that should be serialized to MillisecondsSince1970

struct MyType: Codable {
    @MillisecondsSince1970DateCoding
    var myDate: Date // Now encodes to MillisecondsSince1970
}

@DateFormatterCoding<DateFormatterStaticCoder>

For other Date formats create a Type that adheres to the DateFormatterStaticCoder Protocol and use the convenience @DateFormatterCoding typealias or @CodingUses<StaticCoder>.

struct MyCustomDateCoder: DateFormatterStaticCoder {
    static let dateFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "MM:dd:yy H:mm:ss"
        return formatter
    }()
}

struct MyType: Codable {
    @DateFormatterCoding<MyCustomDateCoder>
    var myDate: Date // Now encodes to the format: "MM:dd:yy H:mm:ss"
}

@ISO8601DateCoding

For a Date property that should be serialized using the ISO8601DateFormatter

struct MyType: Codable {
    @ISO8601DateCoding
    var myDate: Date // Now encodes to ISO8601
}

@ISO8601DateFormatterCoding<ISO8601DateFormatterStaticCoder>

For other Date formats create a Type that adheres to the ISO8601DateFormatterStaticCoder Protocol and use the convenience @ISO8601DateFormatterCoding typealias or @CodingUses<StaticCoder>.

@available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
struct MyCustomISO8601DateFormatter: ISO8601DateFormatterStaticCoder {
    static let iso8601DateFormatter: ISO8601DateFormatter = {
        let formatter = ISO8601DateFormatter()
        formatter.formatOptions = [.withInternetDateTime, .withDashSeparatorInDate]
        return formatter
    }()
}


struct MyType: Codable {
    @ISO8601DateFormatterCoding<MyCustomISO8601DateFormatter>
    var myDate: Date // Now encodes with MyCustomISO8601DateFormatter's formatter
}

@NonConformingFloatCoding<ValueProvider>

When using a non-conforming Float, create a Type that adheres to NonConformingDecimalValueProvider and use @NonConformingFloatCoding<NonConformingDecimalValueProvider>

struct MyNonConformingValueProvider: NonConformingDecimalValueProvider {
    static var positiveInfinity: String = "100"
    static var negativeInfinity: String = "-100"
    static var nan: String = "-1"
}

struct MyType: Codable {
    @NonConformingFloatCoding<MyNonConformingValueProvider>
    var myFloat: Float // Now encodes with the MyNonConformingValueProvider values for infinity/NaN
}

@NonConformingDoubleCoding<ValueProvider>

When using a non-conforming Double, create a Type that adheres to NonConformingDecimalValueProvider and use @NonConformingDoubleCoding<NonConformingDecimalValueProvider>

struct MyNonConformingValueProvider: NonConformingDecimalValueProvider {
    static var positiveInfinity: String = "100"
    static var negativeInfinity: String = "-100"
    static var nan: String = "-1"
}

struct MyType: Codable {
    @NonConformingDoubleCoding<MyNonConformingValueProvider>
    var myFloat: Float // Now encodes with the MyNonConformingValueProvider values for infinity/NaN
}

Bool Coding

Sometimes an API uses an Int or String for a booleans.

@BoolAsStringCoding

struct MyType: Codable {
    @BoolAsStringCoding
    var myBool: Bool // Now encodes/decodes as a String. `"true"` for `true` and `"false"` for `false`. (Values are lower-cased before decoding)
}

@BoolAsIntCoding

struct MyType: Codable {
    @BoolAsIntCoding
    var myBool: Bool // Now encodes/decodes as an Int. `1` for `true` and `0` for `false`.
}

Additional Customization

The architecture was built with extensibility in mind so Implementing your own custom coding is as simple as adhering to the StaticCoder protocol. You can then simply add @CodingUses<YourCustomCoder> to your property, or create a typealias to make it cleaner: typealias YourCustomCoding = CodingUses<YourCustomCoder>

In fact all the included Wrappers are built the same way!

Full Example

struct NanosecondsSince9170Coder: StaticCoder {

    static func decode(from decoder: Decoder) throws -> Date {
        let nanoSeconds = try Double(from: decoder)
        let seconds = nanoSeconds * 0.000000001
        return Date(secondsSince1970: seconds)
    }

    static func encode(value: Date, to encoder: Encoder) throws {
        let nanoSeconds = value.secondsSince1970 / 0.000000001
        return try nanoSeconds.encode(to: encoder)
    }
}

// Approach 1: CustomCoding
struct MyType: Codable {
    @CodingUses<NanosecondsSince9170Coder>
    var myData: Date // Now uses the NanosecondsSince9170Coder for serialization
}

// Approach 2: CustomEncoding Property Wrapper typealias

typealias NanosecondsSince9170Coding = CodingUses<NanosecondsSince9170Coder>

struct MyType: Codable {
    @NanosecondsSince9170Coding
    var myData: Date // Now uses the NanosecondsSince9170Coder for serialization
}

Take a look at these other examples to see what else is possible.


Property Mutability

In 2.0 all wrappers are Mutable by default and can be made Immutable via Property Wrapper Composition

struct MyType: Codable {
    @Immutable @SecondsSince1970DateCoding
    var createdAt: Date

    @SecondsSince1970DateCoding
    var updatedAt: Date

    mutating func update() {
        createdAt = Date() // ERROR - Cannot assign to property: 'createdAt' is a get-only property
        updatedAt = Date() // Works!
    }
}

Optionals

2.0 introduces @OptionalCoding<StaticCodingWrapper> to enable Optionals for a property.

struct MyType: Codable {
    @SecondsSince1970DateCoding
    var createdAt: Date

    @OptionalCoding<SecondsSince1970DateCoding>
    var updatedAt: Date?
}

Only Encoding or Decoding

Sometimes you are only able/wanting to implement Encoding or Decoding.

To enable this, (where practical/possible), all of the included Wrappers have Encoding and Decoding variants

Change Coder to Encoder/Decoder or Coding to Encoding/Decoding to implement only one E.g. @Base64Encoding, @SecondsSince1970DateDecoding, @EncodingUses<ACustomEncoder>, etc.

struct MyType: Encodable {
    @SecondsSince1970DateEncoding
    var myDate: Date
}

struct MyType: Decodable {
    @SecondsSince1970DateDecoding
    var myDate: Date
}

Contributions

If there is a standard Serialization strategy that could be added feel free to open an issue requesting it and/or submit a pull request with the new option.

codablewrappers's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

codablewrappers's Issues

Hello friend

Could you tell me how can i set @OptionalCoding<#BoolAsStringCoding#> @OptionalCoding<#BoolAsIntCoding#> @FallbackDecoding<#EmptyBool#> together?

`@Immutable @EncodeNulls` doesn’t work as expected

Hey @GottaGetSwifty,

Using @Immutable with @EncodeNulls doesn’t work as expected.

struct TestModel: Encodable {
    @EncodeNulls var date1: Date?
    @Immutable @EncodeNulls var date2: Date?
}

 print(String(data: try! JSONEncoder().encode(TestModel(date1: nil, date2: nil)), encoding: .utf8))

// OUTPUT: "{\"date1\":null}"

I also can’t seem to get this snippet to compile (related?):

@Immutable @OptionalCoding<DateFormatterCoding<RFC3339DateCoder>> @EncodeNulls var myDate: Date?

Use default encoding with the optional wrapper

Hi,

What would be the simplest way to encode an optional as null if nil or use the default Codable encoding strategy if present ? I mean a generic way to do it on Codable to avoid writing static encoder for each of my Codable types.

so :
struct some: Encodable {
@??
let thisShouldBeEncodedAsNull: String? = nil
let thisShouldNotBeEncodedAsNull: String? = nil
}

would give in JSON:
{
"thisShouldBeEncodedAsNull": null
}

`DateFormatterStaticDecoder` throws `valueNotFound` error instead of `dataCorrupted` error

extension DateFormatterStaticDecoder {
/// Uses `dateFormatter` for decoding
public static func decode(from decoder: Decoder) throws -> Date {
let stringValue = try String(from: decoder)
guard let value = dateFormatter.date(from: stringValue) else {
throw DecodingError.valueNotFound(self, DecodingError.Context(codingPath: decoder.codingPath,
debugDescription: "Expected \(Data.self) but could not convert \(stringValue) to Data"))
}
return value
}
}

I was debugging an issue which was made a bit confusing because of throwing valueNotFound, would you like me to make a PR changing this to a dataCorrupted error?

It would match the behaviour of:

import Foundation

let string = """
{ "date": "ehrtrthrt" }
"""

struct Model: Codable {
  let date: Date
}

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601

do {
  let model = try decoder.decode(Model.self, from: Data(string.utf8))
} catch {
  if case DecodingError.dataCorrupted = error {
    print("DecodingError is dataCorrupted")
  } else {
    // not called
  }
}

Can I combine OptionalCoding<BoolAsIntCoding> with FallbackEncoding<EmptyBool>?

Hello, is it possible to combine the following two wrappers in some way?

public struct EmptyBoolTrue: FallbackValueProvider {
    public static var defaultValue: Bool { true }
}

@OptionalCoding<BoolAsIntCoding>
@FallbackEncoding<EmptyBoolTrue>
var autoRenewWarning: Bool?

The server sends 1 and 0 for booleans and I use Bool locally. What I would like to achieve is to set a default value of 1 or true whichever is possible if the key is missing or null but it seems the above two cannot be combined because one expects Int and the other Bool. How should I proceed regarding this, is there anything similar implemented that I can use as reference?

Feature request: change name of key

I would like to have a property wrapper that made it possible to change name of the key used when encoding and decoding. The result could look like this:

struct MyStruct: Codable {
   @CustomKey("key_in_json") var myOwnName: String
}

It is possible that I can do this by creating a custom codable wrapper, but so far I have not been able to achieve it.
The backed codable package has support for this. I think it would be really nice if this package could include this as well :)

Add Travis for Linux

Linux should be added as an additional environment for Travis CI.

Last time the test suite was run via Docker it passed with a couple false-negatives seemingly due to JSONEncoder implementation differences between between Mac and Linux. These tests should be fixed or workarounds should be found before adding integration.

`@EncodeNulls` and `@OptionalEncoding<X>` can’t be used together

I want to write something like this:

@Immutable @EncodeNulls @OptionalEncoding<DateFormatterEncoding<RFC3339DateCoder>> var completedOn: Date?

However, currently that doesn’t work. I did try a few variations but from what I could tell we don’t have the functionality to do this yet.

@jayrhynas kindly helped me out and we were able to come up with:

struct Model: Codable {
  @Immutable @EncodeOptionalNulls @OptionalEncoding<DateFormatterEncoding<RFC3339DateCoder>> var completedOn: Date?
}

/// Encodes an optional nil value in a singleValueContainer using `encodeNil` rather than it being omitted.
typealias EncodeOptionalNulls<T: Encodable & OptionalEncodingWrapper> = EncodingUses<OptionalNullStaticEncoder<T>>

struct OptionalNullStaticEncoder<T: Encodable>: StaticEncoder, AnyNullEncoder where T: OptionalEncodingWrapper {
  static func encode(value: T, to encoder: Encoder) throws {
    if case Optional<Any>.none = value.wrappedValue as Any {
      var container = encoder.singleValueContainer()
      try container.encodeNil()
      return
    }
    try value.encode(to: encoder)
  }
}

struct RFC3339DateCoder: DateFormatterStaticCoder {
  static let dateFormatter = with(DateFormatter()) {
    $0.timeZone = TimeZone(secondsFromGMT: 0)
    $0.locale = Locale(identifier: "en_US_POSIX")
    $0.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
  }
}

I’m not sure if the above could be simplified or made so that an additional StaticEncoder struct is not needed?

Feature: Sendable @OptionalDecoding<ISO8601DateDecoding> and @ISO8601DateDecoding

I'm using the wrappers @OptionalDecoding<ISO8601DateDecoding> and @ISO8601DateDecoding in my struct to decode dates, but making the struct conform to Sendable gives warnings for the properties with these wrappers as they don't conform to Sendable themselves

It looks like I can silence the warnings from Xcode with the following:

extension ISO8601DateDecoding: @unchecked Sendable {}
extension OptionalDecoding: @unchecked Sendable {}

But is there a technical reason this isn't done as part of the wrappers? Or is has it just not been implemented yet?

Is it possible to decode to custom types?

Hi,

I'm looking for a way to map/decode json values to custom Enums.

For instance my API return status value which may be something like -1, 0 or 1
I also have an enum:

enum Status: Int {
    case deleted = -1
    case inactive = 0
    case active = 1
}

Can I map these together? I tried implementing a custom mapper from your example buy it doest seem to accept custom types, such as Status . I want to be able to do something like this:

return Status(rawValue: -1)

and get my custom type

Unable to compile with Xcode12.5 beta3

Can't compile on macOS 11 (11.3 beta 20E5229a) using XCode 12.5 beta 3 (12E5244e) due to following error:
'Float16' is unavailable in macOS
Not sure what the extent of this is or if it does build for other macOS versions? If not we can simply rewrite the swift version check as:
#if swift(>=5.4) && !os(macOS)

Push new version to CocoaPods

When I install CodableWrappers via cocoapods, I only get version 2.0.0 instead of the latest 2.0.6. I need this newer version, and as I searched around I found others have the same issue and suggested:
"to update register version update in CocoaPods you shoud do pod trunk push CodableWrappers.podspec"
Please do so, so we can use this awesome library. Thank you!

Default values when key is not present

Hi, I've been working on a similar set of features as this project, until I found this one, great work!

The one feature I'm missing is for a way to have a non optional field that contains a default value in case the key is not present in the input data. So far I was able to get to this solution, which works for my use case, and was wondering if it might be something that could be added to this project

What I came up with was this:

import Foundation

public protocol DefaultValue<Value> where Value: Codable {
  associatedtype Value

  static var defaultValue: Value { get }
}

@propertyWrapper
public struct DefaultCodable<D: DefaultValue>: Codable {
  private enum State<Value> {
    case uninitialized
    case initialized(Value)
  }

  private var innerValue: State<D.Value>

  public init(value: D.Value? = nil) {
    if let value {
      innerValue = .initialized(value)
    } else {
      innerValue = .uninitialized
    }
  }

  public var wrappedValue: D.Value {
    get {
      if case .initialized(let value) = innerValue {
        return value
      } else {
        return D.self.defaultValue
      }
    }
    set {
      innerValue = .initialized(newValue)
    }
  }

  fileprivate var isSet: Bool {
    if case .uninitialized = innerValue {
      return false
    } else {
      return true
    }
  }

  public func encode(to encoder: Encoder) throws {
    if case .initialized(let value) = innerValue {
      var container = encoder.singleValueContainer()
      try container.encode(value)
    }
  }

  public init(from decoder: Decoder) throws {
    let container = try decoder.singleValueContainer()
    self.innerValue = try .initialized(container.decode(D.Value.self))
  }
}

extension KeyedEncodingContainer {
  public mutating func encode<T>(
    _ value: DefaultCodable<T>,
    forKey key: KeyedEncodingContainer<K>.Key
  ) throws {
    if value.isSet {
      try encode(value.wrappedValue, forKey: key)
    }
  }
}

extension KeyedDecodingContainer {
  public func decode<T>(
    _ type: DefaultCodable<T>.Type,
    forKey key: Self.Key
  ) throws -> DefaultCodable<T> {
    if contains(key) {
      let value = try decode(T.Value.self, forKey: key)
      return DefaultCodable(value: value)
    } else {
      return DefaultCodable()
    }
  }
}

// Default Values

public enum DefaultBoolTrue: DefaultValue {
  public static var defaultValue = true
}

public enum DefaultBoolFalse: DefaultValue {
  public static var defaultValue = false
}

which can be used like this:

public enum DefaultNameUnknown: DefaultValue {
  public static var emptyDefault = "Unknown"
}

public struct UserInfo: Codable {
  @DefaultCodable<DefaultBoolFalse> public var admin: Bool
  @DefaultCodable<DefaultBoolTrue> public var isActive: Bool

  @DefaultCodable<DefaultNameUnknown> public var name: String

  public init() {}
}

And used like this:

public enum DefaultNameUnknown: DefaultValue {
  public static var defaultValue = "Unknown"
}

public struct UserInfo: Codable {
  @DefaultCodable<DefaultBoolFalse> public var admin: Bool
  @DefaultCodable<DefaultBoolTrue> public var isActive: Bool

  @DefaultCodable<DefaultNameUnknown> public var name: String

  public init() {}
}

which results in

let data = #"{}"#.data(using: .utf8)!

let decoder = JSONDecoder()
let user = try decoder.decode(UserInfo.self, from: data)
print(user.admin) // false
print(user.isActive) // true
print(user.name) // Unknown

This is using 5.7 syntax, but could probably be adapted. Also, there might be a better way to specify a default value other than types, but this worked for me well enough.

Is this something that you might consider adding to CodableWrappers?

Decoding empty JSON string value into nil with Codable

normal case:

{
    "maintenance": true
}

{
    "maintenance": false
}

If there is no maintenance station then it will become empty string

{
    "maintenance": ""
}

i want to have nil if maintenance is empty string in json

struct Demo: Codable {
    var maintenance: Bool?
}

Is there a good way to do it?

Using `@Immutable` with `@FallbackDecoding` doesn’t work as expected

struct WorkingModel: Codable {
  @FallbackDecoding<EmptyDouble>
  var duration: Double = 0
}

struct FailingModel: Codable {
  @Immutable @FallbackDecoding<EmptyDouble>
  var duration: Double = 0
}

let json = "{}"
let decoder = JSONDecoder()

do {
  _ = try decoder.decode(WorkingModel.self, from: json.data(using: .utf8).unsafelyUnwrapped) // Works
  _ = try decoder.decode(FailingModel.self, from: json.data(using: .utf8).unsafelyUnwrapped) // Throws an error about missing key
} catch {
  dump(error)
  fatalError()
}

Running the above code should produce an error about a missing key. Using breakpoints I was expecting ImmutableWrapper.swift:L41-L44 or ImmutableWrapper.swift:L64-L66 to be called. However, it didn’t appear that they were.

Make all wrappers optional by default

I've used CodableWrappers for a while and very liked it.

But it was inconvenient to write OptionalCoding every time I use wrapper on optional variable. Isn't it possible to make all wrappers Optional by default?

Add support for Optional Properties

Due to the way PropertyWrappers are implemented and some current Swift constraints, the currently available wrappers don't support Optionals. Simply creating an optional version will fail with a missing key when decoding, but there is a workaround pointed out here.

API is TBD, but the workaround should be used for now and deprecated when new features are available.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.