GithubHelp home page GithubHelp logo

deep-eql's Introduction

Improved deep equality testing for node and the browser.

build:? coverage:? dependencies:? devDependencies:?
Join the Slack chat Join the Gitter chat

What is Deep-Eql?

Deep Eql is a module which you can use to determine if two objects are "deeply" equal - that is, rather than having referential equality (a === b), this module checks an object's keys recursively, until it finds primitives to check for referential equality. For more on equality in JavaScript, read the comparison operators article on mdn.

As an example, take the following:

1 === 1 // These are primitives, they hold the same reference - they are strictly equal
1 == '1' // These are two different primitives, through type coercion they hold the same value - they are loosely equal
{ a: 1 } !== { a: 1 } // These are two different objects, they hold different references and so are not strictly equal - even though they hold the same values inside
{ a: 1 } != { a: 1 } // They have the same type, meaning loose equality performs the same check as strict equality - they are still not equal.

var deepEql = require("deep-eql");
deepEql({ a: 1 }, { a: 1 }) === true // deepEql can determine that they share the same keys and those keys share the same values, therefore they are deeply equal!

Installation

Node.js

deep-eql is available on npm.

$ npm install deep-eql

Usage

The primary export of deep-eql is function that can be given two objects to compare. It will always return a boolean which can be used to determine if two objects are deeply equal.

Rules

  • Strict equality for non-traversable nodes according to Object.is:
    • eql(NaN, NaN).should.be.true;
    • eql(-0, +0).should.be.false;
  • All own and inherited enumerable properties are considered:
    • eql(Object.create({ foo: { a: 1 } }), Object.create({ foo: { a: 1 } })).should.be.true;
    • eql(Object.create({ foo: { a: 1 } }), Object.create({ foo: { a: 2 } })).should.be.false;
  • When comparing Error objects, only name, message, and code properties are considered, regardless of enumerability:
    • eql(Error('foo'), Error('foo')).should.be.true;
    • eql(Error('foo'), Error('bar')).should.be.false;
    • eql(Error('foo'), TypeError('foo')).should.be.false;
    • eql(Object.assign(Error('foo'), { code: 42 }), Object.assign(Error('foo'), { code: 42 })).should.be.true;
    • eql(Object.assign(Error('foo'), { code: 42 }), Object.assign(Error('foo'), { code: 13 })).should.be.false;
    • eql(Object.assign(Error('foo'), { otherProp: 42 }), Object.assign(Error('foo'), { otherProp: 13 })).should.be.true;
  • Arguments are not Arrays:
    • eql([], arguments).should.be.false;
    • eql([], Array.prototype.slice.call(arguments)).should.be.true;

deep-eql's People

Contributors

dougluce avatar erezarnon avatar erikvold avatar greenkeeperio-bot avatar kapouer avatar keithamus avatar koddsson avatar logicalparadox avatar lorenzleutgeb avatar lucasfcosta avatar lucaswerkmeister avatar meeber avatar shvaikalesh avatar snewcomer avatar strml avatar teamworkguy2 avatar ucandoit avatar vesln avatar

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

deep-eql's Issues

Cannot reliably compare Ada-based URLs (Node.js v18.17.0 & newer)

Until recently, my team was using Node.js v18.13.0. Our CI system picked up Node.js v18.17.0 and started failing. Specifically, we started failing when using Chai to perform expect(…).to.deep.equal on URLs.

After reading the changelog for v18.17.0, I see that Ada-based URLs were backported to Node.js 18 (see here).

Narrowing down some more, it seems there is a behavior change in Node.js 18.17.0 where Symbol(query) is lazily set on URLs whenever searchParams is accessed (see here). So, if you've never accessed that property of a URL, Symbol(query) does not exist; however, once you have accessed that property, Symbol(query) does exist. This leads to the following breakage (I'm demonstrating with Mocha):

const { expect } = require('chai')

