twcable / cq-gradle-plugin Goto Github PK
View Code? Open in Web Editor NEWDEPRECATED: A number of plugins for making it easier to work with Gradle and Adobe CQ/AEM
License: Apache License 2.0
DEPRECATED: A number of plugins for making it easier to work with Gradle and Adobe CQ/AEM
License: Apache License 2.0
https://github.com/Netflix/Hystrix/blob/master/.travis.yml looks like a good starting point :)
Right now SlingServersConfiguration
is created for each project, which means that information added by one project (such as publish not being available) has to be "rediscovered" by all the other projects.
We have set up a module in a project for packaging the 3rd party dependencies of the project. The module's build.gradle file has just dependencies and enough to build a package. We also have the usual bundle and content modules. Lines 233-126 of AddBundlesToFilterXmlTask.gradle result in adding a line to the xml filter to filter the bundle jar in the 3rd party dependencies package which is not desired.
When trying to install Grabbit using v3.0.1
grabbit is not currently on the server, so can not install
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:77)
at org.codehaus.groovy.reflection.CachedConstructor.doConstructorInvoke(CachedConstructor.java:71)
at org.codehaus.groovy.runtime.callsite.ConstructorSite$ConstructorSiteNoUnwrap.callConstructor(ConstructorSite.java:81)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:57)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:182)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:190)
at com.twcable.gradle.cqpackage.CqPackageCommand.commandPackage(CqPackageCommand.groovy:115)
at com.twcable.gradle.cqpackage.CqPackageHelper$_installPackage_closure3.doCall(CqPackageHelper.groovy:131)
at com.twcable.gradle.cqpackage.CqPackageHelper$_installPackage_closure3.call(CqPackageHelper.groovy)
at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:1379)
at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:1372)
at com.twcable.gradle.cqpackage.CqPackageHelper.installPackage(CqPackageHelper.groovy:130)
at com.twcable.gradle.cqpackage.CqPackageHelper$installPackage$5.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
at com.twcable.gradle.cqpackage.CqPackagePlugin$_installPackage_closure6_closure19.doCall(CqPackagePlugin.groovy:197)
Hi Jim,
I am facing an issue using the plugin.For the first time installation,the content pages get loaded correctly but on subsequent builds,we are getting "class cannot be correctly instantiated" errors. We had to delete/uninstall all application-specific bundles and then run the build to make our pages load correctly.We believe this is because for every build the uninstall task is removing the previously installed bundles and causing issues due to the behavior described by the enhancement.(#3)
We are using 3.0.2 version of your plugin and also set unistallBundlesPredicate to true/false but there is no difference in terms of uninstall task.
Please provide inputs or pointers to avoid uninstalling the bundles for every build.
Currently in SlingServersConfiguration.groovy, the method defaultServers()
uses hard coded values for an local author and publish server. This should be updated to try to pull from the system's environment variables if they are configured.
For Ex.
Could have following environment vars set:
AEM_AUTHOR_MACHINENAME
AEM_AUTHOR_PORT
AEM_AUTHOR_PROTOCOL
AEM_AUTHOR_USERNAME
AEM_AUTHOR_PASSWORD
AEM_PUBLISH_MACHINENAME
AEM_PUBLISH_PORT
AEM_PUBLISH_PROTOCOL
AEM_PUBLISH_USERNAME
AEM_PUBLISH_PASSWORD
The method should try to set values based on the environment variables if they are set. If not then fall back to the hardcoded standard OOTB values.
Especially since there's so much duplication between the metadata files in META-INF/vault
, allow the cqpackage
plugin to accept some additional information so that those files can be fully generated instead of merely templated now.
Right now "uninstallBundles" simply uninstalls the bundles in the order it "discovers" them, which is effectively alphabetical. Unfortunately that can also effectively be the opposite order that they should be uninstalled.
It should ask each bundle what other bundles depend on them (or what other bundles it depends on) and build a dependency graph so that it can uninstall from "least connected" to "most connected".
If you set the contentSrc
on createPackage
, it is not used by default for addBundlesToFilterXml
to know where to get the "source" filter.xml file.
The work around looks like:
createPackage.contentSrc = project.file("src/main")
addBundlesToFilterXml.filterXmlReader = new FileReader(new File(createPackage.contentSrc as File, "META-INF/vault/filter.xml"))
Hi Jim,
Now I am facing problems with the OsgI bundles.I am applying the plugin sling-bundle and issuing the gradlew clean install.
The Osgi bundle is getting generated locally in the build/libs folder of the project but nothing happens after that.Build is successful but the bundle doesn't get installed or even uploaded.
I am using the defaults except for the install path location.Am I invoking the plugin wrongly?
Please help.
Below is the build.gradle file I am using:
group = 'com.projectname'
description = 'ProjectName Core'
version = '0.1-SNAPSHOT'
configurations {
provided
compile.transitive = true
}
apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'osgi'
apply plugin: 'sling-bundle'
slingServers.author.installPath = '/apps/projectname/install'
sourceCompatibility = 1.8
targetCompatibility = 1.8
dependencies {
compile group: 'org.slf4j', name: 'slf4j-simple', version:'1.6.4'
compile group: 'org.slf4j', name: 'slf4j-api', version:'1.6.6'
compile group: 'org.apache.felix', name: 'org.osgi.core', version:'1.4.0'
compile group: 'org.apache.felix', name: 'org.apache.felix.scr', version:'1.6.0'
compile group: 'commons-collections', name: 'commons-collections', version:'3.0'
compile group: 'commons-lang', name: 'commons-lang', version:'2.3'
compile group: 'com.google.guava', name: 'guava', version:'14.0'
compile(group: 'org.apache.felix', name: 'org.apache.felix.scr.annotations', version:'1.9.10') {
/* This dependency was originally in the Maven provided scope, but the project was not of type war.
This behavior is not yet supported by Gradle, so this dependency has been converted to a compile dependency.
Please review and delete this closure when resolved. /
}
compile(group: 'org.apache.felix', name: 'org.apache.felix.ipojo', version:'1.8.0') {
/ This dependency was originally in the Maven provided scope, but the project was not of type war.
This behavior is not yet supported by Gradle, so this dependency has been converted to a compile dependency.
Please review and delete this closure when resolved. /
}
compile(group: 'org.osgi', name: 'org.osgi.core', version:'4.2.0') {
/ This dependency was originally in the Maven provided scope, but the project was not of type war.
This behavior is not yet supported by Gradle, so this dependency has been converted to a compile dependency.
Please review and delete this closure when resolved. /
}
compile(group: 'javax.servlet', name: 'servlet-api', version:'2.5') {
/ This dependency was originally in the Maven provided scope, but the project was not of type war.
This behavior is not yet supported by Gradle, so this dependency has been converted to a compile dependency.
Please review and delete this closure when resolved. /
}
compile(group: 'javax.servlet', name: 'jsp-api', version:'2.0') {
/ This dependency was originally in the Maven provided scope, but the project was not of type war.
This behavior is not yet supported by Gradle, so this dependency has been converted to a compile dependency.
Please review and delete this closure when resolved. /
}
compile(group: 'com.adobe.aem', name: 'aem-api', version:'6.0.0.1') {
/ This dependency was originally in the Maven provided scope, but the project was not of type war.
This behavior is not yet supported by Gradle, so this dependency has been converted to a compile dependency.
Please review and delete this closure when resolved. /
}
compile(group: 'org.apache.sling', name: 'org.apache.sling.jcr.jcr-wrapper', version:'2.0.0') {
/ This dependency was originally in the Maven provided scope, but the project was not of type war.
This behavior is not yet supported by Gradle, so this dependency has been converted to a compile dependency.
Please review and delete this closure when resolved. */
}
}
uploadBundle{
}
showBundle {
}
For example, if your configuration says to check author and publisher but publisher is not currently running, checkBundleStatus
will keep waiting for all the bundles to be active on publisher (which of course won't happen) and then fail.
If we ever have large pools of AEM instances to deploy to, the time to deploy will be very long. Multi-threading all the deploy actions (uninstall, remove, install, validateBundles, etc..) would cut deploy times significantly.
If you restrict the bundles in a package (e.g., createPackage.addProjectBundles()
) or specify a different Configuration to use (e.g, createPackage.configuration = project.configurations.myconf
), they are not being used by the verifyBundles
task.
In other words, for all "configurable" properties (not "service." or "sling."), there should not be a "value" attribute on the @Property
.
This typically happens when the bundle is not OSGI wrapped. We should catch the NPE and point out which bundle has the null symbolicName. We should probably still do the uninstall as well.
Caused by: java.lang.NullPointerException: Cannot invoke method contains() on null object
at org.codehaus.groovy.runtime.NullObject.invokeMethod(NullObject.java:88)
at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:45)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.NullCallSite.call(NullCallSite.java:32)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:55)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at com.twcable.gradle.sling.osgi.SlingOsgiBundle$_uninstallAllBundles_closure19.doCall(SlingOsgiBundle.groovy:434)
at sun.reflect.GeneratedMethodAccessor328.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:324)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:278)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1016)
at groovy.lang.Closure.call(Closure.java:423)
at groovy.lang.Closure.call(Closure.java:439)
at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:1379)
at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:1372)
at org.codehaus.groovy.runtime.dgm$149.invoke(Unknown Source)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:271)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:53)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at com.twcable.gradle.sling.osgi.SlingOsgiBundle.uninstallAllBundles(SlingOsgiBundle.groovy:433)
at com.twcable.gradle.sling.osgi.SlingOsgiBundle$uninstallAllBundles.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
at com.twcable.gradle.cqpackage.CqPackageHelper$_uninstallBundles_closure14_closure29.doCall(CqPackageHelper.groovy:332)
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.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:324)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:278)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1016)
at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:39)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:54)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at com.twcable.gradle.sling.SlingSupport.doHttp(SlingSupport.groovy:124)
at com.twcable.gradle.sling.SlingSupport$doHttp.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at com.twcable.gradle.cqpackage.CqPackageHelper$_uninstallBundles_closure14.doCall(CqPackageHelper.groovy:330)
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.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:324)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:278)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1016)
at groovy.lang.Closure.call(Closure.java:423)
at groovy.lang.Closure.call(Closure.java:439)
at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:1379)
at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:1372)
at org.codehaus.groovy.runtime.dgm$149.invoke(Unknown Source)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoMetaMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:248)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMetaMethodSite.java:68)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at com.twcable.gradle.cqpackage.CqPackageHelper.uninstallBundles(CqPackageHelper.groovy:327)
at com.twcable.gradle.cqpackage.CqPackageHelper$uninstallBundles.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
at com.twcable.gradle.cqpackage.CqPackagePlugin$_createUninstallBundlesTask_closure13.doCall(CqPackagePlugin.groovy:279)
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.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:324)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:278)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1016)
at groovy.lang.Closure.call(Closure.java:423)
at groovy.lang.Closure.call(Closure.java:439)
at org.gradle.api.internal.AbstractTask$ClosureTaskAction.execute(AbstractTask.java:548)
at org.gradle.api.internal.AbstractTask$ClosureTaskAction.execute(AbstractTask.java:529)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:80)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:61)
... 57 more
I'm trying to merge the bundle
and content
parts into one single project. That way the source structure would look like this...
src
├── main
│ ├── java
│ ├── content
├── test
Whether that's a good idea or not, I don't know yet. But it would finally place related and dependent things into one place.
In order to get the previously built bundle
into the content
zip file, I'd need a way to tell the createPackage
task to include the jar.archivePath
, which is a File object pointing to the bundle
jar file.
Probably even better would be if there was a way to provide arbitrary bundles directly as files...
apply plugin: 'cqpackage'
createPackage {
bundles << jar.archivePath
}
Is this something that would make sense to add to the cqpackage
plugin?
CqPackageConfiguration.groovy should exclude group com.adobe.aem in order to not pick up the AEM 6.0 uber-jar.
The split start level capabilities has always been dubious, and there are better ways to handle it (including breaking out into different packages). It over-complicates the plugin and the sequence of things starting in CQ.
With the exception of the "non-configurable" properties. (e.g., "service.vendor")
Hi Jim,
Thank you for this wonderful plugin for gradle.
I am trying to use it for the content packages but I am failing in doing so.
I am new to gradle and in the process of migrating from maven to gradle on Java 1.8
Can you please let me know what I am doing wrong in the way am using your plugin?
The OSGI bundles are building just fine in other core projects.But using the below am able to see only the below tasks being called.
.....
............
..................
:project-view:assemble UP-TO-DATE
:project-view:check UP-TO-DATE
:project-view:build UP-TO-DATE
BUILD SUCCESSFUL
Nothing gets generated under the build directory.
Also if I apply the sling plugin (apply plugin: 'sling-bundle') am getting the below error.
Caused by: java.lang.IllegalStateException: There is not a 'jar' task for project ':saks-view'
at com.twcable.gradle.sling.osgi.SlingBundleConfiguration.getSourceFile(SlingBundleConfiguration.groovy:109)
at com.twcable.gradle.sling.osgi.SlingBundleConfiguration_Decorated.getSourceFile(Unknown Source)
at org.gradle.api.internal.BeanDynamicObject$MetaClassAdapter.getProperty(BeanDynamicObject.java:153)
at org.gradle.api.internal.BeanDynamicObject.getProperty(BeanDynamicObject.java:107)
at org.gradle.api.internal.CompositeDynamicObject.getProperty(CompositeDynamicObject.java:78)
at com.twcable.gradle.sling.osgi.SlingBundleConfiguration_Decorated.getProperty(Unknown Source)
at com.twcable.gradle.sling.osgi.SlingBundlePlugin.apply(SlingBundlePlugin.groovy:72)
at com.twcable.gradle.sling.osgi.SlingBundlePlugin.apply(SlingBundlePlugin.groovy)
at org.gradle.api.internal.plugins.DefaultPluginContainer.providePlugin(DefaultPluginContainer.java:188)
at org.gradle.api.internal.plugins.DefaultPluginContainer.addPluginInternal(DefaultPluginContainer.java:137)
at org.gradle.api.internal.plugins.DefaultPluginContainer.apply(DefaultPluginContainer.java:103)
at org.gradle.api.internal.plugins.DefaultObjectConfigurationAction.applyPlugin(DefaultObjectConfigurationAction.java:115)
... 44 more
So I added the apply plugin: 'scr' and it fails with the below error
Caused by: org.gradle.api.UnknownDomainObjectException: SourceSet with name 'main' not found.
at org.gradle.api.internal.DefaultNamedDomainObjectCollection.createNotFoundException(DefaultNamedDomainObjectCollection.java:272)
at org.gradle.api.internal.DefaultNamedDomainObjectCollection.getByName(DefaultNamedDomainObjectCollection.java:192)
at org.gradle.api.NamedDomainObjectCollection$getByName.call(Unknown Source)
at com.twcable.gradle.scr.ScrPlugin.mainSourceSet(ScrPlugin.groovy:155)
at com.twcable.gradle.scr.ScrPlugin$_addScrTask_closure1.doCall(ScrPlugin.groovy:55)
at com.twcable.gradle.scr.ScrPlugin.addScrTask(ScrPlugin.groovy:51)
at com.twcable.gradle.scr.ScrPlugin.apply(ScrPlugin.groovy:45)
at com.twcable.gradle.scr.ScrPlugin.apply(ScrPlugin.groovy)
at org.gradle.api.internal.plugins.DefaultPluginContainer.providePlugin(DefaultPluginContainer.java:188)
at org.gradle.api.internal.plugins.DefaultPluginContainer.addPluginInternal(DefaultPluginContainer.java:137)
at org.gradle.api.internal.plugins.DefaultPluginContainer.apply(DefaultPluginContainer.java:103)
at org.gradle.api.internal.plugins.DefaultObjectConfigurationAction.applyPlugin(DefaultObjectConfigurationAction.java:115)
... 44 more
The below is the sample 'view' project's build.gradle file am using under the project-view folder.
-------------------------------------------------------------build.gradle file--------------------------------------------------------------------
group = 'com.project'
description = 'Project View Package'
apply plugin: 'maven'
apply plugin: 'osgi'
apply plugin: "cqpackage"
sourceCompatibility = 1.8
targetCompatibility = 1.8
createPackage {
bundleInstallRoot
contentSrc
addAllBundles()
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.