Giter Site home page Giter Site logo

paketo-buildpacks / executable-jar Goto Github PK

View Code? Open in Web Editor NEW
16.0 10.0 8.0 538 KB

A Cloud Native Buildpack that contributes a Process Type for executable JARs.

License: Apache License 2.0

Go 98.75% Shell 1.25%
cnb executable-jar jvm-applications hacktoberfest

executable-jar's Introduction

gcr.io/paketo-buildpacks/executable-jar

The Paketo Buildpack for Executable JAR is a Cloud Native Buildpack that contributes a Process Type for executable JARs.

Behavior

This buildpack will participate if any the following conditions are met:

  • <APPLICATION_ROOT>/META-INF/MANIFEST.MF contains a Main-Class entry
  • <APPLICATION_ROOT>/**/*.jar exists and that JAR has a /META-INF/MANIFEST.MF file which contains a Main-Class entry

When building a JVM application the buildpack will do the following:

  • Requests that a JRE be installed
  • If <APPLICATION_ROOT> contains an exploded JAR:
    • It contributes <APPLICATION_ROOT> to build and runtime $CLASSPATH
    • If <APPLICATION_ROOT>/META-INF/MANIFEST.MF Class-Path exists
      • Contributes entries to build and runtime $CLASSPATH
  • Contributes executable-jar, task, and web process types

When participating in the build of a native image application the buildpack will:

  • If <APPLICATION_ROOT> contains an exploded JAR:
    • Contributes <APPLICATION_ROOT> to build-time $CLASSPATH
    • If <APPLICATION_ROOT>/META-INF/MANIFEST.MF Class-Path exists
      • Contributes entries to build-time $CLASSPATH

When $BP_LIVE_RELOAD_ENABLE is true:

  • Requests that watchexec be installed
  • Contributes reload process type

Configuration

Environment Variable Description
$BP_LIVE_RELOAD_ENABLED Enable live process reloading. Defaults to false.
$BP_EXECUTABLE_JAR_LOCATION An optional glob to specify the JAR used as an entrypoint. Defaults to "", which causes the buildpack to do a breadth-first search for the first executable JAR it finds.

License

This buildpack is released under version 2.0 of the Apache License.

executable-jar's People

Contributors

anthonydahanne avatar c0d1ngm0nk3y avatar christopherclark avatar dependabot[bot] avatar dmikusa avatar ekcasey avatar matejvasek avatar nebhale avatar paketo-bot avatar pivotal-david-osullivan avatar ryanmoran avatar sap-ali avatar saschaschwarze0 avatar twoseat avatar

Stargazers

 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

executable-jar's Issues

watchexec not work for java -jar

I config BP_LIVE_RELOAD_ENABLED env to enable live process reloading, then create a Procfile to determine my process type. After that, deploy the app to k8s

Procfile:

web: watchexec -r --shell=none -- java -jar /byos/1019/echo-app-mason-with-log4j-0.0.1-SNAPSHOT.jar

Build logs

Paketo Buildpack for Procfile 5.4.0
  https://github.com/paketo-buildpacks/procfile
  Process types:
    web: watchexec -r --shell=none -- java -jar /byos/1019/echo-app-mason-with-log4j-0.0.1-SNAPSHOT.jar

exec to pod, shows process:

cnb@app-newre-default-9-d5f5844c4-wmd7z:/byos/1019$ ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
cnb          1     0  0 07:25 ?        00:00:00 watchexec -r --shell=none -- java -jar /byos/1019/echo-app-mason-with-log4j-0.0.1-SNAPSHOT
cnb        101     1  1 07:25 ?        00:00:32 java -jar /byos/1019/echo-app-mason-with-log4j-0.0.1-SNAPSHOT.jar
cnb        225     0  0 07:38 pts/0    00:00:00 bash

Then I change my jar file and update some files, then the container doesn't restart. but the jar file has already been updated.

image

Another question

If I deploy the sprint boot project to a cloud platform, like azure, what's the usage to watch a workspace?
E.g
If I watch a sprint boot project

 watchexec -r --shell=none -- java org.springframework.boot.loader.JarLauncher