describe('URL', () => {
  it('succeeds', () => {
    const url = new URL('foo://bar')
    expect(url).to.deep.equal(new URL('foo://bar'))
  })

  // The following succeeded in Node.js < v18.17.0.
  it('fails', () => {
    const url = new URL('foo://bar')
    void url.searchParams
    expect(url).to.deep.equal(new URL('foo://bar'))
  })
})

Maybe this is working as expected, but it was an unfortunate bug we hit. We have worked around it by changing our tests to no longer expect(…).to.deep.equal on URLs.

deep equal comparison fails when objects contain function

I'm trying to write unit tests for my redux-saga functionality. I found out that there is an issue when trying to compare 2 identical objects containing a function. Basically it never equals:

const obj1 = {
  test: function () {},
  prop: 'prop',
};
const obj2 = {
  test: function () {},
  prop: 'prop',
};

I've seen example created using Tape framework where that comparison worked.

Assertion error does not state problematic parts for Maps

chai.expect(new Map([['a','a']])).to.deep.equal(new Map([['a','b']]))
// AssertionError: expected {} to deeply equal {}
chai.expect([['a','a']]).to.deep.equal([['a','b']])
// AssertionError: expected [ [ 'a', 'a' ] ] to deeply equal [ [ 'a', 'b' ] ]

As you can se it is not clear why it fails from the error message

Support for tc39/proposal-temporal

Hello, I've recently encounted a problem with chai's deep equal assertion when an object contains a property of type Temporal.PlainDate. For example the following assertion does not result in error while it's not the same date.

expect({ name: 'a', date: Temporal.PlainDate.from('2022-05-30') }).to.deep.equal({
  name: 'a',
  date: Temporal.PlainDate.from('2022-05-31'),
});

The reason is that in deep-eql https://github.com/chaijs/deep-eql/blob/main/index.js#L197 the Temporal.PlainDate type is not managed since it's still in stage 3.
What's your opinion on making a PR to add the Temporal type comparison?
Otherwise do you have alternative solutions to make the comparison work?

Set and Map performance and correctness

I was curious how well chai would handle big sets and maps and checked a couple of things and also stumbled across this PR and I am sorry to say that these benchmarks are somewhat flawed.

The Node.js assert module was never used for comparison because the benchmark required a in-existing function that would be replaced with deep-eql in that case. The result is that the node and deep-eql results are actually both from the same library so they should be pretty much identical. However, that is not always the case and they partially differ by a big margin e.g.

buffer                               x 1,166,637 ops/sec ±6.09% (73 runs sampled)
buffer                        (node) x 611,182 ops/sec ±2.47% (65 runs sampled)
object literal                       x 160,121 ops/sec ±2.89% (81 runs sampled)
object literal                (node) x 392,734 ops/sec ±2.38% (85 runs sampled)

My main concern with these benchmarks is though, that only very simply objects are used. Having nice numbers for those is awesome but they are normally not an issue. If a complex object is used though, this can be really bad.

// Set with 10000 numbers
const actual = new Set(Array(1e4).fill(1).map((_, i) => len - i - 1))
const expected = new Set(Array(1e4).fill(1).map((_, i) => i))

This time compared to Node.js 8.4 (this time for real)

set                                  x 3.89 ops/sec ±1.26% (58 runs sampled)
set                           (node) x 1,387 ops/sec ±0.33% (138 runs sampled)

So Node.js is more then 350 times as fast in this case.

While checking Sets and Maps further I also noticed the following:
When using Sets twice the work is done that is needed in general because the key and the value are both the value when returned in a forEach.

Worse though: comparing Sets or Maps with Objects does not even work properly!

const deepEql = require('./')
const a = new Set([{}, {a:5}])
const b = new Set([{a:5}, {}])
deepEql(a,b) // false

Sorting an array with objects is not possible and that is why this bug exists.

I suggest to have a look at a PR from me that would improve the situation and fix the bug as well nodejs/node#14258.

As chai currently does not have a loose equal comparison the algorithm should be pretty straight forward (otherwise there is quite some extra handling for that).

Build failing due to change in error comparison algo

