Coder Social home page Coder Social logo

google / cel-java Goto Github PK

View Code? Open in Web Editor NEW
81.0 9.0 15.0 1.86 MB

Fast, portable, non-Turing complete expression evaluation with gradual typing (Java)

Home Page: https://cel.dev

License: Apache License 2.0

Starlark 4.42% Java 95.30% Shell 0.12% ANTLR 0.16%
cel expression expression-language expression-parser java

cel-java's Introduction

Common Expression Language for Java

The Common Expression Language (CEL) is a non-Turing complete language designed for simplicity, speed, safety, and portability. CEL's C-like syntax looks nearly identical to equivalent expressions in C++, Go, Java, and TypeScript.

// Check whether a resource name starts with a group name.
resource.name.startsWith("/groups/"+auth.claims.group)
// Determine whether the request is in the permitted time window.
request.time - resource.age < duration("24h")
// Check whether all resource names in a list match a given filter.
auth.claims.email_verified && resources.all(r, r.startsWith(auth.claims.email))

A CEL "program" is a single expression. The examples have been tagged as java, go, and typescript within the markdown to showcase the commonality of the syntax.

CEL is ideal for lightweight expression evaluation when a fully sandboxed scripting language is too resource intensive.



Quick Start

Install

CEL-Java is available in Maven Central Repository. Download the JARs here or add the following to your build dependencies:

Maven (pom.xml):

<dependency>
  <groupId>dev.cel</groupId>
  <artifactId>cel</artifactId>
  <version>0.5.1</version>
</dependency>

Gradle

implementation 'dev.cel:cel:0.5.1'

Then run this example:

import dev.cel.common.CelAbstractSyntaxTree;
import dev.cel.common.CelValidationException;
import dev.cel.common.types.SimpleType;
import dev.cel.compiler.CelCompiler;
import dev.cel.compiler.CelCompilerFactory;
import dev.cel.runtime.CelEvaluationException;
import dev.cel.runtime.CelRuntime;
import dev.cel.runtime.CelRuntimeFactory;
import java.util.Map;

public class HelloWorld {
  // Construct the compilation and runtime environments.
  // These instances are immutable and thus trivially thread-safe and amenable to caching.
  private static final CelCompiler CEL_COMPILER =
      CelCompilerFactory.standardCelCompilerBuilder().addVar("my_var", SimpleType.STRING).build();
  private static final CelRuntime CEL_RUNTIME =
      CelRuntimeFactory.standardCelRuntimeBuilder().build();

  public void run() throws CelValidationException, CelEvaluationException {
    // Compile the expression into an Abstract Syntax Tree.
    CelAbstractSyntaxTree ast = CEL_COMPILER.compile("my_var + '!'").getAst();

    // Plan an executable program instance.
    CelRuntime.Program program = CEL_RUNTIME.createProgram(ast);

    // Evaluate the program with an input variable.
    String result = (String) program.eval(Map.of("my_var", "Hello World"));
    System.out.println(result); // 'Hello World!'
  }
}

Overview

Determine the variables and functions you want to provide to CEL. Parse and check an expression to make sure it's valid. Then evaluate the output AST against some input. Checking is optional, but strongly encouraged.

Environment Setup

Configuration for the entire CEL stack can be done all at once via the CelFactory.standardCelBuilder(), or can be composed into compilation and evaluation via the CelCompilerFactory and CelRuntimeFactory.

The simplest form of CEL usage is as follows:

Cel cel = CelFactory.standardCelBuilder().build();

More commonly, your application will want to configure type-checking separately from the runtime. Use CelCompilerFactory to construct a compilation environment and declare the types, macros, variables, and functions to use with your CEL application:

// Example environment for the following expression:
//    resource.name.startsWith('/groups/' + group)
CelCompiler cel = CelCompilerFactory.standardCelCompilerBuilder()
    .setStandardMacros(CelStandardMacro.HAS)
    .setContainer("google.rpc.context.AttributeContext")
    .addMessageTypes(AttributeContext.getDescriptor())
    .addVar("resource",
        StructTypeReference.create("google.rpc.context.AttributeContext.Resource"))
    .addVar("group", SimpleType.STRING)
    .build();

