Giter VIP home page Giter VIP logo

jeka's Introduction

Build Status Maven Central Twitter Follow

Important

JeKa 0.11.0 has been released!!!

This release brings major and drastic changes compared to previous JeKa versions.

The content of this page reflects the new version and does not apply to 0.10.x.

The existing IDE plugin for IntelliJ still works with Jeka 0.10.x but is no longer compatible with the new version. A new plugin for Jeka 0.11.x is under development.

The official documentation provides information for both versions and a migration guide.

Contribute

Are you a developer, technical writer, or user interested in making an impact? We invite you to join us in contributing code, documenting knowledge, or providing valuable feedback. Your participation is crucial in creating something great. At Jeka, every contribution counts, and every voice matters. Collaborate with like-minded individuals and help shape the future of our community.

Let’s build, learn, and grow together. Join us and make a difference.

See contribution page for starting.

What is JeKa ?

JeKa is a Java build tool for building or executing Java applications and scripts, directly from source code.

Its key features include:

  • JDKs Management: Automatically downloads and selects the appropriate JDKs. No need to have Java already installed on the host machine.

  • Direct App Execution: Run applications directly from their Git repository, providing a means to distribute Java applications as source.

  • Portable Builds: JeKa downloads everything needed for building your projects (JDKs, Maven deps, NodeJs, OpenAPI tooling, etc. including JeKa itself!)

  • Customizable and Extendable: JeKa can be configured with a concise property file for generic cases, or by Java code for specific needs. Also, JeKa provides a simple plugin mechanism that allows for easy extension.

  • Kotlin Support: Scripts or applications can also be implemented using the Kotlin language.

Use-cases

  • Use Java for scripting

    JeKa makes it ridiculously easy to write and execute scripts using the Java language. Write your automated tasks directly in Java, using third-party dependencies or not, and execute them from anywhere, without any setup.

  • Build projects - Create delivery pipelines

    Build projects and seamlessly combine scripts to create comprehensive CI/CD pipelines that can run anywhere, from IDE debugger to cloud CI/CD environments.

    JeKa can also complement other build tools such as Maven or Gradle to fulfill their missing features.

  • Deliver applications as sources

    JeKa can execute entire Java applications of any kind and size directly from their Git repository.

    Simply commit or tag repository to publish application.

  • Make Java fun for newcomers

    Say goodbye to learning legacy build tools and grappling with JDKs when starting with Java.

    Write directly Java code that can be built and executed from anywhere with minimal or zero setup.

  • Centralize build logic

    Define project build and CI/CD logic in one place, and reuse accross all your organization.

Examples

Run Java Applications directly from their Source Repository

Build and Test E2E

Reuse Build Logic

Combine with existing Build Tools


Other Examples of projects built with JeKa.

Getting Started

Visit following pages according your expectation :

KBeans

KBeans are JeKa components that expose functionnalities to the command line. They can also be conveniently activated and configured via properties, or via other KBeans.

Plugins generally contain one KBean, but they can contain zero or many.

Bundled KBeans

JeKa is bundled with KBeans covering : IDE integration (IntelliJ Eclipse), Java/Kotlin Project building, Maven publication, Git integration, Docker and more.

You can get a description of the functionalities provided by the KBeans by executing jeka --doc

Additionnaly JeKa offers high and low level api for dealing with dependency management, compilation, testing, Git, GPG signing, Scaffolding, Maven publication, Docker image maker, ...

External Plugins

External plugins require to be explicitly imported. They are hosted as jar file in Maven Central.

The following plugins are hosted in same monorepo then JeKa, and so are released in conjunction which means that we don't need to specify their version when importing.

The following plugins are maintained in their own repos.

Versioning

JeKa follows Semantic Versioning 2.0.

Community

Image

This project is supported by OW2 consortium.

Issues: https://github.com/jeka-dev/jeka/issues

Discussions: https://github.com/orgs/jeka-dev/discussions