Looks like #57 broke the build for IE 9 & 11 as well as Safari 10.

Apparently IE 9 & 11 add an enumerable description property to Error objects but not to TypeError objects, causing one of the comparison tests to fail. The description property appears to have the same value as message. (If message and description is empty, then IE 9 & 11 also add an enumerable number property, but that doesn't come into play with any of the tests.)

Apparently Safari 10 adds enumerable line, column, and sourceURL properties to all Error objects. This causes all of the tests to fail that expected two Error objects to be equal, since the line and/or column properties will always be different between Error objects.

What a pain. I'm not sure what the right solution is here.

Dataview comparison ignores offsets

The dataview comparison in ExtensiveDeepEqualByType compares the underlying buffers instead of comparing the dataviews themselves.
This means that the following dataviews are treated as different even if they represent the same data:

const shortBuffer = new Uint8Array([0x01, 0x01]);
const longBuffer = new Uint8Array([0x00, 0x01, 0x02, 0x03]);
const view1 = new DataView(shortBuffer, 0, 1);
const view2 = new DataView(longBuffer, 1, 1);

Both views represent the slice [0x01] but the equality test returns false because the underlying buffers are different.
Note that this behavior is not even fully consistent. If you want to treat buffer as a public property that should match in both cases, then the offset should also matter. At the moment new DataView(longBuffer, 0, 2) is equal to new DataView(2, 2) because the buffers are the same (even if the data is different due to the different offsets).

eql({}, null) throws WeakMap key error

Simple reproduction:

$ node
> const eql = require('deep-eql')
undefined
> eql({}, null)
TypeError: Invalid value used as weak map key
    at WeakMap.set (native)
    at memoizeSet (/Users/samuelreed/git/forks/ajv/node_modules/deep-eql/index.js:92:17)
    at extensiveDeepEqual (/Users/samuelreed/git/forks/ajv/node_modules/deep-eql/index.js:175:5)
    at deepEqual (/Users/samuelreed/git/forks/ajv/node_modules/deep-eql/index.js:141:10)
    at repl:1:1
    at sigintHandlersWrap (vm.js:22:35)
    at sigintHandlersWrap (vm.js:96:12)
    at ContextifyScript.Script.runInThisContext (vm.js:21:12)
    at REPLServer.defaultEval (repl.js:313:29)
    at bound (domain.js:280:14)
$ node --version
v6.9.1

Update karma package version to the newer one to support newer nodejs version

This package (deep-eql) is used in chai latest version as a dependency.
deep-eql package has a dependency from "karma": "^0.13.22"

Using even the latest(v3.0.1) version of the deep-eql package I am getting the following error:

lerna ERR! execute Error: Command failed: npm install
lerna ERR! execute npm WARN EBADENGINE Unsupported engine {
lerna ERR! execute npm WARN EBADENGINE   package: '[email protected]',
lerna ERR! execute npm WARN EBADENGINE   required: { node: '0.10 || 0.12 || 4 || 5' },
lerna ERR! execute npm WARN EBADENGINE   current: { node: 'v16.13.1', npm: '8.1.2' }
lerna ERR! execute npm WARN EBADENGINE }

Please see also the screenshot:

image

My suggestion is to update karma version to a newer one that supports a higher version of the nodejs.

Deep equality with a set depth

Is it possible to limit the deep equality comparison to a certain depth?

For example:

const a = {
    foo: {
        bar: {
            baz: "qux"
        }
    }
}

const b = {
    foo: { // compared deeply
        bar: { // compared by identity (===)
            baz: "qux"
        }
    }
}

// this passes, since 'a' and 'b' are structurally equal
expect(a).to.deep.equal(b);

// this would fail, since the 'bar' object would be compared by identity
expect(a).to.deep.depth(1).equal(b);

In my real-world scenario the bar object would of course be a lot more complicated. Comparing these by identity is more than sufficient, and deep-equality even runs into issues due to circular references.

Feature request - allow '==' equality with an option

In some cases, it would make sense to use the weak equality == instead of the strong one ===.

Take this example, where two URL parsers give different results :

{
  pathvars: {
    id: 42
  }
}

vs

{
  pathvars: {
    id: "42"
  }
}

I have no idea how complicated it would be to achieve internally. From the API point of view, I would add another function or a flag in the current one's arguments to enable the weak comparison.

TypeError: Cannot convert a Symbol value to a string

// @ts-ignore
import _equals from 'deep-eql';

let u1 = new URL(`https://bafybeicm5clh7fl4up4prnbfqksou6vsp5voth54rcsxhsjysimm3o77fq.on.fleek.co/`);
let u2 = new URL(`https://bafybeicm5clh7fl4up4prnbfqksou6vsp5voth54rcsxhsjysimm3o77fq.on.fleek.co/`);

console.dir(_equals(u1, u2))

Comparing Properties with getters only

I have an immutable data structure defined as follow:

let DataStructure = function (name, description, imageUrl, linkUrl) {
    let _name = name;
    let _description = description;
    let _imageUrl = imageUrl;
    let _linkUrl = linkUrl;

    Object.defineProperty(this, 'name', {
        get: () => _name,
    });

    Object.defineProperty(this, 'description', {
        get: () => _description,
    });

    Object.defineProperty(this, 'imageUrl', {
        get: () => _imageUrl,
    });

    Object.defineProperty(this, 'linkUrl', {
        get: () => _linkUrl,
    });
};

Comparing to object instances with different values always returns true when it should return false.

objectEqual Sorts Keys Before Compare

Today, when reserving the objectEqual function in this library while evaluating deep.equal call stacks in a chai test harness, I observed that when comparing objectEqual() from the default branch in extensiveDeepEqualByType) it sorts the keys.

