Coder Social home page Coder Social logo

siom79 / japicmp Goto Github PK

View Code? Open in Web Editor NEW
680.0 24.0 107.0 8.41 MB

Comparison of two versions of a jar archive

Home Page: https://siom79.github.io/japicmp

License: Apache License 2.0

Java 99.18% CSS 0.21% Groovy 0.05% Python 0.14% Shell 0.03% HTML 0.39%
java api-documentation api-management change-tracker change-management comparison

japicmp's People

Contributors

243826 avatar badlogic avatar chonton avatar chtompki avatar cstamas avatar dependabot[bot] avatar dinomite avatar earcam avatar eldur avatar goooler avatar guillermocalvo avatar io7m avatar johnjohndoe avatar kingle avatar marcono1234 avatar mike-duigou avatar mikerscher avatar mmois avatar ntherning avatar rjatkins avatar rmetzger avatar roomsg avatar rsvoboda avatar scordio avatar siom79 avatar swankjesse avatar tombentley avatar twogee avatar unaszole avatar zentol 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

japicmp's Issues

mvn plugin fails if 'mvn verify' is ran consecutively.

The problem is probably the directory which the plugin creates and tries to recreate on subsequent runs. This problem does not exist if 'clean' goal is given every single time which first deletes the target folder of the mvn project.

Show differences in javadoc comments

The user should be able to provide the source code for both versions (either on the command line as source jar or the maven plugin loads it if available from the repository) and japicmp should in this case additionally also compare the javadoc comments.

If the javadoc comment has changed this may indicate that the behavior of the method has changed. For modified methods is also shows whether the javadoc comment has been adjusted.

Sorted output in reports

The ordering of classes and methods in reports appears to be random. Please sort them so that reports have a consistent order.

The functionality of japicmp should be available as a maven plugin

In order to compare two versions of an artifact during the build process, the functionality of japicmp should be available per maven plugin.

The command line options should be available as maven elements.

There should be an option to break the build every time a change in the API has been detected.

Fails to recognize changed superclass

We have integrated japicmp into Groovy to integrate binary compatibility checks. See [1] and [2].

However, it fails to recognize the change of superclass. To reproduce:

git clone https://github.com/melix/japicmp-bugs.git
cd changed-superclass
./gradlew japicmp

The build should fail, but it doesn't, because japicmp failed to recognize the new superclass and says the class is unchanged.

[1] https://github.com/melix/japicmp-gradle-plugin
[2] groovy/groovy-core@29e3bd4

Detect enum declaration order changes

Changing the declaration order of enums, which could break code relying on the value of Enum#ordinal(), should perhaps be detected as a breaking change.

HTML output improvements

In my HTML output I noticed any class with changes has an additional "Superclass UNCHANGED" table, even with the -m option passed. This takes up a lot of space in large diffs and is just noise. Ignoring the -m option seems like a bug.

Wishlist improvements:

  • Support maven site reports - This would be a nice feature for those of us that still generate full maven sites for reports like this. The only issue is CSS which might be better in separate file anyway so people can use their own CSS.
  • Hide Superclass when its a new class - Pointing out that a new class extends Object doesn't really seem useful. The only debatable useful instance is when extending anything else, but it just seems like noise since you'll still need Javadoc or IDE's to find out what org.random.project.SomeClass actually does.
  • Add generation date - Since the full path of the jars is already at the top, adding a "generated date" line could be useful for tracking snapshots and versions since the compared jars aren't always static.

Thanks for finishing the HTML reports though, its still pretty useful!

Fails to recognize changed interfaces

We have integrated japicmp into Groovy to integrate binary compatibility checks. See [1] and [2].

However, it fails to recognize the change in implemented interfaces. To reproduce:

git clone https://github.com/melix/japicmp-bugs.git
cd changed-interface
./gradlew japicmp

The build should fail, but it doesn't, because japicmp failed to recognize the new interface and says the class is unchanged.

[1] https://github.com/melix/japicmp-gradle-plugin
[2] groovy/groovy-core@29e3bd4

Incorrectly reports method changes

I have been testing the 0.2.3 version and have noticed that it does not correctly report changes to methods. I have created a repository for demonstrating the problems I am seeing. To reproduce:

git clone https://[email protected]/ojburn/japicmp-bugs.git
cd japicmp-bugs/method-changes
./gradlew jar cmp

The first problem is changing the method compareTo from:

public class MethodAnnotations implements Comparable<String>
{
    @Override
    public int compareTo(String o)
    {
        return 0;
    }
}

to:

public class MethodAnnotations
{
    public int compareTo(String o)
    {
        return 0;
    }
}

japicmp reports that the method is both UNCHANGED and REMOVED

Processing samples.MethodAnnotations, change status MODIFIED
    Number methods: 2
        method compareTo, change status UNCHANGED, compat true
        method compareTo, change status REMOVED, compat false

The second problem is that when a method return type is changed, japicmp is reporting that a method had been REMOVED as well as a NEW one added. I would suggest that japicmp should report that the method has been CHANGED.

An example would be the changes in the return types from:

public interface InterfaceMethodChanges
{
    void returnChangedVoidToInt();
    int returnChangedIntToVoid();
    String returnChangedStringToObject();
}

to:

public interface InterfaceMethodChanges
{
    int returnChangedVoidToInt();
    void returnChangedIntToVoid();
    Object returnChangedStringToObject();
}

Don't Report Removal for methods that are ACC_BRIDGE or ACC_SYNTHETIC

These methods are generated by the compiler and their implementation should be allowed to change between compiled versions. This would include bridge methods and accessor methods.

This was originally going to be a report requesting non-reporting of removed anonymous inner classes but I can't (yet) formulate the rules that should be applied.

Fails to recognize removed constructor

We have integrated japicmp into Groovy to integrate binary compatibility checks. See [1] and [2].

However, it fails to recognize removed constructors. To reproduce:

git clone https://github.com/melix/japicmp-bugs.git
cd removed-constructor
./gradlew japicmp

The build should fail, but it doesn't, because japicmp failed to recognize the removed constructor and says the class is unchanged.

[1] https://github.com/melix/japicmp-gradle-plugin
[2] groovy/groovy-core@29e3bd4

Include transitive dependency jars

I have a multi module project with a module that is used from other modules. That common module in turn depends on Guice and exposes a class that extends AbstractModule.