More information about the features which are supported on the builder may be found in the CelCompilerBuilder.

Parsing

Some CEL use cases only require parsing of an expression in order to be useful. For example, one example might want to check whether the expression contains any nested comprehensions, or possibly to pass the parsed expression to a C++ or Go binary for evaluation. Presently, Java does not support parse-only evaluation.

CelValidationResult parseResult =
    cel.parse("resource.name.startsWith('/groups/' + group)");
try {
  return parseResult.getAst();
} catch (CelValidationException e) {
  // Handle exception...
}

Checking

Type-checking is performed on CelAbstractSyntaxTree values to ensure that the expression is well formed and all variable and function references are defined.

Type-checking can be performed immediately after parsing an expression:

try {
  CelValidationResult parseResult =
      cel.parse("resource.name.startsWith('/groups/' + group)");
  CelValidationResult checkResult = cel.check(parseResult.getAst());
  return checkResult.getAst();
} catch (CelValidationException e) {
  // Handle exception...
}

Or, the parse and type-check can be combined into the compile call. This is likely the more common need.

CelValidationResult compileResult =
    cel.compile("resource.name.startsWith('/groups/' + group)");
try {
  return compileResult.getAst();
} catch (CelValidationException e) {
  // Handle exception...
}

Macros

Macros were introduced to support optional CEL features that might not be desired in all use cases without the syntactic burden and complexity such features might desire if they were part of the core CEL syntax. Macros are expanded at parse time and their expansions are type-checked at check time.

For example, when macros are enabled it is possible to support bounded iteration / fold operators. The macros all, exists, exists_one, filter, and map are particularly useful for evaluating a single predicate against list and map values.

// Ensure all tweets are less than 140 chars
tweets.all(t, t.size() <= 140)

The has macro is useful for unifying field presence testing logic across protobuf types and dynamic (JSON-like) types.

// Test whether the field is a non-default value if proto-based, or defined
// in the JSON case.
has(message.field)

Both cases traditionally require special syntax at the language level, but these features are exposed via macros in CEL.

Refer to the CEL Specification for full listings of available macros. To leverage them, simply set the desired macros via setStandardMacros on the builder:

CelCompiler.standardCelBuilder()
  .setStandardMacros(CelStandardMacro.STANDARD_MACROS)

Evaluation

Expressions can be evaluated using once they are type-checked/compiled by creating a CelRuntime.Program from a CelAbstractSyntaxTree:

CelRuntime celRuntime = CelRuntimeFactory.standardCelRuntimeBuilder().build();
try {
  CelRuntime.Program program = celRuntime.createProgram(compileResult.getAst());
  return program.eval(
      ImmutableMap.of(
          "resource", Resource.newBuilder().setName("/groups/").build(),
          "group", "admin"
      ));
} catch (CelEvaluationException e) {
  // Handle evaluation exceptions ...
}

The evaluation is thread-safe and side effect free thus many different inputs can be sent to the same cel.Program.

Partial State

In distributed apps it is not uncommon to have edge caches and central services. If possible, evaluation should happen at the edge, but it isn't always possible to know the full state required for all values and functions present in the CEL expression.

To improve the odds of successful evaluation with partial state, CEL uses commutative logical operators &&, ||. If an error or unknown value (not the same thing) is encountered on the left-hand side, the right-hand side is evaluated also to determine the outcome. While it is possible to implement evaluation with partial state without this feature, this method was chosen because it aligns with the semantics of SQL evaluation and because it's more robust to evaluation against dynamic data types such as JSON inputs.

In the following truth-table, the symbols <x> and <y> represent error or unknown values, with the ? indicating that the branch is not taken due to short-circuiting. When the result is <x, y> this means that the both args are possibly relevant to the result.