leftHandKeys.sort();

rightHandKeys.sort();

Is it not more performant for large objects to just iterate over unsorted properties with something like hasOwnProperty on the rightHandProperty properties? If so, I can make a PR.

URLSearchParams deep equal not working

I'm trying to test if my URLSearchParams are correct with the to.deep.equal option but it returns true (is equal) when it shouldn't.

See the running code at https://stackblitz.com/edit/node-qx7qra?file=index.test.js

Let's assume that we're testing this function:

function getIncorrectParams() {
  return new URLSearchParams({
    from: '2020',
    to: '2021',
    ids: ['abc-1'],
  });
}

If I write:

test('via string', () => {
  expect(getIncorrectParams().toString()).not.to.equal(
    new URLSearchParams({
      from: '2020',
      to: '2021',
      ids: ['abc-1', 'abc-2'],
    }).toString()
  );
});

It correctly notices that the strings are not the same, good. But as soon as I remove the toString and test with:

test('via deep equal', () => {
  expect(getIncorrectParams()).not.to.deep.equal(
    new URLSearchParams({
      from: '2020',
      to: '2021',
      ids: ['abc-1', 'abc-2'],
    })
  );
});

It claims that the assertion failed because the two objects are "equal". Note if you actually go ahead and run the example, the debug output clearly shows that there are differences!

And the deep.equal property works if I use "normal" object. See this example where I convert the URLSearchParams to a "plain object" first:

test('deep equal plain objects', () => {
  expect(Object.fromEntries(getIncorrectParams().entries())).not.to.deep.equal({
    from: '2020',
    to: '2021',
    ids: ['abc-1', 'abc-2'],
  });
});

ChainAlert: new npm maintainer has published version 4.0.1 of package deep-eql

Dear deep-eql maintainers,
Thank you for your contribution to the open-source community.

We've noticed that chai, a new maintainer, just published version 4.0.1 of deep-eql to npm.

As part of our efforts to fight software supply chain attacks, we would like to verify this release is known and intended, and not a result of an unauthorized activity.

Tagging @chaijs (publisher of the previous version).

This issue was automatically created by ChainAlert.
If you find this behavior legitimate, kindly close and ignore this issue. Read more

badge

Strange behavior for objects with defined properties

