Giter Club home page Giter Club logo

skip's Introduction

CircleCI

Skip Overview

Skip is a general-purpose programming language that tracks side effects to provide caching with reactive invalidation, ergonomic and safe parallelism, and efficient garbage collection. Skip is statically typed and ahead-of-time compiled using LLVM to produce highly optimized executables.

Caching with Reactive Invalidation

Skip's main new language feature is its precise tracking of side effects, including both mutability of values as well as distinguishing between non-deterministic data sources and those that can provide reactive invalidations (telling Skip when data has changed). When Skip's type system can prove the absence of side effects at a given function boundary developers can opt-in to safely memoizing that computation, with the runtime ensuring that previously cached values are invalidated when underlying data changes.

Safe Parallelism

Skip supports two complementary forms of concurrent programming, both of which avoid the usual thread safety issues thanks to Skip's tracking of side effects. First, Skip supports ergonomic asynchronous computation with async/await syntax. Thanks to Skip's tracking of side effects, asynchronous computations cannot refer to mutable state and are therefore safe to execute in parallel (this means that independent async continuations can continue in parallel). Second, Skip has APIs for direct parallel computation, again using its tracking of side effects to prevent thread safety issues such as shared access to mutable state.

Efficient and Predictable GC

Skip uses a novel approach to memory management that combines aspects of typical garbage collectors with more straightforward linear (bump) allocation schemes. Thanks to Skip's tracking of side effects the garbage collector only has to scan memory reachable from the root of a computation. In practical terms, this means that developers can write code with predictable GC overhead.

Hybrid Functional/Object-Oriented Language

Skip features an opinionated mix of ideas from functional and object-oriented styles, all carefully integrated to form a cohesive language. Like functional languages, Skip is expression-oriented and supports abstract data types, pattern matching, easy lambdas, higher-order functions, and (optionally) enforcing pure/referentially-transparent API boundaries. Like imperative/OO languages, Skip supports classes with inheritance, mutable objects, loops, and early returns. Skip also incorporates ideas from “systems” languages to support low-overhead abstractions, compact memory layout of objects via value classes, and patterns that ensure code specialization with static method dispatch.

Great Developer Experience

Skip was designed from the start to support a great developer experience, with a rapid iteration speed more commonly associated with dynamic languages. The compiler supports incremental type-checking (with alpha versions of IDE plugins providing near-instantaneous errors as you type), provides hints for common syntax mistakes and to help newcomers learn the language, recognizes small typos of method/class names, and even recognizes common alternatives to Skip's standard library method names and suggests the correct name in Skip. Skip also features a code-formatter to ensure consistent code style and a tool for running codemods.

Built by a Team of Veterans

Skip was designed by an experienced team including senior contributors to ActionScript, C#, Flow, Hack, HHVM, Prettier, React Native, and Relay.

Documentation is in the docs/ directory.

Instructions for building with cmake

Website

http://skiplang.com

Playground

http://skiplang.com/playground

License

Skip is MIT licensed.

skip's People

Contributors

aorenste avatar badsyntax avatar beauby avatar dependabot[bot] avatar iamrecursion avatar jasone avatar josephsavona avatar joshterrill avatar keichinger avatar koolamusic avatar koresar avatar objectisundefined avatar pavlos1 avatar pikatchu avatar pjc0247 avatar vjeux avatar yabalaban 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  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

skip's Issues

linking errors