Twitter: https://github.com/jeka-dev/jeka

Email support : [email protected]

mascot

jeka's People

Contributors

adabee94 avatar amottier avatar chocohead avatar cuchaz avatar dependabot[bot] avatar djeang avatar eliftopcuoglu avatar giorgiga avatar jeka-build avatar patricksan 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

jeka's Issues

JkImport doesn't allow file dependencies?

My build script,

@JkImport("path/to/jar.jar")
public class Build extends JkJavaBuild {
    ...
}

causes jerkar to throw an exception when it tries to compile the build classes:

java.lang.IllegalStateException: This dependency is type of org.jerkar.api.depmanagement.JkFileSystemDependency. Expecting JkModuleDependency.
	at org.jerkar.api.depmanagement.JkScopedDependency.withScopeMapping(JkScopedDependency.java:160)
	at org.jerkar.api.depmanagement.JkDependencies.withDefaultScopeMapping(JkDependencies.java:136)
	at org.jerkar.tool.Project.buildDefDependencies(Project.java:192)
	at org.jerkar.tool.Project.getBuildDefDependencyResolver(Project.java:279)
	at org.jerkar.tool.Project.compile(Project.java:84)
	at org.jerkar.tool.Project.compile(Project.java:72)
	at org.jerkar.tool.Project.execute(Project.java:121)
	at org.jerkar.tool.Main.main(Main.java:32)

The docs for JkImport annotation says it supports file dependencies, but the code seems to expect only module dependencies.

Injecting options in composite object

For now, options can be injected on field instances if the field is a String, File or primitive.
We would like to inject on composite object as well. so for say, the option is "foo.bar=3" then we look if there is a field called "foo" having a type that contains itself a field called "bar" to assign value on.

plugins not on build classpath?

I'm trying to write a plugin for jerkar, but I'm having trouble using it in my build script. It appears that plugins are not added to the build classpath? Here's a minimial working example:

build script:

package test;

import org.jerkar.tool.builtins.javabuild.JkJavaBuild;

public class Build extends JkJavaBuild { 
	
	public void doTest() {
		System.out.println("plugin: " + org.jerkar.plugins.jacoco.JkBuildPluginJacoco.class);
	}
}

output for jerkar doTest:

 _______           _                 
(_______)         | |                
     _ _____  ____| |  _ _____  ____ 
 _  | | ___ |/ ___) |_/ |____ |/ ___)
| |_| | ____| |   |  _ (/ ___ | |    
 \___/|_____)_|   |_| \_)_____|_|
                                     The 100% Java build tool.