I stumbled on a very un-intuitive issue today trying to compare typescript classes (compiled to es5) with a POJO in a chai test. It turns out that deep-eql does not behave very well when comparing objects that defines properties using Object.defineProperty(). Here is some sample typescript code to better explain what is going on:

class Foo {
  public a = 1;
  public get b() { return 2; }
}

const foo = new Foo();

// Notice how the property is not mentioned in the output, making
// both json exactly the same while still failing the comparison.
expect(foo).to.deep.equal({ a: 1 }); // fails => expect { a: 1 } to deep equal { a: 1 }

// This is a little counter intuitive based on the error but could be
// a perfectly valid scenario.
expect(foo).to.deep.equal({ a: 1, b: 2 }) // success

// Now, this is really not what I was expecting.
expect(foo).to.deep.equal({ a: 1, b: undefined }) // success

It seems that, as long as the key is somehow present in both objects, the value does not matter when comparing defined properties. I would expect either property values to be matching, or properties to be completely ignored in the comparison process, but not the current behavior.

Get mismatch info?

I'm currently struggling to determine why two objects that look the same to me are being compared as being different.

Is there anyway for me to get information as to why the lib is returning false? either as part of the response or just logging would help.

thanks

Issue with semantic-release

Commits aren't triggering new releases. This is from the latest commit:

deep-eql@ semantic-release /home/travis/build/chaijs/deep-eql
semantic-release pre && npm publish && semantic-release post

semantic-release WARN invalid config loglevel="notice"
semantic-release ERR! pre Failed to determine new version.
semantic-release ERR! pre ENOCHANGE There are no relevant changes, so no new version is released.

Any ideas?

Comparison between uninitialized arrays fail

Performing a deep equal on an uninitialized array doesn't behave as expected.

      const myTestArray1 = [undefined, 'test']
      const myTestArray2 = []
      // myTestArray2[0] should be equal to undefined by default
      myTestArray2[1] = 'test'

      expect(myTestArray1).to.deep.equal(myTestArray2)

I would expect these two arrays to pass a deep equality check since javascript seems to default uninitialized values to undefined

`entriesEqual` breaks on sets of objects with null prototype

The last line of entriesEqual throws the following error in my test cases:

TypeError: Cannot convert object to primitive value
    at Array.toString (native)
    at Array.sort (native)
[...]

Here is how I can reproduce it with chai:

function getAnimals() {
  const duck = Object.create(null);
  duck.name = "duck";
  const cat = Object.create(null);
  cat.name = "cat";
  return new Set([duck, cat]);
}

const actual = getAnimals();
const expected = new Set([{name: "duck"}, {name: "cat"}]);

assert.deepEqual(actual, expected);

The error is caused by the fact that the objects with a null prototype cannot be converted to strings implicitly, and the array sort function performs a lexicographical sort on strings so it first tries to convert them to strings.

(Tested on Node 9.4)

'function' comparison

Due to the way npm hoisting works, two deeply equal instances of the same ES6 class loaded from different locations (node_modules) return false.
Maybe instead of referential equality for functions, Function.toString will be a better way to go?

Comparator test fails if args are switched

In work I am doing to solve #33, I noticed that this test will fail:

  it('returns true if Comparator says so even on primitives (switch arg order)', function () {
    var valueA = { a: 1 };
    var valueB = {
      a: new Matcher(function (value) {
        return typeof value === 'number';
      }),
    };
    assert(eql(valueA, valueB, { comparator: matcherComparator }) === true,
      'eql({a:1}, {a:value => typeof value === "number"}, <comparator>) === true');
  });

This only changes the argument order from the existing test. This is because only the left-hand side is checked as a primitive, when really both sides should be to ensure identical behavior.

I will fix this as part of a PR, but I believe we'll end up breaking null comparator behavior.

Loosely comparator with Set gives false result

Hello! This library looks like a great alternative for deep-equal but there are some cases where I can't make it work:

console.log(deepEql(
  new Set([null, '', 1, 5, 2, false]),
  new Set([undefined, 0, '5', true, '2', '-000']),
  { comparator: loosely }
))