[83/168] : && /usr/lib64/ccache/bin/x86_64-pc-linux-gnu-g++  -O2 -march=native -mtune=native -pipe  -Wl,-O1 -Wl,--as-needed lkg/tmp/skip_to_llvm.gen.o lkg/CMakeFiles/skip_to_llvm.lkg.dir/runtime/native/src/sk_standalone.cpp.o  -o lkg/bin/skip_to_llvm  lkg/runtime/native/libskip_runtime.a third-party/googletest/libgtest_main.a third-party/install/lib/libfolly.a /usr/lib/libdouble-conversion.so /usr/lib/libgflags.so /usr/lib/libglog.so -ldl /usr/lib/libevent.so /usr/lib/libboost_thread-mt.so /usr/lib/libboost_system-mt.so /usr/lib/libboost_context-mt.so /usr/lib/libboost_filesystem-mt.so /usr/lib/libboost_chrono-mt.so /usr/lib/libboost_date_time-mt.so /usr/lib/libboost_atomic-mt.so -Wl,-rpath,/usr/lib /usr/lib/libunwind.a -lpthread third-party/install/lib/libicutu.a third-party/install/lib/libicuio.a third-party/install/lib/libicui18n.a third-party/install/lib/libicuuc.a third-party/install/lib/libicudata.a -lpcre -lrt /usr/lib/libjemalloc.so && :
FAILED: lkg/bin/skip_to_llvm 
: && /usr/lib64/ccache/bin/x86_64-pc-linux-gnu-g++  -O2 -march=native -mtune=native -pipe  -Wl,-O1 -Wl,--as-needed lkg/tmp/skip_to_llvm.gen.o lkg/CMakeFiles/skip_to_llvm.lkg.dir/runtime/native/src/sk_standalone.cpp.o  -o lkg/bin/skip_to_llvm  lkg/runtime/native/libskip_runtime.a third-party/googletest/libgtest_main.a third-party/install/lib/libfolly.a /usr/lib/libdouble-conversion.so /usr/lib/libgflags.so /usr/lib/libglog.so -ldl /usr/lib/libevent.so /usr/lib/libboost_thread-mt.so /usr/lib/libboost_system-mt.so /usr/lib/libboost_context-mt.so /usr/lib/libboost_filesystem-mt.so /usr/lib/libboost_chrono-mt.so /usr/lib/libboost_date_time-mt.so /usr/lib/libboost_atomic-mt.so -Wl,-rpath,/usr/lib /usr/lib/libunwind.a -lpthread third-party/install/lib/libicutu.a third-party/install/lib/libicuio.a third-party/install/lib/libicui18n.a third-party/install/lib/libicuuc.a third-party/install/lib/libicudata.a -lpcre -lrt /usr/lib/libjemalloc.so && :
/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: lkg/tmp/skip_to_llvm.gen.o: in function `sk.Instr__visitInputs':
/Users/joesavona/github/skip-oss/src/native/IR.sk:626: undefined reference to `SKIP_Obstack_note_inl'
/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: lkg/tmp/skip_to_llvm.gen.o: in function `BoolCmpEq__clone':
/Users/joesavona/github/skip-oss/src/native/IR.sk:963: undefined reference to `SKIP_Obstack_note_inl'
/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: lkg/tmp/skip_to_llvm.gen.o: in function `Int::>=<Int>':
/Users/joesavona/github/skip-oss/src/runtime/prelude/core/primitives/Int.sk:82: undefined reference to `SKIP_Obstack_note_inl'
/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: /Users/joesavona/github/skip-oss/src/runtime/prelude/core/primitives/Int.sk:82: undefined reference to `SKIP_Obstack_note_inl'
/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: lkg/tmp/skip_to_llvm.gen.o: in function `Sequence<String>::iterator':
/Users/joesavona/github/skip-oss/src/runtime/prelude/core/language/Sequence.sk:37: undefined reference to `SKIP_Obstack_note_inl'
/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: lkg/tmp/skip_to_llvm.gen.o:/Users/joesavona/github/skip-oss/src/runtime/prelude/core/primitives/Array.sk:303: more undefined references to `SKIP_Obstack_note_inl' follow
collect2: error: ld returned 1 exit status

Install via homebrew

Description

Get install process via homebrew on MacOS

Why

Install the product via homebrew brings skip inline with other languages and product that get installed on MacOS. It is a fairly easy and straightforward process. The current process is not very clear and somewhat cumbersome.

Simple and straightforward installation process on MacOS will help to bring more developers into the language due to the simplicity of the process.

Possible Implementation & Open Questions

Follow homebrew guideline to add new formula.

N/A

Is this something you're interested in working on?

  • YES
  • [ X] NO

Abstract static methods on traits are too restrictive

The following program:

trait MyTrait {
static fun foo(): void;
static fun bar(): void {
static::foo();
}
}

Gives the error:
File "/home/ci/skfs/lexer.sk", line 6, characters 5-17:
Invalid abstract call
4 | static fun foo(): void;
5 | static fun bar(): void {
6 | static::foo();
| ^^^^^^^^^^^^^
7 | }