guice
`- a
   `- b
   `- c

I have to declare guice as a dependency in the plugin configuration for both b and c or I'll get an error:

[ERROR] Failed to execute goal com.github.siom79.japicmp:japicmp-maven-plugin:0.5.1:cmp (default) on project apollo-nameless: Execution default of goal com.github.siom79.japicmp:japicmp-maven-plugin:0.5.1:cmp failed: Could not load 'com.example.ExampleModule': com.google.inject.AbstractModule. Please make sure that all libraries have been added to the classpath...

Is there a good reason for not including transitive dependencies automatically?

Add ability to check whether a method is synthetic

It would be nice if JApiMethod provided some helper methods like:

  • isPublic
  • isPrivate
  • isSynthetic
  • isPackagePrivate

...

All those methods would be useful, because some changes are critical (changing from public to private for example), but others are not (protected to public). The synthetic check is also nice because some methods are generated by the compiler and for internal use only, so they do not participate the same way in breaking changes.

The difficulty of this ticket is that JApiMethod documents a method change, so references 2 methods, and that oldMethod and newMethod are jassist classes which do not provide those helper methods.

Another option would be to rely on the visitor pattern: register visitors on the comparator, then call visitModifierChange(JApiMethod, int oldModifier, int newModifier) (and provide a bunch of those methods that allow to customize the behavior of the comparator).

Show short usage

As terminal user without a 64" display with 180 lines in my terminal session, I want to read an error message without scrolling ๐Ÿ˜‰

compare to other shell tools like find -> find --unknown-opt, find --help, man find

  • If I enter .. -jar japicmp.jar I only want to see short usage information and an error message or the successful result of japicmp
  • exit codes should be zero on success and according to other shell tools 1 or 2 ... up to 255
  • If I enter .. -jar japicmp.jar --help I want to see the full help - man page equivalent and no error message, the exit code sould be zero

actual on feature-semver branch

$  .. -jar japicmp.jar --help
E: Required option '-o' is missing
NAME
        java -jar japicmp.jar - Compares jars
...
...
$ echo $?
255
$ # why is -o required for help output?

I tought it was fixed with 145b7f6 and 3ab5e55 but I can't find its content anymore. ... Maybe also abandoned with my other changes ... It feels a little bit like "Don't write test and don't send me pull requests, I'll rollback them later" ๐Ÿ˜‰ ๐Ÿ˜„

See also: http://tldp.org/LDP/abs/html/exitcodes.html

Automatically skip pom type modules

First I would like to thank you for this great tool.

I plan to use japicmp maven plugin in a full development stack (https://github.com/seedstack) which contains a lot of modules, some of which are of pom packaging type. I configured japicmp in my parent pom with maven properties to automatically check the current version against the latest release:

<oldVersion>
    <dependency>
        <groupId>${project.groupId}</groupId>
        <artifactId>${project.artifactId}</artifactId>
        <version>RELEASE</version>
    </dependency>
</oldVersion>
<newVersion>
    <file>
        <path>${project.build.directory}/${project.build.finalName}.jar</path>
    </file>
</newVersion>

I found that japicmp doesn't automatically skip pom packaging modules and fails instead because it cannot find the file specified in . I worked around this problem by using a property in the tag that is set to true by default but I must override it to false in each of my 69 jar modules.

It would help me a lot if the japicmp maven plugin could automatically skip every non jar-packaged module (with an info log). This behavior may be enabled with a configuration option.

Regards.

Incorrectly reporting changes to the classes / interfaces

I am evaluating the code on the master branch whether I can use this to follow the semantic versions for some artifacts we build. But I found out that there are false positives.

Here are the links to get the 2 jars:
http://www.malhar-inc.com/chetan/dt-api-2.0.0.jar
http://www.malhar-inc.com/chetan/dt-api-2.0.1.jar

And here is the command that I use (note that even if i change the association of new and old - in both cases it reports that methods are removed):

chetan@chubi:~/work/japicmp$ java -jar ./japicmp/target/japicmp-0.4.2-SNAPSHOT-jar-with-dependencies.jar -n /home/chetan/datatorrent/releases/2.0.1/lib/dt-api-2.0.1.jar -o /home/chetan/datatorrent/releases/2.0.0/lib/dt-api-2.0.0.jar -b
Comparing /home/chetan/datatorrent/releases/2.0.0/lib/dt-api-2.0.0.jar with /home/chetan/datatorrent/releases/2.0.1/lib/dt-api-2.0.1.jar:
***! MODIFIED CLASS: PUBLIC ABSTRACT com.datatorrent.api.LocalMode  (not serializable)
    ---! REMOVED METHOD: PUBLIC(-) ABSTRACT(-) com.datatorrent.api.DAG prepareDAG(com.datatorrent.api.StreamingApplication, org.apache.hadoop.conf.Configuration)
    ---! REMOVED METHOD: PUBLIC(-) STATIC(-) void runApp(com.datatorrent.api.StreamingApplication, org.apache.hadoop.conf.Configuration, int)
***! MODIFIED INTERFACE: PUBLIC ABSTRACT com.datatorrent.api.StreamCodec  (not serializable)
    ---! REMOVED METHOD: PUBLIC(-) ABSTRACT(-) java.lang.Object fromByteArray(com.datatorrent.common.util.Slice)
***! MODIFIED INTERFACE: PUBLIC ABSTRACT com.datatorrent.api.StreamingApplication  (not serializable)
    ---! REMOVED METHOD: PUBLIC(-) ABSTRACT(-) void populateDAG(com.datatorrent.api.DAG, org.apache.hadoop.conf.Configuration)

chetan@chubi:~/work/japicmp$ java -jar ./japicmp/target/japicmp-0.4.2-SNAPSHOT-jar-with-dependencies.jar -o /home/chetan/datatorrent/releases/2.0.1/lib/dt-api-2.0.1.jar -n /home/chetan/datatorrent/releases/2.0.0/lib/dt-api-2.0.0.jar -b
Comparing /home/chetan/datatorrent/releases/2.0.1/lib/dt-api-2.0.1.jar with /home/chetan/datatorrent/releases/2.0.0/lib/dt-api-2.0.0.jar:
***! MODIFIED CLASS: PUBLIC ABSTRACT com.datatorrent.api.LocalMode  (not serializable)
    ---! REMOVED METHOD: PUBLIC(-) ABSTRACT(-) com.datatorrent.api.DAG prepareDAG(com.datatorrent.api.StreamingApplication, org.apache.hadoop.conf.Configuration)
    ---! REMOVED METHOD: PUBLIC(-) STATIC(-) void runApp(com.datatorrent.api.StreamingApplication, org.apache.hadoop.conf.Configuration, int)
***! MODIFIED INTERFACE: PUBLIC ABSTRACT com.datatorrent.api.StreamCodec  (not serializable)
    ---! REMOVED METHOD: PUBLIC(-) ABSTRACT(-) java.lang.Object fromByteArray(com.datatorrent.common.util.Slice)
***! MODIFIED INTERFACE: PUBLIC ABSTRACT com.datatorrent.api.StreamingApplication  (not serializable)
    ---! REMOVED METHOD: PUBLIC(-) ABSTRACT(-) void populateDAG(com.datatorrent.api.DAG, org.apache.hadoop.conf.Configuration)

Oldversion dependency do not support classifier.

Thanks for providing a compare tool that works with java8, used clirr before.

Currently build jar files with different classifiers that I want to compare, but classifier is not supported inside dependency when configuring old version to compare against.

want to be able to use classifier like below

japicmp japicmp-test-v1 0.5.3 somevariant ##

Best regards
Pether

Show semver difference

As developer I want to know a short info about api changes - as lib maintainer I want check the compatibility with previous jar without details.

  • When I call java -jar japicmp.jar --old .. --new .. --only-semver-diff the output is one of the following values: 1.0.0 or 0.1.0 or 0.0.1

1.0.0 means: there are incompatible (-b) public (-a public) changes like method deletions
0.1.0 means: there are public (-a public) changes like new methods or classes
0.0.1 means: there are no public (-a public) changes

  • Compatible switches for --only-semver-diff are --exclude, --include, --new, --old

The output of this call can be interpreted like output = newVersion - oldVersion.

See also: http://semver.org/

(I know that semver addresses also internal behavior and not only api changes, but I think it is a helpful short information. - I don't want to work with given maven pom versions.)

Command-line option to filter packages

A new command-line option should be added, that filters the classes under investigation by their package name. The package names should be given as a list of comma-separated regular expressions.

Binary compatibility of a bunch of jars

Tool is great. No, it is just awesome. Thanks. ๐Ÿ‘

Our team consider to use japicmp to automate a binary compatibility verification of a bunch of jars. We deliver 15 jars and i can run appropriate command 15 times but the problem is with reporting. We would like to have one html (instead of 15) for a hole verification.

I found few examples for comparison of one jar (with old version). But are there any practices to compare a bunch of jars and report properly ?

Thank you.

unexpected behavior wrt include and exclude packages

Whenever a package matches an include filter, it is taken into account, ignoring the exclude filter.
I would have expected the exclude filter has precedence over the include filter

eg:
include: com.example.*
exclude: com.example.internal.*

would ignore all com.example.internal.* packages

Output.xml contains non existant url in schemaLocation

When I run japicmp the output.xml gets this header

<japicmp xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" newJar="c:\new.jar" oldJar="c:\old.jar" xsi:schemaLocation="https://github.com/siom79/japicmp/schema/japicmp.xsd japicmp.xsd" xsi:noNamespaceSchemaLocation="japicmp.xsd">
  1. https://github.com/siom79/japicmp/schema/japicmp.xsd does not exist. Does it exist somewhere else?
  2. schemaLocation is set to a url (pointing to a xsd) followed by space and then the xsd filename (again) as in xsi:schemaLocation="https://github.com/siom79/japicmp/schema/japicmp.xsd japicmp.xsd" That must be wrong, right?

Use separate classpaths for old/new jars

In my opinion it is not correct, to use the same classpath when looking for interfaces or base classes when comparing two classes.

Assume i have a service interface A in a.jar and its implementation B in b.jar. Now i want to compare two versions B1 (in b1.jar) and B2 (in b2.jar) which implement A1 (in a1.jar) and A2 (in a2.jar) which may or may not differ. So for correct results when loading B1 i need a1.jar on the classpath as for loading B2 i need a2.jar.

Adding a method to an interface should be incompatible modification

  1. Have a build that has breakBuildOnBinaryIncompatibleModifications set to true
  2. On an included interface, add a new method to it
  3. Run the build

Expected: It should fail
Actual: It doesn't fail

Adding a new method (without default implementation) to an interface breaks compatibility, because existing implementations will break. See Eclipse's reference for this too. Or am I missing some configuration for this?

Path containing spaces mishandled in maven plugin

If your jenkins project name contains a space then some apparent mishandling of paths will be observed

[INFO] java.io.FileNotFoundException: /home/jenkins/workspace/Generic%20Utilities/target/japicmp/japicmp.xsd (No such file or directory)
com.sun.xml.internal.txw2.TxwException: java.io.FileNotFoundException: /home/jenkins/workspace/Generic%20Utilities/target/japicmp/japicmp.xsd (No such file or directory)
    at com.sun.xml.internal.txw2.output.StreamSerializer.<init>(StreamSerializer.java:81)
    at com.sun.xml.internal.txw2.output.ResultFactory.createSerializer(ResultFactory.java:60)
    at com.sun.xml.internal.bind.v2.schemagen.XmlSchemaGenerator$Namespace.writeTo(XmlSchemaGenerator.java:607)
    at com.sun.xml.internal.bind.v2.schemagen.XmlSchemaGenerator$Namespace.access$800(XmlSchemaGenerator.java:490)
    at com.sun.xml.internal.bind.v2.schemagen.XmlSchemaGenerator.write(XmlSchemaGenerator.java:472)
    at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.generateSchema(JAXBContextImpl.java:792)
    at japicmp.output.xml.XmlOutputGenerator.createXmlDocumentAndSchema(XmlOutputGenerator.java:71)
    at japicmp.output.xml.XmlOutputGenerator.generate(XmlOutputGenerator.java:34)
    at japicmp.maven.JApiCmpMojo.generateXmlOutput(JApiCmpMojo.java:209)
    at japicmp.maven.JApiCmpMojo.execute(JApiCmpMojo.java:107)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:132)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:208)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:116)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:80)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:120)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:347)
    at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:154)
    at org.jvnet.hudson.maven3.launcher.Maven32Launcher.main(Maven32Launcher.java:132)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchStandard(Launcher.java:330)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:238)
    at jenkins.maven3.agent.Maven32Main.launch(Maven32Main.java:181)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at hudson.maven.Maven3Builder.call(Maven3Builder.java:136)
    at hudson.maven.Maven3Builder.call(Maven3Builder.java:71)
    at hudson.remoting.UserRequest.perform(UserRequest.java:118)
    at hudson.remoting.UserRequest.perform(UserRequest.java:48)
    at hudson.remoting.Request$2.run(Request.java:328)
    at hudson.remoting.InterceptingExecutorService$1.call(InterceptingExecutorService.java:72)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.FileNotFoundException: /home/jenkins/workspace/Generic%20Utilities/target/japicmp/japicmp.xsd (No such file or directory)
    at java.io.FileOutputStream.open(Native Method)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:221)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:110)
    at com.sun.xml.internal.txw2.output.StreamSerializer.<init>(StreamSerializer.java:77)

japicmp fails to recognize added constructor

We have integrated japicmp into Groovy to integrate binary compatibility checks. See [1] and [2].

However, it fails to recognize added constructors. To reproduce:

git clone https://github.com/melix/japicmp-bugs.git
cd added-constructor
./gradlew japicmp

The build should fail, but it doesn't, because japicmp failed to recognize the added constructor and says the class is unchanged.

[1] https://github.com/melix/japicmp-gradle-plugin
[2] groovy/groovy-core@29e3bd4

Have maven 3.0.5 as a prerequisite instead of 3.1.0

3.0.5 of maven is prevalent with many projects and is being widely used. e.g. netbeans 8.0.1 gets shipped with maven 3.0.5. There is an inertia which prevents upgrades without benefits.

While evealuating japicmp, I realized that even if the prerequisite is 3.0.5, japicmp works as probably the API japicmp cares about has not changed.

Can we make 3.0.5 prerequisite? The issues that come with taking such a case will be the cost people who stick to 3.0.5 will have to pay.

japicmp should track changes on annotations

Although adding or removing annotations does not affect the binary compatibility, it would be nice to track annotation changes. This feature could be used to analyse changes in annotation-based APIs/features (like e.g. JPA, JAX-RS, etc.).

Excludes/includes at the method level

Hi,

It would be great if it was possible to specify excludes (and includes) at the level of the method, something like:
package.Class.method or maybe even something more specific including parameters types.

The motivation is that we use your (wonderful I must say) tool (the maven plugin in particular) to prevent changes to an API and so we want to always fail a build if there was such changes.
But of course, sometimes, there is exceptions and these exceptions are for specific method.
So we would like to skip checks for these :)

Thanks!

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.