function isPrimitive (value) {
  return value === null || typeof value !== 'object'
}

function loosely (a, b) {
  // console.log('loosely', [typeof a, typeof b], [a, b])
  if (!isPrimitive(a)) return null
  if (!isPrimitive(b)) return null
  const equal = a == b
  // console.log('loosely primitives', [a, b], 'equal?', equal)
  return equal
}

Currently I'm trying to test against several deep-equal tests to ensure that is mostly compatible to not break anything in the lib switching. Probably it's a good idea as you could find bugs this way

Btw I took the loosely comaprator from here: #47 (comment)

Thanks!

Don’t compare non-enumerable symbols

Since version 4.0.1 (67d704c / #81, CC @snewcomer and @keithamus), deep-eql compares non-enumerable symbols. I find this surprising and unintuitive, and it’s different from string keys, where only enumerable keys are compared:

> key = 'x';
> deepEql(Object.defineProperty({}, key, { value: 'x', enumerable: false }), Object.defineProperty({}, key, { value: 'y', enumerable: false }))
true
> key = Symbol.for('x');
> deepEql(Object.defineProperty({}, key, { value: 'x', enumerable: false }), Object.defineProperty({}, key, { value: 'y', enumerable: false }))
false

@meeber in chaijs/chai#1054 (comment) also only suggested that enumerable symbols should be compared, and I suggest changing deep-eql to only compare these.

Does not work with browserify

When running browserify to bundle test files using chai, I am getting the following error:

Cannot find module './lib-cov/eql'

This is because index.js has a conditional require that is not supported by browserify. There was a similar problem in chai itself that has been fixed, is it possible to apply the same fix to deep-eql too? See chaijs/chai#28.

Sets/Maps silently pass

As @hildjj and @rocketraman point out in chaijs/chai#394, deep equality for Maps and Sets doesn't work (because their keys are not exposed like a normal object, which is what we check for).

x = new Map
x.set('foo', 'bar');
y = new Map
y.set('bar', 'baz');
chai.expect(y).to.deep.equal(x) // this passes, but should fail.

There's also not any particularly convenient ways to get all of the values out in a succinct way, except maybe the spread operator, but this is only available if transpiling ES6.

chai.expect([...y]).to.deep.equal([...x])

With Maps and Sets now a part of Node v4.0, deep-eql should definitely support Maps and Sets.

To implement this, we'd just need to add some extra conditions within around L56 to detect Maps and Sets (and WeakMaps and WeakSets), and call out to functions such as mapEqual and setEqual.

When done, we should PR upstream to chai proper.

Feature request: Add possibility to exclude/omit keys when comparing objects

I encountered the necessity to compare some generated data with test data, where those data sets include dynamically generated id values nested in different levels. So the goal was to test the object for equality by ignoring/ommiting those id_ keys.

E.G.

// test for equality but ignore the values of id
{
  id: 1234,
  a: 'foo',
  b: {
    id: 45678
    c:  'bar'
  }

}

I cerated my own - much simpler deepEql_ function

const deepEql = (a: unknown, b: unknown, omitKeys: string[] = []): boolean => {
    if (a === b) return true;

    omitKeys.forEach(key => delete a[key]);
    omitKeys.forEach(key => delete b[key]);

    if (typeof a !== 'object' || typeof b !== 'object' || a == null || b == null) return false;

    const keysA = Object.keys(a);
    const keysB = Object.keys(b);

    if (keysA.length !== keysB.length) return false;

    // eslint-disable-next-line no-restricted-syntax
    for (const key of keysA) {
      if (!keysB.includes(key)) return false;

      if (typeof a[key] === 'function' || typeof b[key] === 'function') {
        if (a[key].toString() !== b[key].toString()) return false;
      } else if (!this.deepEql(a[key], b[key], omitKeys)) return false;
    }

    return true;
  }

which works in my case, but I would love to see the possibility to specify which keys to exclude in the deep-eql api which seems obviously much more reliable than my solution

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.