Expression Result
false && ? false
true && false false
<x> && false false
true && true true
true && <x> <x>
<x> && true <x>
<x> && <y> <x, y>
true || ? true
false || true true
<x> || true true
false || false false
false || <x> <x>
<x> || false <x>
<x> || <y> <x, y>

Errors

Parse and check errors have friendly error messages with pointers to where the issues occur in source:

ERROR: <input>:1:40: undefined field 'undefined'
    | TestAllTypes{single_int32: 1, undefined: 2}
    | .......................................^`,

Both the parsed and checked expressions contain source position information about each node that appears in the output AST. This information can be used to determine error locations at evaluation time as well.

Extensions

CEL-Java offers a suite of canonical extensions to support commonly needed features that falls outside the CEL specification.

Examples:

// String manipulation
'hello hello'.replace('he', 'we')     // returns 'wello wello'
'hello hello hello'.split(' ')     // returns ['hello', 'hello', 'hello']

// Math extensions
math.greatest(-42.0, -21.5, -100.0)   // -21.5
math.least(-42.0, -21.5, -100.0)   // -100.0

// Proto extensions
proto.getExt(msg, google.expr.proto2.test.int32_ext) // returns int value

// Local bindings
cel.bind(a, 'hello',
    cel.bind(b, 'world', a + b + b + a)) // "helloworldworldhello"

Common Questions

Why not JavaScript, Lua, or WASM?

JavaScript and Lua are rich languages that require sandboxing to execute safely. Sandboxing is costly and factors into the "what will I let users evaluate?" question heavily when the answer is anything more than O(n) complexity.

CEL evaluates linearly with respect to the size of the expression and the input being evaluated when macros are disabled. The only functions beyond the built-ins that may be invoked are provided by the host environment. While extension functions may be more complex, this is a choice by the application embedding CEL.

But, why not WASM? WASM is an excellent choice for certain applications and is far superior to embedded JavaScript and Lua, but it does not have support for garbage collection and non-primitive object types require semi-expensive calls across modules. In most cases CEL will be faster and just as portable for its intended use case, though for node.js and web-based execution CEL too may offer a WASM evaluator with direct to WASM compilation.

Do I need to Parse and Check?

Checking is an optional, but strongly suggested, step in CEL expression validation. It is sufficient in some cases to simply Parse and rely on the runtime bindings and error handling to do the right thing.

Where can I learn more about the language?

  • See the CEL Spec for the specification and conformance test suite.
  • Ask for support on the CEL Java Discuss Google group.

How can I contribute?

Dependencies

Java 8 or newer is required.

Library Details
Guava N/A
RE2/J N/A
Protocol Buffers Full or lite runtime
ANTLR4 Java runtime

License

Released under the Apache License.

Disclaimer: This is not an official Google product.

cel-java's People

Contributors

ckennelly avatar copybara-service[bot] avatar cpovirk avatar cushon avatar jcking avatar jnthntatum avatar l46kok avatar mikedanese avatar modhanami avatar smparkes 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cel-java's Issues

Evaluating unchecked expressions in CEL-Java

Describe the bug

In the README, under "Common Questions", it is written that:

Checking is an optional, but strongly suggested, step in CEL expression validation. It is sufficient in some cases to simply Parse and rely on the runtime bindings and error handling to do the right thing.

I believe there currently is no way around checking an expression before evaluation, as an expression must be checked before it can be turned into a program and evaluated. An attempt to create a program from an unchecked AST always results in an error "programs must be created from checked expressions".

Checking in turn requires declaring variables. However, in my particular use case, I cannot acquire a full list of variables to be used in expressions (there may be many, and acquiring variable values is costly, so I would only like to do this whenever required). I believe that the above should be achievable with an unchecked variable and CelVariableResolver.

It seems that this behavior deviates from CEL Go and also does not coincide with a similar question posted in the CEL Go group: https://groups.google.com/g/cel-go-discuss/c/PoyIrdFPwHM. Here, the possibility of evaluating unchecked expression is suggested. An (unrelated) Python implementation supports the same functionality: https://github.com/cloud-custodian/cel-python.

I file this as a bug as the current behavior seems to be conflicting with respect to the documentation.

To Reproduce

Check which components this affects:

  • parser
  • checker
  • runtime

When attempting to create a program from an unchecked AST:

var p = cel.createProgram(cel.parse("5").getAst()).eval();

Expected behavior

I expect to be able to evaluate the unchecked expression.

Additional context

None.

Maven packaging conflicts

I am running into package conflicts when building a project using bazel. Specifically, I have noted the following conflicts between these two packages:

I've been able to trace the conflicts based on the following:

There isn't an easy work around for this due to the fact that the maven dependency is hard coded into the cel-java files.

Support trivial comprehensions in constant folding

The expression cel.bind(a, 1, a + arg) is macro expanded into a trivial comprehension that doesn't loop and assigns 1 to the accum_var, so theoretically it can be folded into 1 + arg. Is that possible to support that case in the constant folding optimizer?

ConstantFoldingOptimizer fails when optimizing "in" operator over non-literal list

import dev.cel.bundle.CelFactory
import dev.cel.common.types.{ListType, SimpleType}
import dev.cel.optimizer.CelOptimizerFactory
import dev.cel.optimizer.optimizers.ConstantFoldingOptimizer


object Repro extends App {

  val cel = CelFactory
    .standardCelBuilder
    .addVar("arg", ListType.create(SimpleType.STRING))
    .build()

  val optimizer = CelOptimizerFactory.standardCelOptimizerBuilder(cel)
    .addAstOptimizers(ConstantFoldingOptimizer.INSTANCE)
    .build()


  optimizer.optimize(cel.compile("'abc' in arg").getAst)

}
Exception in thread "main" java.lang.ExceptionInInitializerError
	at Repro.main(Repro.scala)
Caused by: dev.cel.optimizer.CelOptimizationException: Optimization failure: IDENT
	at dev.cel.optimizer.CelOptimizerImpl.optimize(CelOptimizerImpl.java:52)
	at Repro$.<clinit>(Repro.scala:19)
	... 1 more
Caused by: java.lang.UnsupportedOperationException: IDENT
	at dev.cel.common.ast.AutoOneOf_CelExpr_ExprKind$Parent_.createList(AutoOneOf_CelExpr_ExprKind.java:96)
	at dev.cel.common.ast.CelExpr.createList(CelExpr.java:106)
	at dev.cel.optimizer.optimizers.ConstantFoldingOptimizer.maybePruneBranches(ConstantFoldingOptimizer.java:302)
	at dev.cel.optimizer.optimizers.ConstantFoldingOptimizer.optimize(ConstantFoldingOptimizer.java:84)
	at dev.cel.optimizer.CelOptimizerImpl.optimize(CelOptimizerImpl.java:45)
	... 2 more

[BUG] JsonType isn't in the jar file

Describe the bug
I see that we have a dev.cel.common.types.JsonType. But this does not seem to be found in the JAR file.

It looks like in the build file JsonType is in a separate build declaration, but it isn't required in the main cel build declaration. This may be the cause. Was this intended, or is it a bug?

Expected behavior
I should be able to import dev.cel.common.types.JsonType


cel is so awesome! Great work team.

CEL-Java?

I'm one of the maintainers of CEL-Java, which exists for quite a while now and is used in production. It is inspired by CEL-Go and has all the features CEL-Go has plus support for Jackson.

I wonder whether it would be beneficial to join forces and only have one implementation instead of two "competing" CEL-Java implementations. We're open to discuss options regarding a joint effort.

Calling `CelRuntimeBuilder.setStandardEnvironmentEnabled(false)` does not disable standard functions

Note

I see StandardFunctions.add() being called twice in CelRuntimeLegacyImpl.build(), once in DefaultDispatcher.create() unconditionally, and another when standardEnvironmentEnabled is true.

Are these intended? Or how can I disable the standard functions completely to achieve something like cel-go's NewCustomEnv?

DefaultDispatcher dispatcher = DefaultDispatcher.create(options, dynamicProto);
if (standardEnvironmentEnabled) {
StandardFunctions.add(dispatcher, dynamicProto, options);
}

public static DefaultDispatcher create(CelOptions celOptions, DynamicProto dynamicProto) {
DefaultDispatcher dispatcher = new DefaultDispatcher(celOptions);
StandardFunctions.add(dispatcher, dynamicProto, celOptions);
return dispatcher;
}

[BUG] Build failure on Mac OSX

Describe the bug
//publish:cel.publish doesn't build on Mac OS. Full error message is below.

I believe the problem is that parser/src/main/java/dev/cel/parser/CelParser.java conflicts with CELParser.java generated by the antlr build rule here:

antlr4_java_combined(
name = "cel_g4",
src = "CEL.g4",
listener = False,
package = "cel.parser.internal",
visitor = True,
)

And the default filesystem of MacOS does not have case sensitive file paths. This (https://support.apple.com/lt-lt/guide/disk-utility/dsku19ed921c/mac) looks like the most official documentation of this behavior, and I believe you need to do a full disk reformat to fix so not easy to workaround.

To Reproduce

On OSX:

$ bazel build //publish:cel.publish
INFO: Analyzed target //publish:cel.publish (0 packages loaded, 0 targets configured).
INFO: From Action publish/cel-docs.jar:
javadoc -cp ....
javadoc: warning - You have specified to generate frames, by using the --frames option.
The default is currently to not generate frames and the support for
frames will be removed in a future release.
To suppress this warning, remove the --frames option and avoid the use of frames.
/var/folders/f9/sc20dw5134n9vxn6np883f5c0000gp/T/unpacked-sources790206605151880537/dev/cel/parser/CELParser.java:24: error: interface CelParser is public, should be declared in a file named CelParser.java
public interface CelParser {
       ^
1 error
1 warning

ERROR: /Users/mike.danese/code/cel-java/publish/BUILD.bazel:52:12: output 'publish/cel-docs.jar' was not created
ERROR: /Users/mike.danese/code/cel-java/publish/BUILD.bazel:52:12: output 'publish/cel-docs-element-list-dir/element-list' was not created
ERROR: /Users/mike.danese/code/cel-java/publish/BUILD.bazel:52:12: Action publish/cel-docs.jar failed: not all outputs were created or valid
Target //publish:cel.publish failed to build
Use --verbose_failures to see the command lines of failed build steps.
INFO: Elapsed time: 2.182s, Critical Path: 2.03s
INFO: 2 processes: 1 internal, 1 darwin-sandbox.
ERROR: Build did NOT complete successfully

Query to map in DynamicMessage generated with JsonFormat.Parser cause ClassCastException

Hi, thanks for cel-java.

First of all, sorry if this is not the correct place to ask questions.

I tried to run a query to access to map against DynamicMessage which built with JsonFormat.Parser, then I get following exception.

Exception in thread "main" java.lang.ClassCastException: class com.google.protobuf.DynamicMessage cannot be cast to class com.google.protobuf.MapEntry (com.google.protobuf.DynamicMessage and com.google.protobuf.MapEntry are in unnamed module of loader 'app')

According to the stacktrace, it looks like that exception is happening here here 1. I run same code with debugger and stop program at that line, then Message built using JsonFormat.Parser seems to contain map entry as list of DynamicMessage and it can not cast to MapEntry.
I run same query against a Message which build with specific message's builder and put MapEntry using builder's putAll function. In this case, the query ended without exception.

I'm not sure whether this behavior is bug or not.
Are there any way to run a query to access a map against DynamicMessage generated with JsonFormat.Parser?
If currently this operation it not supported, are there any plan to support queries on objects that hold map as a List of DynamicMessage in the future?

To Reproduce

First, define following message and generate java source code with protoc command.

message Test {
  map<string, string> a = 1;
  Contents contents = 2;
  message Contents{
    map<string, string> b = 1;
  }
}

Then build a CelRuntime.Program instance with these code.

        CelBuilder celBuilder = CelFactory.standardCelBuilder()
                .addMessageTypes(Test.getDescriptor())
                .setOptions(CelOptions.newBuilder()
                        .enableCelValue(true)
                        .enableOptionalSyntax(true)
                        .build());
        Cel cel = celBuilder
                .addVar("a", MapType.create(SimpleType.STRING, SimpleType.STRING))
                .addVar("contents", StructTypeReference.create(Test.Contents.getDescriptor().getFullName()))
                .build();
        CelValidationResult validationResult = cel.compile("contents.b.size() > 0");
        CelRuntime.Program program = cel.createProgram(validationResult.getAst());

Finally, build a DynamicMessage value and query to it, then exception is thrown.

        String stringJson = """
                {
                    "a" : {
                        "test_key_a" : "test_value_a"
                    },
                    "contents" : {
                        "b" : {
                            "test_key_b_1" : "test_value_b_1",
                            "test_key_b_2" : "test_value_b_2"
                        }
                    }
                }
                """;
        DynamicMessage.Builder messageBuilder = DynamicMessage.newBuilder(Test.getDescriptor());
        JsonFormat.parser().ignoringUnknownFields().merge(stringJson, messageBuilder);
        // Following cause Exception : Exception in thread "main" java.lang.ClassCastException: class com.google.protobuf.DynamicMessage cannot be cast to class com.google.protobuf.MapEntry (com.google.protobuf.DynamicMessage and com.google.protobuf.MapEntry are in unnamed module of loader 'app')
        Object queryResult2 = program.eval(messageBuilder.build());

My code is located here, and all of stacktrace is following.

Exception in thread "main" java.lang.ClassCastException: class com.google.protobuf.DynamicMessage cannot be cast to class com.google.protobuf.MapEntry (com.google.protobuf.DynamicMessage and com.google.protobuf.MapEntry are in unnamed module of loader 'app')
	at dev.cel.common.internal.ProtoAdapter.adaptFieldToValue(ProtoAdapter.java:216)
	at dev.cel.runtime.Activation.fromProto(Activation.java:180)
	at dev.cel.runtime.CelRuntime$Program.eval(CelRuntime.java:59)
	at org.example.Main.main(Main.java:69)

Footnotes

  1. I edit because the link I wrote first was wrong โ†ฉ

Terrible performance when using dynamic messages

SinceLazyGeneratedMessageDefaultInstance.getDefaultInstance's result is not cached when class lookup fails, when working with dynamic messages it is called over and over, generating a ClassNotFoundExcpetion (along with its stack trace) resulting in a very slow evaluation

[BUG] Compile only Auto value processor library is included as a dependency

Describe the bug

Cel includes Auto value processor as a dependency in the pom.xml:

<dependency>
  <groupId>com.google.auto.value</groupId>
  <artifactId>auto-value</artifactId>
  <version>1.10.4</version>
</dependency>

This would be some big of a problem but Auto Value Processor itself is a shaded JAR and includes Kotlin Runtime among other things.

To Reproduce
Check which components this affects:

  • parser
  • checker
  • runtime

Expected behavior
Compile time only dependencies should not be part of the pom.xml.

Additional context

It will take some time to figure out CLAs etc with my company but I found out that removing this line:

"@maven//:com_google_auto_value_auto_value",
solves the issue at least for locally built pom.xml using the publish.sh script

Unparser

I see there's an "unparser" implementation (AST to text) but it is not published. Is there a way to publish it or is it not meant for client code use?

Example code

๐Ÿ‘‹ I'm looking to give this repository a shot but I'm finding that the examples in the README are incomplete and the Examples directory in the table of contents goes to a 404.

Do you happen to have a snippet of how to construct a CelProgram and evaluate a simple expression with an Activation?

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.