the workspace is default /workspace,

cnb@app-dynamic-default-11-96d7c598-zdzld:/workspace$ ls
BOOT-INF  META-INF  org

I can't update the class file in the /workspace directly, so what's the meaning of watching this?

Expected Behavior

the jar file update should be detected and restart the container

Current Behavior

the jar file changed but the container is not restarted

Possible Solution

Steps to Reproduce

Motivations

Live reload command fails for projects built with Gradle

What happened?

When building an image from a Java app that uses Gradle and enabling live reload with BP_LIVE_RELOAD_ENABLED=true, the reload command in the image fails.

When building the image, the reload process type is added as expected:

Paketo Watchexec Buildpack 2.4.0
  https://github.com/paketo-buildpacks/watchexec

Paketo Executable JAR Buildpack 6.2.2
  https://github.com/paketo-buildpacks/executable-jar
  Process types:
    executable-jar: java -jar /workspace/example-java-0.0.1-SNAPSHOT.jar (direct)
    reload:         watchexec -r java -jar /workspace/example-java-0.0.1-SNAPSHOT.jar (direct)
    task:           java -jar /workspace/example-java-0.0.1-SNAPSHOT.jar (direct)
    web:            java -jar /workspace/example-java-0.0.1-SNAPSHOT.jar (direct)

When running the image, the watchexec command in the reload process throws an error:

Enabling Java Native Memory Tracking
Adding 128 container CA certificates to JVM truststore
error: Found argument '-j' which wasn't expected, or isn't valid in this context

USAGE:
    watchexec <command>... --restart

For more information try --help

Build Configuration

  • Generate a trivial Spring Boot app that uses Gradle, using this start.spring.io example.
  • Create a Tiltfile as shown in the PR that introduced the live reload process type:
custom_build(
    'example-java-image',
    'pack build --builder=paketobuildpacks/builder:base --pull-policy=if-not-present -e BP_LIVE_RELOAD_ENABLED=true example-java-image:dev',
    ['build.gradle, './build.classes'],
    live_update = [
        sync('./build/classes', '/workspace/BOOT-INF/classes'),
    ],
    tag="dev"

)
k8s_yaml('kubernetes.yaml')
k8s_resource('example-java', port_forwards=8000)
  • Create a kubernetes.yaml for the Tilt deployment.

After successfully building the image, the Tilt deployment will fail with the watchexec error shown above.

Checklist

  • I have included log output.
  • The log output includes an error message.
  • I have included steps for reproduction.

SBoM of Docker image contains test dependencies

Hi,

We opened this issue in the context of the Spring Boot project, but according to the developers, the issue lies in the executable-jar framework,

Expected Behavior

The SBoM should not contain test dependencies from the Maven pom file in general.

Current Behavior

When creating the Docker image for a Maven project, the resulting SBoM files contain entries for the test dependencies.

Motivations

This is an issue as vulnerability scanners use these meta files to check the image for security violations. In our case this leads to various false positives that have to be checked manually.

Thank you and best regards

Nils

Packing a single executable fat-Jar does not work

Hi team,

We have a runnable fat-jar and when I tried to configure the buildpack to simply pack it and run it, I keep running into the buildpack detecting it as an exploded Jar. In other words, I could not configure it to reach

jarPath, props, err = findExecutableJAR(appPath, executableJarGlob)
. I forked the repository and commented out the exploded Jar detection if and everything worked fine.

Expected Behavior

Allow packing a single executable fat-Jar.

Current Behavior

Only performs to pack an exploded Jar.

Possible Solution

I can see a few possibilities to fix it:

  • Adjust the condition that detects whether it is an exploded Jar
  • Make the buildpack participation conditions disjuctive, that is, if a runnable jar is detected, then it is a jar, if not, require a MANIFEST.MF and treat it as exploded Jar

Steps to Reproduce

  1. Create an executable far-Jar
  2. Define project.toml as:
[_]
schema-version = "0.2"
id = "com.test.jar"
name = "Test Fat Jar"

[[io.buildpacks.group]]
uri = "gcr.io/paketo-buildpacks/sap-machine"

[[io.buildpacks.group]]
uri = "gcr.io/paketo-buildpacks/syft"

[[io.buildpacks.group]]
uri = "gcr.io/paketo-buildpacks/executable-jar"

[[io.buildpacks.build.env]]
name = "BP_JVM_VERSION"
value = "21"
  1. [this step is required only due to the activation conditions] Extract jar's MANIFEST.MF into META-INF/MANIFEST.MF
  2. Build the package by running:
pack build example:latest \
  --descriptor project.toml \
  --builder paketobuildpacks/builder:base
  1. Run the image by:
docker run --name example --rm example
  1. The following error is received:
Error: Could not find or load main class [class name in the extracted MANIFEST.MF]
Caused by: java.lang.ClassNotFoundException: [class name in the extracted MANIFEST.MF]

Looking at the generated image layer, the contents of the layer seem as expected:

Permission     UID:GID       Size  Filetree                                     
drwxrwxrwx   1000:1000      76 MB  └── workspace                                
drwxr-xr-x   1000:1000       68 B      ├── META-INF                             
-rw-rw----   1000:1000       68 B      │   └── MANIFEST.MF                      
-rw-r--r--   1000:1000      76 MB      └── example.jar

Motivations

I cannot use the buildpack to package my jar file and for me renders the buildpack unusable, however, as I have read in the tests, this is one of the desired usecases of using this buildpack. It would be great if we can either fix the issue or clarify the detailed conditions in which it can be used in such a scenario.

Implement RFC0044: Disable SBOM

Describe the Enhancement

This buildpack should opt-in to allowing users to disable SBOM generation. In doing so, it should conform to RFC044.

When BP_DISABLE_SBOM is set to true, buildpacks that allow SBOM to be omitted from their output should refrain from generating or attaching an SBOM in their outputs. This would apply to both new (Syft, CycloneDX, and SPDX formats) and old (label) SBOM outputs.

Additionally, when this variable is set to true a buildpack should set an image label of io.paketo.sbom.disabled to true. This label interface would allow downstream consumers of the image to understand that SBOM generation had been explicitly disabled.

Possible Solution

Motivation

SBOM generation can take substantial time. There may also be other reasons for wanting this functionality to be disabled.

Convert internal test suite

Convert to using the standard for our project test suite and Gomega matchers for the recently committed BFS internal package.

Support reloadable process types on Tiny

What happened?

The watchexec buildpack has a PR to include a version of watchexec that runs on Tiny. Unfortunately, in recent versions of watchexec they default to running the watched process through a shell, which fails on Tiny where there are no shells.

To make this work, we need to generate a different process type when on the tiny stack. It simply needs to include the --shell none arguments. This tells watchexec to not use a shell.

In the meantime, if someone is stuck on this, they can simply append --shell none to the start command and it should work as well.

docker run -it apps/maven --shell none

The launcher takes --shell none and passed it through as arguments to the default process type, which is watchexec.

permission denied error when building spring boot application image

What happened?

I use spring-boot-maven-plugin in my Spring Boot application and build Docker image with build-image goal
It uses Paketo Buildpacks under the hood
In my CI (based on Jenkins) some time ago i started to receive this error during build:

14:57:41  [INFO]     [creator]     Paketo Executable JAR Buildpack 6.0.1
14:57:41  [INFO]     [creator]       unable to create Build SBoM 
14:57:41  [INFO]     [creator]       unable to run syft
14:57:41  [INFO]     [creator]       unable to run syft on directory /workspace
14:57:41  [INFO]     [creator]       unable to start PTY
14:57:41  [INFO]     [creator]       fork/exec /layers/paketo-buildpacks_syft/syft/bin/syft: permission denied
14:57:41  [INFO]     [creator]     ERROR: failed to build: exit status 1

I tried to build with "-X" but cannot find any usefull information about it
Full debug run log is attached: maven-build-output.txt

I think that there may be some problem on agent but i cannot get what it is by error message
I tried to prune all docker containers, volumes, images, caches, etc. on agent
What else can i do to detect and fix the problem?

Build Configuration

  • Spring Boot 2.6.1 with spring-boot-maven-plugin
  • Paketo Executable JAR Buildpack 6.0.1 (under the hood)

Checklist

  • I have included log output.
  • The log output includes an error message.
  • I have included steps for reproduction.

Support for multiple jars

As of now executable-jar allows only one jar (and that single jar is extracted to application path).
We should allow multiple jars.

Provide Way to Handle Multiple Jars with Main-Class Entries

Sometimes projects have dependencies containing Main-Class entries in their manifests. Since this buildpack picks the first Jar found with such an entry, this can lead to not picking the right Main-Class. Perhaps an env var could be used to specify a glob for the desired Jar containing the right Main-Class.

Enable detect to support multiple jar files

What happened?

The executable jar buildpack will detect if you either:

  1. Build from source code and the build output is either a single executable JAR or multiple files that only contain a single executable JAR
  2. Build with a pre-compiled asset that is a single executable JAR file

In some cases, you may want to compile locally but build an image from a directory or archive that is not an executable JAR. This is not presently possible because detect.go looks for /workspace/META-INF/MANIFEST.MF, which will only exist if the asset being provided to build is an executable JAR.

This enhancement request is to have detect also look at the present workspace and see if either a.) the workspace itself has a manifest or if b.) it can identify a single executable JAR file in the workspace.