Jerkar Version : 0.4.5
Working Directory : /path/to/Test
Java Home : /usr/lib/jvm/java-8-openjdk-amd64/jre
Java Version : 1.8.0_111, Oracle Corporation
Jerkar Home : /path/to/jerkar-v0.4.5
Jerkar User Home : /path/to/.jerkar
Jerkar Repository Cache : /path/to/.jerkar/cache/repo
Jerkar Classpath : /path/to/jerkar-v0.4.5/libs/ext/*:/path/to/jerkar-v0.4.5/libs/builtins/org.jerkar.plugins-jacoco.jar:/path/to/jerkar-v0.4.5/libs/builtins/org.jerkar.plugins-sonar.jar:/path/to/jerkar-v0.4.5/org.jerkar.core.jar
Command Line : doTest
Specified System Properties : none.
Standard Options : buildClass=null, verbose=false, silent=false
Options : none.

----------------------------------------
Compiling build classes for project Test
----------------------------------------
|  Resolving compilation classpath ... 
|   \ Done in 0.005 seconds.
|  Compiling 1 source files using options : -d /path/to/Test/build/output/def-bin -cp /path/to/jerkar-v0.4.5/org.jerkar.core.jar ... 
/path/to/Test/build/def/test/Build.java:8: error: package org.jerkar.plugins.jacoco does not exist
		System.out.println("plugin: " + org.jerkar.plugins.jacoco.JkBuildPluginJacoco.class);
		                                                         ^
1 error
|   \ Done in 0.342 seconds.

java.lang.IllegalStateException: Compilation failed.
	at org.jerkar.api.java.JkJavaCompiler.compile(JkJavaCompiler.java:279)
	at org.jerkar.tool.Project.compileBuild(Project.java:225)
	at org.jerkar.tool.Project.compile(Project.java:89)
	at org.jerkar.tool.Project.compile(Project.java:72)
	at org.jerkar.tool.Project.execute(Project.java:121)
	at org.jerkar.tool.Main.main(Main.java:32)
 _______     _ _            _    _ 
(_______)   (_) |          | |  | |
 _____ _____ _| | _____  __| |  | |
|  ___|____ | | || ___ |/ _  |  |_|
| |   / ___ | | || ____( (_| |   _ 
|_|   \_____|_|\_)_____)\____|  |_|
                             
                             
                                   Total build time : 0.493 seconds.

I noticed the "Jerkar Classpath" section shows the plugins correctly, but the "Compiling 1 source files using options" -cp flag only lists the core jar.

How can I make sure the plugins are on the build classpath? Do I need to add something to my build script to tell jerkar to include the plugins? Or is this a bug?

two different ways to configure packers

It looks like there are two different ways to configure JkJavaPacker that offer different functionalities. The two ways overlap in a lot of key features, but there are significant differences.

The JkJavaBuild.JkOptionPack method allows configuration of doFatJar and farJarSuffix, but not fatJarEntryFilter or other things like doJar doSources, etc.

The JkJavaPacker.Builder method allows configuration of doFatJar, farJarEntryFilter, and others like doJar, doSources, but not fatJarSuffix.

To fully configure the java packer, one must use both methods, which can conflict over options like doFatJar.

Here's an example:

public class Build extends JkJavaBuild {

	public Build() {
		pack.fatJarSuffix = null;
	}
	
	@Override
	protected JkJavaPacker createPacker() {
		return JkJavaPacker.builder(this)
			.includeVersion(true)
			.doJar(false)
			.doSources(false)
			.doFatJar(true)
			.build();
	}
}

This is pretty confusing. Maybe we could have a unified configuration system? Or ensure that both configuration systems offer the same functionality without conflicting?

Generated eclipse with inclusions/exclusion for resources

When we redefine resources like

 @Override
    public JkFileTreeSet editedResources() {
    	return super.editedResources().and(baseDir().include("LICENSE.txt"));
    }

we should get eclipse classpath mentioning inclusions/exclusions like : <classpathentry including="LICENSE.txt" kind="src" path=""/>

Remove plugins to a separated repository

The whole idea is much more than just a plugin for eclipse. Considere to remove the core to a main repository. Like maven has it own code and around it plugins.

IntellijJ integration

The modules today are extremely tied with Eclipse. IntelliJ is getting a lot of attention. It deserves to have a look.

Feature request: add arbitrary files to jars

Properly adding license/readme files to jars is tricky because license/readme files belong in the project root, not in any source/resources folder. So they don't get "compiled" into the classes folder and picked up by the usual jar packer methods.

Here's some workaround code I have that's working for now:

	@Override
	protected JkJavaPacker createPacker() {
		return JkJavaPacker.builder(this)
			.includeVersion(true)
			.doJar(false)
			.doSources(false)
			.doFatJar(true)
			.extraAction(new JkExtraPacking() {

				private File licenseFile = new File("LICENSE.txt");
				
				@Override
				public void process(JkJavaBuild build) {
					
					// move the fat jar to a temp file
					JkJavaPacker packer = createPacker();
					File tempFile = build.ouputDir("temp.jar");
					packer.fatJarFile().renameTo(tempFile);
					
					// make a new fat jar with the stuff we want to keep
					try (ZipFile zipIn = new ZipFile(tempFile)) {
						try (ZipOutputStream zipOut = JkUtilsZip.createZipOutputStream(packer.fatJarFile(), Deflater.DEFAULT_COMPRESSION)) {
							
							// add new entries
							JkUtilsZip.addZipEntry(zipOut, licenseFile, licenseFile.getName(), false);
						}
					} catch (IOException ex) {
						throw new RuntimeException(ex);
					}
				
					// cleanup
					tempFile.delete();
				}
			})
			.build();
	}

Maybe there's a way to tell the default packer to grab extra files while it's zipping the classes folder?

Thanks!

eclipse classpath builder adds wrong source folders

If my build script has these overrides on the JkJavaBuild template:

@Override
public JkFileTreeSet editedSources() {
	return JkFileTreeSet.of(file("src"));
}

@Override
public JkFileTreeSet editedResources() {
	return super.editedResources()
		.and(baseDir().andFilter(JkPathFilter.include("LICENSE.txt")));
}

Then the eclipse classpath has "." and "./src" as source folders, but only "src" should be the source folder. "." should not be a source folder.

I'm using jerkar compiled from commit a9faab6

I'm guessing this could be tricky to fix... because resource folders generally should be on the classpath. Except, I'm using the resource system to include LICENSE.txt in the jar file like you suggested, even though LICENSE.txt isn't really a resource and it doesn't need to be on the classpath.

Maybe we need a mechanism to include non-classpath files in Jars that is separate from the resource mechanism? Or teach the resource mechanism to not create source folders for file resources?

Proguard integration? Or maybe usage example for java-based build tools

Proguard is a popular minifier for Java. While specific integration between Proguard and jerkar would be nice, maybe tight integration with specific third-party tools isn't a goal for jerkar.

At the very least, maybe jerkar users would benefit from an example of how to use java-based third-party tools like Proguard. Since Proguard is java-based, using jerkar's dependency management tools is a really elegant way to "install" Proguard and use it in a project. Here's the code I'm using:

@Override
protected JkJavaPacker createPacker() {
	return JkJavaPacker.builder(this)
		.extraAction(new JkExtraPacking() {
			
			@Override
			public void process(JkJavaBuild build) {

				// get the proguard jar
				JkVersionedModule proguardMod = JkModuleId.of("net.sf.proguard", "proguard-base").version("5.1");
				JkDependencies proguardDeps = JkDependencies.builder()
					.on(proguardMod.moduleId(), proguardMod.version().name()).scope(COMPILE)
					.build();
				JkResolveResult resolved = dependencyResolver().withDependencies(proguardDeps).resolve(COMPILE);
				File proguardJar = resolved.filesOf(proguardMod.moduleId()).get(0);
				
				// move the fat jar to a temp file
				JkJavaPacker packer = createPacker();
				File tempFile = build.ouputDir("temp.jar");
				packer.fatJarFile().renameTo(tempFile);
				
				// run proguard
				JkProcess.of("java")
					.andParameters("-jar", proguardJar.getAbsolutePath())
					.andParameters("@proguard.conf")
					.andParameters("-injars", tempFile.getAbsolutePath())
					.andParameters("-outjars", packer.fatJarFile().getAbsolutePath())
					.failOnError(true)
					.runSync();
			
				// cleanup
				tempFile.delete();
			}
		})
		.build();
}

Maybe the docs could include an example like this? This code probably isn't robust enough to cover all the possible use cases, but maybe it's helpful to some. Feel free to modify it and make it better.

Improvement

Hi Jeff. Thanks for the quite valuable job you did for Jerkar so far.
Do not hesitate to suggest some improvement about the tool you feel relevant. I'll do my best to make it.
Btw, how do you use Jerkar ? Command line ? Eclipse GUI plugin ? Launching main methods within Eclipse ?

project dependencies not sorted correctly with module dependencies

Looks like project dependencies are always last?

for example:

public class Build extends JkJavaBuild {
	
	@JkProject("../other/project")
	JkJavaBuild otherProject;
	
	@Override
	public JkDependencies dependencies() {
		return JkDependencies.builder()
			.on(otherProject.asJavaDependency())
			.on("somewhere:somelib:1.0")
			.build();
	}
}

This always results in somelib being before otherProject on the classpath, instead of after.

BouncyCastle ClassNotfound when signing

The bug happen only when using Jerkar in command line. The nested bouncycastle jar is not accessible to create a classloader from => use similar mechanism than for the jacoco plugin.

crash on eclipse#generateFiles

Caused by: java.lang.NullPointerException
	at org.jerkar.tool.builtins.eclipse.DotClasspathGenerator.writeModuleEntry(DotClasspathGenerator.java:299)
	at org.jerkar.tool.builtins.eclipse.DotClasspathGenerator.writeDependenciesEntries(DotClasspathGenerator.java:281)
	at org.jerkar.tool.builtins.eclipse.DotClasspathGenerator.generateJava(DotClasspathGenerator.java:248)
	at org.jerkar.tool.builtins.eclipse.DotClasspathGenerator._generate(DotClasspathGenerator.java:109)
	at org.jerkar.tool.builtins.eclipse.DotClasspathGenerator.generate(DotClasspathGenerator.java:93)
	at org.jerkar.tool.builtins.eclipse.JkBuildPluginEclipse.generateFiles(JkBuildPluginEclipse.java:60)
	... 12 more

Took a quick look at the source, looks like there's a missing null check on jkAttachedArtifacts?

I think I can fix it, I'll work on a PR...

if no jar, fatJar doesn't get manifest

The following build script

public class Build extends JkJavaBuild {
	
	public Build() {
		manifest.mainClass = "mypackage.MyClass";
	}

	@Override
	protected JkJavaPacker createPacker() {
		return JkJavaPacker.builder(this)
			.doJar(false)
			.doFatJar(true)
			.build();
	}
}

causes the final jar file to not have a manifest (or the incorrect manifest from a dependency jar).

Dependency classpath order

Sometimes libraries provide implementations of the same classes, and which one gets loaded at runtime is determined by the classloader rules, which are based mainly on classpath order. Meaning, in order to get the dependencies loaded correctly, we need to be able to specify the classpath order for all the dependencies. So that library A correctly overrides library B by having an earlier classpath order, etc.

In eclipse, you can adjust the library order easily with the "up" and "down" buttons. Sadly, manual adjustments are overrwritten the next time jerkar is used to write the classpath. In the build script, the JkDependencies.Builder explicitly defines an order for dependencies (using the .on() chain), but the dependencies in the classpath appear to be sorted by type and name?

Is there a way to get the classpath builder to use an explicit order for dependencies so that class overrides are handled correctly?

I can use the "up" and "down" buttons after the classpath is generated, but that workaround is tedious.

Thanks!

No way to filter dependencies for fat jars?

When merging dependency jar files together to make a fat jar, sometimes we need to filter out files from the dependency jars or the fat jar will not work as intended. For example, signature files need to be removed or the fat jar could throw and exception:

java.lang.SecurityException: Invalid signature file digest for Manifest main attributes

I couldn't find a simple way in jakar to filter files from fat jars, but this workaround worked for my project. Basically, I open the fat jar as a zip file and delete anything I don't want.

	@Override
	protected JkJavaPacker createPacker() {
		return JkJavaPacker.builder(this)
			.doFatJar(true)
			.extraAction(new JkExtraPacking() {
				
				private String[] filteredExtensions = { "RSA", "DSA", "SF" };
				
				@Override
				public void process(JkJavaBuild build) {
					
					// move the fat jar to a temp file
					JkJavaPacker packer = JkJavaPacker.of(Build.this);
					File tempFile = build.ouputDir("temp.jar");
					packer.fatJarFile().renameTo(tempFile);
					
					// make a new fat jar with the stuff we want to keep
					try (ZipFile zipIn = new ZipFile(tempFile)) {
						try (ZipOutputStream zipOut = JkUtilsZip.createZipOutputStream(packer.fatJarFile(), Deflater.DEFAULT_COMPRESSION)) {
							Enumeration<? extends ZipEntry> entries = zipIn.entries();
							while (entries.hasMoreElements()) {
								ZipEntry entry = entries.nextElement();
								if (shouldSkip(entry)) {
									continue;
								}
								copy(zipIn, entry, zipOut);
							}
						}
					} catch (IOException ex) {
						throw new RuntimeException(ex);
					}
				
					// cleanup
					tempFile.delete();
				}

				private boolean shouldSkip(ZipEntry entry) {
					
					// skip directories
					if (entry.isDirectory()) {
						return true;
					}
					
					// skip things that break the jar
					for (String filteredExtension : filteredExtensions) {
						if (entry.getName().endsWith("." + filteredExtension)) {
							return true;
						}
					}
					
					return false;
				}
				
				private void copy(ZipFile zipIn, ZipEntry entry, ZipOutputStream out) {
					try {
						
						// start the entry
						out.putNextEntry(entry);
						
						// copy the data
						InputStream entryIn = zipIn.getInputStream(entry);
						final int bufSize = 2048;
						final BufferedInputStream buf = new BufferedInputStream(entryIn, bufSize);
						int count;
						final byte data[] = new byte[bufSize];
						while ((count = buf.read(data, 0, bufSize)) != -1) {
							out.write(data, 0, count);
						}
						buf.close();
						entryIn.close();
						
						// finish the entry
						out.closeEntry();
						
					} catch (final IOException e) {
						throw new RuntimeException(e);
					}
				}
			})
			.build();
	}

Maybe there could be a way to simplify the build process to make this kind of thing easier to do in the future?

Thanks for making such a great build system btw. I really like it so far. =)

Feature request: make a fat jar, but allow not calling it "fat"

In some of my projects, the only jar artifact is a fat jar that gets distributed directly to end users. I'd prefer to not tell users my jar is "fat". They don't really care about those kinds of details.

Here's a quick workaround that fixes the issue for me, but maybe some jerkar users would enjoy a simpler solution:

@Override
protected JkJavaPacker createPacker() {
	return JkJavaPacker.builder(this)
		.includeVersion(true)
		.doJar(false)
		.doSources(false)
		.doFatJar(true)
		.extraAction(new JkExtraPacking() {
			
			@Override
			public void process(JkJavaBuild build) {
				
				// rename the fat jar to the regular jar
				JkJavaPacker packer = createPacker();
				packer.fatJarFile().renameTo(packer.jarFile());
			}
		})
		.build();
}

One suggestion might be to allow the JkJavaBuild.JkOptionPack.fatJarSuffix to allow a null value. The null value here could signify that the "-fat" in the jar name should be omitted. Although, if JkJavaPacker.doJar(true), then maybe jerkar should warn about the naming conflict.

Thanks!

need way to put natives jars on classpath

Jerkar does a really good job at downloading jars for dependency libraries and build a classpath for them, but I can't figure out how to get it to download natives jars and add them to the classpath.

Natives jars are other jars attached to the module, like a source jar or a javadoc jar. Here's an example on Maven Central. I think the Jerkar dependency resolver calls them attached artifacts.

I can find in the code where the eclipse#generateFiles dependency resolver calls Ivy to download the sources and javadoc jars, but I can't find a way to configure Jerkar to tell Ivy to download the natives jars too and add them to the classpath.

I tried a couple things, but they didn't seem to have the effect I wanted:

JkScope scopeNativesLinux = JkScope.of("natives-linux");

@Override
public JkDependencies dependencies() {
	return JkDependencies.builder()
		.on("org.lwjgl:lwjgl:3.1.1")
		.on("org.lwjgl:lwjgl:3.1.1", scopeNativesLinux)
		.build();
}

Is there a way to do this if I had the right build script? Or do we need to modify Jerkar to do it?

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.