File "/home/ci/skfs/lexer.sk", line 4, characters 14-16:
'foo' is abstract. It can be used only from 'static' or a Concrete<_> object
2 |
3 | trait MyTrait {
4 | static fun foo(): void;
| ^^^
5 | static fun bar(): void {

Communication about the project

Hi,

This project seems really interesting. As such I would like to know more about it.

It seems that some members of the core (previously at Facebook) hang around here. If this is the case, can one of them communicate (a bit more) about the language. For example:

Do they have any plan to continue to work on it? If yes, what features are planned? Do they have a vision for the future of the language? If no, do they plan to give away the ownership of the repository? etc...

Incremental Compilation?

In docs/blog/2017-11-30-parallelism.md you stated that skip is going to have incremental compiler based on memoization:

Although this was a fun hack, the next big exciting change won't involve parallelism, and will take a lot longer than a weekend — it's making the compiler incremental, using Skip's own reactive memoizer to only recompile code affected by modified files. Stay tuned!

But there was no follow up post on this topic, even though it's almost 3 years already. Therefore, I have few questions:

  1. Does skip have incremental compiler?
  2. How many parts of the compiler are actually incremental?
  3. Was builtin meoization useful?
  4. If yes, are there also some examples where memoization (perhaps surprisingly) wasn't that useful?

IDE's?

In the README it says "with alpha versions of IDE plugins providing near-instantaneous errors as you type". Where can I find these alpha IDE plugins?

The website is down again.

request http://skiplang.com/
get error

Error: connect ECONNREFUSED 127.0.0.1:8082
    at Object._errnoException (util.js:1022:11)
    at _exceptionWithHostPort (util.js:1044:20)
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1198:14)

Tutorial exercice 10 failure

In tutorial for exercice n°10:

Now, let's write the mutable version. Notice the keywords 'mutable' placed in front of the field and the method. this.!field = value modifies object in place, much like in any other programming language.

mutable class Point {mutable x: Int, y: Int} {
    mutable fun incrX(): void {
      // TODO: increment the field 'x' by 1
      // HINT: 'this.!x = value' sets the field 'x' to 'value'
      
    }
}

A compilation error is returned regardless of the expression tested with run:

File "playground.sk", line 1, characters 15-19:
In 'Point's version of the member '!=' inherited from 'Equality'
1 | mutable class Point {mutable x: Int, y: Int} {
  |               ^^^^^
2 |   mutable fun incrX(): void {
File "tests/runtime/prelude/core/traits/Equality.sk", line 26, characters 12-13:
Cannot call this method on a readonly object
24 |
25 |   overridable readonly fun !=(other: inst): Bool {
26 |     !(this == other)
   |            ^^
27 |   }
File "playground.sk", line 13, characters 7-8:
Try annotating '==' method as 'readonly'
11 | extension class Point uses Equality, Show {
12 |   // Defining equality for a Point
13 |   fun ==(other: this): Bool {
   |       ^^
14 |     other.x == this.x && other.y == this.y    

Memoization documentation

Posting as an issue since I don't know how to reach the authors otherwise.

Skip is a very interesting language.

I scanned the docs but could not find any information about the feature giving the language its name: memoization.

EG:

  • what are the cache semantics?
  • does it employ some kind of LRU cache?
  • what are the performance and memory implications to consider?

I'd be interested in how this works, is implemented, etc.

Also, since the language is a "now concluded research project", it would be very interesting to read about the conclusions of the project: how useful is the concept in practice, are there performance wins to be had in realistic workloads, etc.

[Internal] Improve Constraint Solving

We should collapse most constraints into into a single type when possible.

For example

fun ex<U, T: Show & Eq & U> 

We get an upper bounds array of

T => [%Show, %Eq, U]

We should instead collapse these into a single point
So

T => [-{Show, Eq}, U]

We can likely accomplish this by contra-promote joining the constraints
There are likely some issues though around tuples.
Such as

fun ex<T: (L, R) & (R, L)>

And even worse with

fun ex<U: R, T: (L, U) & (U, L)>

Since you likely want

T => [(L, U), (U, L), (L & R, L & R)]

But if we can accomplish this simplification it will

  • Likely allow some simplifications for code when adding whenparams/conditional constraints
  • Open up statics on tparams/generics

Simplify algebraic method declarations. Rewrite inheritance for methods

Currently algebraic method declarations can be used for any valid child of the given type.
We should limit it to only children declared in the given class with 'children'

So

base class X1 {
  fun no(): void 
  | C1() -> void // SHOULD ERROR  
}
class C1() extends X1

base class X {
  children  = A() | B() 
  fun no(): void 
  | A() -> void // Valid!
  | C() -> void // SHOULD ERROR 
  | X _ -> void // Valid!
}
class C() extends X

Doing this will make a lot of the override rules MUCH simpler.
After this is done, the whole pass for method inheritance can probably be rewritten and simplified

skip_to_native script fails with LLVM 8

Fedora 30 ships with LLVM version 8 and apparently some command line options have changed.
llc should be invoked with -frame-pointer=all (I think) instead of -disable-fp-elim, otherwise this breaks the skip_to_native script and stalls the build.

[doc website]

👋 skiplang team,

I'm working at Algolia on the a project called DocSearch which goal is to enhance documentation websites with exhaustive, fast and relevant search. You might have seen DocSearch live already on websites like Bootstrap, ESLint or Babel.

As Docusaurus user, you would need to enable our search experience.

Looking forward to have it? Just update your siteConfig.js.:

apiKey: '7d79ea7bb5fdb8d123b2ed2c40d781a5',
  indexName: 'skiplang',

Feel free to reach me out for any issue.

We do offer free search analytics regarding the usage of your search. Send us the email of the ppl to add [email protected]

Skip examples

Hi. Are there any Skip examples out there? Programs which have:

  • FFI: JS/native interop
  • networked code
  • reading/writing files (is bundler app the best one?)

Github Template Files

This repository doesn't have some useful GitHub template files at the barest :

  • ISSUE TEMPLATE
  • PULL REQUEST TEMPLATE

which are templates that can assist contributors in communicating their intentions better,
I would love to work on this 😄

Add demo gif to README

Disclaimer: This is a bot

It looks like your repo is trending. The github_trending_videos Instgram account automatically shows the demo gifs of trending repos in Github.

Your README doesn't seem to have any demo gifs. Add one and the next time the parser runs it will pick it up and post it on its Instagram feed. If you don't want to just close this issue we won't bother you again.

if/then/else unexpected behavior

When we wrote
value = if (test) {v1} else {0.0} - v2;
We expect to have something equals to if (test) {v1 - v2} else {- v2} but it's equals to if (test) {v1} else {- v2};
A message should warn to use parentheses when if/then/else is used with operators .

sk still says "Written ..." even when the build failed

The client does not check that the binary file was really written before writing the message "Written ..." which leads to this very confusing case where we get a log that something was written when in reality nothing happened.

Docs : Missing Stdlib entries

If we go on matches function of String doc
Links to the regular expression module are available.
However, the documents targeted by these links are not accessible.

In addition, like Regexp, some other very useful modules like Subprocess, Math, ... are not present in the Stdlib documentation

High Performance JS Backend

Chatted with @josephsavona about this the other day.

Here's a plan which would result in a JS backend which had perf on par with hand written JS. Goals would be:

  • No boxing of primitives(bool, string, most numerics)
  • Inlining of most operations on primitives (!, +, -, *, …)

We would need to make some concessions:

  • only possible in an environment where monkey patching JS primitives was tolerable
  • No longer 100% compatibility between JSBE and NBE.
  • Duplicating/special casing more stdlib code between JSBE and NBE.

Work plan would look like:

  • Rename ‘Int’ to ‘Int64’ in stdlib, make ‘Int’ an alias for Int64 in NBE; make ‘Int’ an alias for Int32 in JSBE.
    • This will require code review of all Int code in stdlib. In particular bitwise operations, hashing, Int.Max/Min, divide, mod, which will need to be special cased for the JSBE.
  • Char becomes a 16-bit Unicode code unit in JSBE.
  • String becomes a sequence 16-bit Unicode code units in JSBE.
    • Requires code review and special casing of much of String and StringIterator.
  • No boxing for primitives:
    • Monkey patch JS builtins with all Skip methods/constants
    • JSBE can now not box builtins safely
  • Update JSBE code gen to inline most primitives now that primitives are no longer boxed.

The cool thing at this point is that primitives still behave like other Skip types. They may participate in traits and everything just works. Generic code which references primitives will dispatch through the monkey patched methods rather than inlined. Future work could also:

  • Special case any generic code which is instantiated to primitives to make generics on primitives run just as fast as non-generic versions of code.

Dead code removal (aka tree shaking) would be pretty trivial. So there’d be no penalty for using a large library in a small application.

To improve the programming model we could additionally:

  • Add a ‘dynamic’ or ‘object’ type to represent untyped JS objects
  • Add typed wrappers for HTML DOM types
  • Enable inline JS implementations of methods with an additional modifier on the method

RSS feed for blog

Hello!

Please add an RSS feed for your blog to make it easier to follow progress.

gcc compilation error

third-party/install/include/folly/synchronization/AtomicStruct.h:77:11: error: ‘void* memcpy(void*, const void*, size_t)’ copying an object of type ‘struct std::chrono::duration<long int, std::ratio<1, 1000000000> >’ with ‘private’ member ‘std::chrono::duration<long int, std::ratio<1, 1000000000> >::__r’ from an array of ‘using Raw = folly::_t<folly::detail::AtomicStructRaw<3> >’ {aka ‘long unsigned int’}; use assignment or copy-initialization instead [-Werror=class-memaccess]
     memcpy(&v, &d, sizeof(T));
     ~~~~~~^~~~~~~~~~~~~~~~~~~
In file included from third-party/install/include/folly/detail/Futex.h:21,
                 from third-party/install/include/folly/MicroLock.h:24,
                 from ../lkg/runtime/native/include/skip/InternTable.h:17,
                 from ../lkg/runtime/native/include/skip/objects.h:14,
                 from ../lkg/runtime/native/include/skip/String.h:13,
                 from ../lkg/runtime/native/include/skip/Exception.h:11,
                 from ../lkg/runtime/native/src/sk_standalone.cpp:27:
/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/include/g++-v8/chrono:302:14: note: ‘struct std::chrono::duration<long int, std::ratio<1, 1000000000> >’ declared here
       struct duration
              ^~~~~~~~
cc1plus: all warnings being treated as errors

Create a project file for src/native

skip/server lists all the source files in src/native, this is wrong.
We should create a library for src/native and then make both the skip_to_llvm binary and src/server use that library.

Need Help in getting started

Hello Everyone!

I'm a student and am interested in learning more about Skip, about how it works and probably build something on top of this. I'm new around here so how can I still contribute to this and learn about how programming languages are built.

Danke!

sk script needs longer ps output

If the paths to the executables are too long the 'sk' script can't find skip_server because the root path is truncated.

The two 'ps xa' lines should be 'ps xawww' to fix this.

Nuclide: Unable to find the "Language Settings-Skip-Directory"

Nuclide Version: 0.351.0.
Available language settings:
General, Clang, Remote Ctags, Flow, Hack, Infer AL, Obj-C, Ocaml, Python, Swift
But nothing for SKIP.

Is there an additional package to install to allow Nuclide to work with skip?
Or should we use a specific version of Nuclide?

Docs: different docker mount path at Getting Started part

when install, at step 3 run the Skip docker image

# Replace <skip-dir> with the directory you created above
docker run -it --user skip --mount type=bind,source=<skip-dir>,target=/home/skip/app verlaguet/skip

the mount target is /home/skip/app

at step 6, write, compile and run the example.sk program

# From docker container shell
> cd /home/skip/apps
> ls # should show example.sk created above
> ../skip/run.sh example.sk

now the mount target is /home/skip/apps

[Internal] Kill check_constraint_consistency in skipTypingUtils

When adding constraints we do some wonky joining of constraints so they are consistent with all tvars.

This is so all type variables have the same physical constraint when entering the NBE. (Physical constraints does not include any KTraits)

Ideally, when constraints are solved, solve each constraint individually with separate accs. After solving all of them, join the physical values contravariantly. This should provide physical values for all tvars that overlap without having to do this constraint forwarding.

skip_server doesn't watch for changes in the list of files referenced by globs in skip.project.json

Current problem as of commit b26a4e

If you have a skip.project.json which refers to globs of files ("foo/**") and you add or remove files then you need to restart the server to pick up the new files.

Example:

{
  "skipVersion": "1.0",
  "programUnits": {
    "test": {
      "sources": [
        "srcs/**",
      ],
      "kind": "Program",
    }
  }
}

Have a file srcs/file1.sk and run sk check to start the server and let it type-check.

Add a new file srcs/file2.sk and run sk check. It doesn't notice that file2.sk now exists until you sk restart.

[Internal] Solve Lambdas in Order Of Capture

Currently, we solve lambdas based on the order they were declared. This was likely done as solving one lambda could influence tvars that are used/captured by later lambdas.
But, it does not work well when one lambda is captured by another.
We should order lambda solving first by the capture order, i.e. if a lambda is captured by another lambda, solve the captured one first. And then defer to declared order

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.