Warning about SBOM reported.

What happened?

Warning about SBOM reported when running bootBuildImage with spring-boot-gradle-plugin.
The message is as follows.

  • Warning: this buildpack is including both old and new format SBOM information, which is an invalid state. To prevent the lifecycle from failing, libcnb is discarding the old SBOM information.

Build Configuration

This problem is reproduced at least in versions that refer to Executable JAR Buildpack 6.0.0.

A project that can reproduce the problem has been pushed as follows.
https://github.com/k163377/spring-boot-build-image-warn-sandbox

The complete log is shown as follows.

complete log
17:53:37: Executing 'bootBuildImage'...

> Task :compileKotlin UP-TO-DATE
> Task :compileJava NO-SOURCE
> Task :processResources NO-SOURCE
> Task :classes UP-TO-DATE
> Task :bootJarMainClassName UP-TO-DATE
> Task :bootJar UP-TO-DATE

> Task :bootBuildImage
Building image 'docker.io/library/spring-boot-build-image-warn-sandbox:1.0-SNAPSHOT'

 > Pulling builder image 'docker.io/paketobuildpacks/builder:base' ..................................................
 > Pulled builder image 'paketobuildpacks/builder@sha256:988d9d956b62d18a828ea9deab5586d5a307becae23c72c76746c8307048d56f'
 > Pulling run image 'docker.io/paketobuildpacks/run:base-cnb' ..................................................
 > Pulled run image 'paketobuildpacks/run@sha256:b1e8add4fc569e37085342cd05186d17cb81e128ee60fd9fd633337e25ac7808'
 > Executing lifecycle version v0.13.0
 > Using build cache volume 'pack-cache-3819609661d9.build'

 > Running creator
    [creator]     ===> DETECTING
    [creator]     6 of 19 buildpacks participating
    [creator]     paketo-buildpacks/ca-certificates   3.0.0
    [creator]     paketo-buildpacks/bellsoft-liberica 9.0.0
    [creator]     paketo-buildpacks/syft              1.0.0
    [creator]     paketo-buildpacks/executable-jar    6.0.0
    [creator]     paketo-buildpacks/dist-zip          5.0.0
    [creator]     paketo-buildpacks/spring-boot       5.0.0
    [creator]     ===> ANALYZING
    [creator]     Restoring metadata for "paketo-buildpacks/ca-certificates:helper" from app image
    [creator]     Restoring metadata for "paketo-buildpacks/bellsoft-liberica:jre" from app image
    [creator]     Restoring metadata for "paketo-buildpacks/bellsoft-liberica:helper" from app image
    [creator]     Restoring metadata for "paketo-buildpacks/bellsoft-liberica:java-security-properties" from app image
    [creator]     Restoring metadata for "paketo-buildpacks/syft:syft" from cache
    [creator]     Restoring metadata for "paketo-buildpacks/spring-boot:helper" from app image
    [creator]     Restoring metadata for "paketo-buildpacks/spring-boot:spring-cloud-bindings" from app image
    [creator]     Restoring metadata for "paketo-buildpacks/spring-boot:web-application-type" from app image
    [creator]     ===> RESTORING
    [creator]     Restoring data for "paketo-buildpacks/syft:syft" from cache
    [creator]     ===> BUILDING
    [creator]     
    [creator]     Paketo CA Certificates Buildpack 3.0.0
    [creator]       https://github.com/paketo-buildpacks/ca-certificates
    [creator]       Launch Helper: Reusing cached layer
    [creator]     
    [creator]     Paketo BellSoft Liberica Buildpack 9.0.0
    [creator]       https://github.com/paketo-buildpacks/bellsoft-liberica
    [creator]       Build Configuration:
    [creator]         $BP_JVM_TYPE                 JRE             the JVM type - JDK or JRE
    [creator]         $BP_JVM_VERSION              17.*            the Java version
    [creator]       Launch Configuration:
    [creator]         $BPL_DEBUG_ENABLED           false           enables Java remote debugging support
    [creator]         $BPL_DEBUG_PORT              8000            configure the remote debugging port
    [creator]         $BPL_DEBUG_SUSPEND           false           configure whether to suspend execution until a debugger has attached
    [creator]         $BPL_HEAP_DUMP_PATH                          write heap dumps on error to this path
    [creator]         $BPL_JAVA_NMT_ENABLED        true            enables Java Native Memory Tracking (NMT)
    [creator]         $BPL_JAVA_NMT_LEVEL          summary         configure level of NMT, summary or detail
    [creator]         $BPL_JFR_ARGS                                configure custom Java Flight Recording (JFR) arguments
    [creator]         $BPL_JFR_ENABLED             false           enables Java Flight Recording (JFR)
    [creator]         $BPL_JMX_ENABLED             false           enables Java Management Extensions (JMX)
    [creator]         $BPL_JMX_PORT                5000            configure the JMX port
    [creator]         $BPL_JVM_HEAD_ROOM           0               the headroom in memory calculation
    [creator]         $BPL_JVM_LOADED_CLASS_COUNT  35% of classes  the number of loaded classes in memory calculation
    [creator]         $BPL_JVM_THREAD_COUNT        250             the number of threads in memory calculation
    [creator]         $JAVA_TOOL_OPTIONS                           the JVM launch flags
    [creator]       BellSoft Liberica JRE 17.0.1: Contributing to layer
    [creator]         Downloading from https://github.com/bell-sw/Liberica/releases/download/17.0.1+12/bellsoft-jre17.0.1+12-linux-amd64.tar.gz
    [creator]         Verifying checksum
    [creator]         Expanding to /layers/paketo-buildpacks_bellsoft-liberica/jre
    [creator]         Adding 128 container CA certificates to JVM truststore
    [creator]         Writing env.launch/BPI_APPLICATION_PATH.default
    [creator]         Writing env.launch/BPI_JVM_CACERTS.default
    [creator]         Writing env.launch/BPI_JVM_CLASS_COUNT.default
    [creator]         Writing env.launch/BPI_JVM_SECURITY_PROVIDERS.default
    [creator]         Writing env.launch/JAVA_HOME.default
    [creator]         Writing env.launch/JAVA_TOOL_OPTIONS.append
    [creator]         Writing env.launch/JAVA_TOOL_OPTIONS.delim
    [creator]         Writing env.launch/MALLOC_ARENA_MAX.default
    [creator]       Launch Helper: Reusing cached layer
    [creator]       Java Security Properties: Reusing cached layer
    [creator]     
    [creator]     Paketo Syft Buildpack 1.0.0
    [creator]       https://github.com/paketo-buildpacks/syft
    [creator]     
    [creator]     Paketo Executable JAR Buildpack 6.0.0
    [creator]       https://github.com/paketo-buildpacks/executable-jar
    [creator]       Class Path: Contributing to layer
    [creator]         Writing env/CLASSPATH.delim
    [creator]         Writing env/CLASSPATH.prepend
    [creator]     Warning: this buildpack is including both old and new format SBOM information, which is an invalid state. To prevent the lifecycle from failing, libcnb is discarding the old SBOM information.
    [creator]       Process types:
    [creator]         executable-jar: java org.springframework.boot.loader.JarLauncher (direct)
    [creator]         task:           java org.springframework.boot.loader.JarLauncher (direct)
    [creator]         web:            java org.springframework.boot.loader.JarLauncher (direct)
    [creator]     
    [creator]     Paketo Spring Boot Buildpack 5.0.0
    [creator]       https://github.com/paketo-buildpacks/spring-boot
    [creator]       Creating slices from layers index
    [creator]         dependencies
    [creator]         spring-boot-loader
    [creator]         snapshot-dependencies
    [creator]         application
    [creator]       Launch Helper: Reusing cached layer
    [creator]       Spring Cloud Bindings 1.8.0: Reusing cached layer
    [creator]       Web Application Type: Reusing cached layer
    [creator]     Warning: this buildpack is including both old and new format SBOM information, which is an invalid state. To prevent the lifecycle from failing, libcnb is discarding the old SBOM information.
    [creator]       4 application slices
    [creator]       Image labels:
    [creator]         org.springframework.boot.version
    [creator]     ===> EXPORTING
    [creator]     Reusing layer 'paketo-buildpacks/ca-certificates:helper'
    [creator]     Reusing layer 'paketo-buildpacks/bellsoft-liberica:helper'
    [creator]     Reusing layer 'paketo-buildpacks/bellsoft-liberica:java-security-properties'
    [creator]     Adding layer 'paketo-buildpacks/bellsoft-liberica:jre'
    [creator]     Reusing layer 'paketo-buildpacks/executable-jar:classpath'
    [creator]     Reusing layer 'paketo-buildpacks/spring-boot:helper'
    [creator]     Reusing layer 'paketo-buildpacks/spring-boot:spring-cloud-bindings'
    [creator]     Reusing layer 'paketo-buildpacks/spring-boot:web-application-type'
    [creator]     Reusing 5/5 app layer(s)
    [creator]     Reusing layer 'launcher'
    [creator]     Reusing layer 'config'
    [creator]     Reusing layer 'process-types'
    [creator]     Adding label 'io.buildpacks.lifecycle.metadata'
    [creator]     Adding label 'io.buildpacks.build.metadata'
    [creator]     Adding label 'io.buildpacks.project.metadata'
    [creator]     Adding label 'org.springframework.boot.version'
    [creator]     Setting default process type 'web'
    [creator]     Saving docker.io/library/spring-boot-build-image-warn-sandbox:1.0-SNAPSHOT...
    [creator]     *** Images (f14191421637):
    [creator]           docker.io/library/spring-boot-build-image-warn-sandbox:1.0-SNAPSHOT
    [creator]     Reusing cache layer 'paketo-buildpacks/syft:syft'

Successfully built image 'docker.io/library/spring-boot-build-image-warn-sandbox:1.0-SNAPSHOT'


BUILD SUCCESSFUL in 4m 7s
4 actionable tasks: 1 executed, 3 up-to-date
17:57:44: Execution finished 'bootBuildImage'.

Checklist

  • I have included log output.
  • The log output includes an error message.
  • I have included steps for reproduction.

Allow the buildpack to skip

Describe the Enhancement

In some cases, you may have an off-the-shelf WAR file that you are trying to deploy. It may contain a Main-Class entry for "reasons" and because it's off-the-shelf you cannot change that easily. In this scenario, the executable-jar buildpack will run first and see the Main-Class and incorrectly try to run it.

We should have a way to override the default behavior to tell executable-jar to skip.

Possible Solution

Add an env variable that disables the executable-jar buildpack, like BP_EXECUTABLE_JAR_DISABLED. It would default to false. When true, it would just cause the buildpack to fail detection, which in turn would make it skip.

Motivation

See Above.

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.