seelabfhdo / lemma Goto Github PK
View Code? Open in Web Editor NEWHome of the Language Ecosystem for Modeling Microservice Architecture (LEMMA)
License: MIT License
Home of the Language Ecosystem for Modeling Microservice Architecture (LEMMA)
License: MIT License
Currently, we only support the generation of LEMMA models from OpenAPI specifications. Would be nice to turn this into a bidirectional transformation in the future (see also Issue #33).
Currently, LEMMA enables the modeling of technology-specific primitive, structured, and list types. Technology-specific enumeration types are not supported. However, their integration would be sensible to express technology-specific types, e.g., in the context of Java types that have a constructor for enumeration values (cf. issue #7).
Possible syntax for technology-specific enumeration types:
technology spring {
types {
enum type ResponseEntity;
}
}
During working on the OpenAPI import feature I encountered a bug. Apparently the word "to" used in comments, in my case in comments for operations in the service dsl, is identified as a keyword and, thus, causes the syntax check to go crazy (see screen). Probably a minor issue which can be fixed easily.
Hi folks,
as you might know because LEMMA is build through various Eclipse Plug-Ins we have a problem with libraries/dependencies which are not available as Eclipse Plug-Ins. A typical example can be found in the Avro Plugin ( de.fhdo.lemma.data.avro ). The Plug-In uses avro, jackson-core, jackson-annotations, and jackson-databind as external libraries.
Unfortunately we cannot use mavens dependency management directly because LEMMA projects are Eclipse Plug-In. Therefore, we currently manually download and add those libraries, e.g., in a lib folder. However, - and I guess we all agree here - this is super tedious. For example the openapi library which I use in the OpenAPI branch in order to enable openapi-2-LEMMA transformations needs 20+ libraries.
Fortunately, I think I was able to find a better solution to get rid of the tedious parts.
We can use the maven-dependency-plugin and the copy-dependencies to automatically download all dependencies during the maven initialize phase of our tycho build. Then, we add the location of the downloaded libs to the bundle classpath in the manifest file. To deal with new versions of a library we can even strip the version number from the downloaded files, i.e. avro 1.10.0 and avro 1.11.0 would both be stored as avro.jar.
By default the lib jars are downloaded to the folder target/dependencies. But we could also configure a different folder.
The only drawback is that when you initially clone the source code and import it into your IDE without executing the maven initialize phase your project will have an error because the lib jar which the classpath points to is not found. Also, this only happens when we use the default target/dependendies location. When we store the lib files in a lib folder and include them in the commit we can even skip the initial errors in the IDE. However, then we still have to commit all lib files ...not sure if we want that cause those files blow the repository size up by quiet a lot (e.g. my OpenAPI module is 100+MB).
I already did a testbuild in the mvnDependencyTest branch. The interesting project is de.fhdo.lemma.technology.technologydsl.experimental . As you can see I added apache commons math3 as an example dependency in the pom file.
What do you guys think? Feasible approach?
Currently, the Boolean values true
and false
receive no syntax highlighting in the modeling languages' editors.
They are defined as possible values of the BOOLEAN terminal
terminal BOOLEAN returns ecore::EBoolean: 'true' | 'false';
in the grammar definition of the Domain Data Modeling Language.
Note that the highlighting needs to be implemented/tested for all modeling languages that make use of the PrimitiveValue
modeling concept and the corresponding grammar rule.
The validation of import paths should consider case-sensitivity and be independent from the used OS.
Suppose the following filesystem structure:
- smodel.services
- technology
|- tmodel.technology
Currently, it is possible under Apple or Windows to write the following in the service model smodel.services
:
// Import from folder "Technology" whose name in the filesystem is actually "technology"
import technology from "Technology/tmodel.technology" as tech
...
However, the above model will be erroneous on Linux systems, whose filesystems are usually case-sensitive. Thus, import path validation should become case-sensitive and OS-independent to work on all major OSes.
Currently, the Technology Modeling Language only enables the modeling of service properties
for deployment and infrastructure (i.e., operation) technologies. The set of expressible property types should be extended by technology-dependent properties that concern the operation node itself, e.g., Kubernetes configuration properties.
The current workaround for operation models to configure a node is the usage of the default properties
section. Semantically, this section does however also target services that are deployed to the node (container) or use the node (infrastructure).
For the inclusion of technology-dependent, node-related properties further reasoning is required (list is probably not complete):
default properties
section of the Operation Modeling Language? Should it be renamed, e.g., to default service properties
?When executing a LEMMA model processor we currently get warnings like
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by nonapi.io.github.classgraph.classpath.CallStackReader (file:/home/florian/Dokumente/Forschung/Dissertation/eclipse-workspace/code%20generators/de.fhdo.lemma.model_processing.code_generation.java_base/build/libs/de.fhdo.lemma.model_processing.code_generation.java_base-0.8.5-SNAPSHOT-standalone.jar) to method java.lang.SecurityManager.getClassContext()
WARNING: Please consider reporting this to the maintainers of nonapi.io.github.classgraph.classpath.CallStackReader
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
This is due to the Java Platform Module System (JPMS), which since Java 9 checks for not explicitly allowed accesses between classpath dependencies (cf. https://www.baeldung.com/java-9-modularity for a more technical explanation). To prevent such warnings (which in future Java releases will be handled more strictly), we would need to convert LEMMA to be compatible with JPMS (in fact, the above warning is from the ClassGraph library with LEMMA's model processing framework scans the classpath for annotations).
Unfortunately, Xtext currently seems to prevent us from porting LEMMA to JPMS given its org.eclipse.xtext
and the transitive org.eclipse.xtext.util
dependency both define the split package "org.eclipse.xtext.util". As it seems, JPMS however prevents split package accesses. See detailed example of the problem here: https://github.com/frademacher/xtext-jpms-test (with an elaborate explanation here: https://github.com/frademacher/xtext-jpms-test/blob/main/build.gradle.kts). Thus, we probably need to wait until Xtext is made JPMS-enabled upstream.
Hello
Lemma looks like a really fascinating, and useful project! Really impressive!
I would be interested in new technology code generators, in particular for typescript.
Do you have any guides on how to do this?
Thanks and kind regards
Currently, the Container Base Generator for Docker and Kubernetes only supports the deployment of one microservice per container. While this approach is common practice, the Operation Modeling Language still supports the definition of multi-deployments (more than one service per container).
However, the Container Base Generator prevents the generation of multi-deployments by means of intermediate model validation. To align the generator with the modeling language, an investigation should be conducted to what extent it is feasible to support multi-deployment with the generator.
In the ideal case, the Container Base Generator should support the generation of multi-deployments for both Docker and Kubernetes, and only yield a warning in the event of a detected multi-deployment (something along the lines "Detected multi-deployment on container X, will proceed in generation. Please consider refactoring towards single-deployment in the future for increased scalability.").
Currently, it is necessary to first import a domain model into a service model to derive its intermediate representation. There should be a GUI option similar to the "Generate Intermediate Service Models" that directly targets domain models and allows the generation of their intermediate representations independent of service model imports.
Technology-specific types in LEMMA technology models can currently only target one built-in type kind at once. For example, a hypothetical technology-specific for Spring's type Response Entity
may be captured in a LEMMA technology model as follows:
technology spring {
types {
...
structure type ResponseEntity;
}
}
However, a ResponseEntity
may cluster several values of different Java types, e.g., regular classes, enumeration classes, and instances of lists. These types map LEMMA data structures, enumerations, and list types. However, the technology-specific ResponseEntity
may only be defined as applicable to exactly one of these types. LEMMA should therefore support the modeling of technology-specific types that can be mapped to more than one kind of a built-in type. A possible solution to this lack in expressivity could be to allow for modeling eponymous types for different type kinds, e.g.,
technology spring {
types {
...
structure type ResponseEntity;
list type ResponseEntity;
enum type ResponseEntity;
}
}
(The modeling of technology-specific enumeration types, as shown above, is currently not possible; their integration is addressed by issue #8.)
LEMMA service models may import domain models in order to type parameters of microservice operations with domain concepts. However, further "links" between both model kinds may be sensible, e.g., to specify the use of domain objects (in the sense of Domain-driven Design; DDD) by microservices. For example, microservices may rely on DDD domain services to employ domain-specific functionality. Next to the kind of link ("use link" in this case), it would probably make sense to enable microservice modelers to state the concrete reason for the link.
Linkage between Domain and Service Viewpoint may also be sensible expressible on the operation-level, i.e., "microservice operation M_o uses domain operation C_o from domain concept C for the sake of X".
Currently, container_base generator doesn't support the configuration of custom properties in operation models.
To enable the support of custom properties, the generator should be able to transform an operation aspect into a service property, as listed below.
// Operation aspect
aspect CustomProperty for containers, infrastructure {
string key<mandatory>;
string value<mandatory>;
}
// Service property
service.property.key=service.property.value
At the moment, the container_base generator supports the configuration of Kubernetes deployments via a basic configuration based on the operation model or a self-defined Kubernetes file via an operation aspect.
To ease the configuration of Kubernetes deployments, certain configuration options should be cluster via operation aspects, to provide additional configuration possibilities on a higher level of abstraction than code / Kubernetes files.
I'm starting the build with the build script lemma.sh
.
With Maven 3.6.2 and 3.6.3 de.fhdo.lemma.data.datadsl
doesn't build and only returns a non-descript NullPointerException as an error. This could be related to this issue and fixed in the upcoming 3.7.0, since I'm getting a similar stacktrace when running Maven with -X
:
java.lang.NullPointerException
at java.util.Hashtable$Entry.setValue (Hashtable.java:1286)
at org.apache.maven.model.interpolation.StringVisitorModelInterpolator$ModelVisitor.visit (StringVisitorModelInterpolator.java:1427)
at org.apache.maven.model.interpolation.StringVisitorModelInterpolator$ModelVisitor.visit (StringVisitorModelInterpolator.java:1025)
at org.apache.maven.model.interpolation.StringVisitorModelInterpolator$ModelVisitor.visit (StringVisitorModelInterpolator.java:168)
at org.apache.maven.model.interpolation.StringVisitorModelInterpolator.interpolateModel (StringVisitorModelInterpolator.java:105)
at org.apache.maven.model.building.DefaultModelBuilder.interpolateModel (DefaultModelBuilder.java:789)
at org.apache.maven.model.building.DefaultModelBuilder.build (DefaultModelBuilder.java:393)
at org.apache.maven.repository.internal.DefaultArtifactDescriptorReader.loadPom (DefaultArtifactDescriptorReader.java:292)
at org.apache.maven.repository.internal.DefaultArtifactDescriptorReader.readArtifactDescriptor (DefaultArtifactDescriptorReader.java:171)
at org.eclipse.aether.internal.impl.collect.DefaultDependencyCollector.resolveCachedArtifactDescriptor (DefaultDependencyCollector.java:541)
at org.eclipse.aether.internal.impl.collect.DefaultDependencyCollector.getArtifactDescriptorResult (DefaultDependencyCollector.java:524)
at org.eclipse.aether.internal.impl.collect.DefaultDependencyCollector.processDependency (DefaultDependencyCollector.java:412)
at org.eclipse.aether.internal.impl.collect.DefaultDependencyCollector.processDependency (DefaultDependencyCollector.java:365)
at org.eclipse.aether.internal.impl.collect.DefaultDependencyCollector.process (DefaultDependencyCollector.java:352)
at org.eclipse.aether.internal.impl.collect.DefaultDependencyCollector.doRecurse (DefaultDependencyCollector.java:509)
at org.eclipse.aether.internal.impl.collect.DefaultDependencyCollector.processDependency (DefaultDependencyCollector.java:461)
at org.eclipse.aether.internal.impl.collect.DefaultDependencyCollector.processDependency (DefaultDependencyCollector.java:365)
at org.eclipse.aether.internal.impl.collect.DefaultDependencyCollector.process (DefaultDependencyCollector.java:352)
at org.eclipse.aether.internal.impl.collect.DefaultDependencyCollector.collectDependencies (DefaultDependencyCollector.java:254)
at org.eclipse.aether.internal.impl.DefaultRepositorySystem.collectDependencies (DefaultRepositorySystem.java:284)
at org.apache.maven.project.DefaultProjectDependenciesResolver.resolve (DefaultProjectDependenciesResolver.java:169)
at org.apache.maven.lifecycle.internal.LifecycleDependencyResolver.getDependencies (LifecycleDependencyResolver.java:243)
at org.apache.maven.lifecycle.internal.LifecycleDependencyResolver.resolveProjectDependencies (LifecycleDependencyResolver.java:147)
at org.apache.maven.lifecycle.internal.MojoExecutor.ensureDependenciesAreResolved (MojoExecutor.java:248)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:202)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
at org.apache.maven.cli.MavenCli.execute (MavenCli.java:956)
at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:288)
at org.apache.maven.cli.MavenCli.main (MavenCli.java:192)
at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke (Method.java:498)
at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:282)
at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:225)
at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:406)
at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:347)
With Maven 3.6.1 de.fhdo.lemma.eclipse.ui.utils
(and possibly others) won't build with the following error:
[ERROR] Cannot resolve project dependencies:
[ERROR] Software being installed: de.fhdo.lemma.eclipse.ui.utils 0.7.0.qualifier
[ERROR] Missing requirement: de.fhdo.lemma.eclipse.ui.utils 0.7.0.qualifier requires 'osgi.bundle; com.google.guava 0.0.0' but it could not be found
Everything works fine with Maven 3.6.0 and 3.5.4.
Lemma Version: current master (a400b0c)
Java Version: 11.0.7
Operating System: openSUSE Tumbleweed 20200622
Currenty, we prevent the usage of the built-in unspecified
primitive type in microservice operation parameters. However, for non-implemented microservice operations it may make sense to allow parameter typing with the unspecified
type. For instance, this approach would foster the agile specification of microservice APIs.
Syntax example:
functional microservice org.example.Service {
interface ExampleIface {
noimpl notFinishedOperation(sync parameterTypeToDecide: unspecified);
}
}
There exist several plugins/related artifacts for LEMMA that are not part of its "official" repository and installation:
These should eventually be integrated into LEMMA's repository and installation.
Currently, complex types, i.e., data structures, list types, and enumerations, cannot be hidden. This is currently only supported for data fields in data structures.
I would fit the semantics of DDD's Bounded Contexts to enable the explicit specification of domain concepts ("complex types" in the wording of the modeling languages) that are not shared with other contexts and are thus hidden. However, hiding of complex types should not only be possible, if they are contained in a context, but also if they are declared on the top-level namespace, i.e., directly in a domain model file w/o any namespace, or in a version. The syntax should look like this:
context MyContext {
hide structure MyStructure { ... }
}
version MyVersion {
hide list MyList { ... }
}
hide enum MyEnumeration { ... }
Hidden complex types should not directly be usable outside of their surrounding namespace in their defining domain model. In particular, they are not usable to type parameters of microservice operations. However, a hidden complex type can be exposed if it is used in a non-hidden complex type to type data fields.
To provide a better modeling experience when addressing an environment with multiple teams each responsible for at least a microservice (and, hence, a service model), it would be awesome to be able to import external models in a service model and resolve those later on.
so in addition to the normal service imports like:
import microservices from "example.services" as example
During a quick discussion, we came up with something like this for the extended mechanism:
import microservices from "https://www.yolorui.com/yolo" to "example.services" as example
I will try to build something ;)
Currently, the Container Base generator doesn't support the configuration of network specifications for Docker Compose or Kubernetes networks.
To enhance the functionalities of the Container Base Generator, the configuration of networks should be enabled via operation aspects.
Because our sonatype repository is currently down and I wanted to do a local build, I just noticed that the dependency versions in https://github.com/SeelabFhdo/lemma/tree/main/examples/model-processing
are still sitting at LEMMA v0.8.0 (build crashed cause v0.8.0 were not accessible locally nor from the temporary down repo). The build will work again when the sonatype repo is back up, however, this made me curious if we need/should do a version uplift to 0.8.5 for those model processing examples?
This may also concern other projects in the examples folder.
Many teams in practice use OpenAPI to document their RESTful interfaces. Hence, it would be great to add a new button/menu item and provide a mechanism for OpenAPI-2-LEMMA.
OpenAPI descs probably contain domain data (schemas in openapi) and service information (api desc in openapi).
To avoid security risks due to passwords stored in plain text, the support for mechanisms like environment variables should be integrated.
This may be especially relevant for code generators like container_base, and eureka.
Currently it is not possible to import mapping models in an operation model, so the technology information from a mapping model cannot be used.
Currently, the LEMMA models generated by the de.fhdo.lemma.service.openapi.tests
project are not checked for syntactic correctness. Consequently, if the syntax of a LEMMA modeling language should change in the future it may happen that the OpenAPI project produces a syntactically wrong output. In a perfect world, this should not happen because a change of the syntax of a LEMMA modeling language should always involve a corresponding adaptation of its extractor. However, since the extractors currently don't have accompanying tests, it would still make sense to let the OpenAPI tests parse LEMMA models after they were generated to detect potential mismatches between the actual syntax implementation and the one extracted from generated in-memory models.
To parse generated LEMMA models, the OpenAPI tests could probably do the same as the loadXtextResource()
method over at
loadXtextResource()
as this would result in a dependency on the de.fhdo.lemma.eclipse.ui
project by the tests project which we definitely do not want).Currently, the operation model transformation and container base generator only support operation aspects configured for containers or infrastructure nodes. Operation aspects specified specifically for deployed services in containers are not supported.
Currently, the OpenAPI plugin requires the user to open a dialog and select an OpenAPI specification file next to having to input some additional stuff like model names. To facilitate the generation of LEMMA models from OpenAPI specification files, it would be nice if the user could right-click on an OpenAPI specification file in the Eclipse Package or Project Explorer, click on an entry like "Extract LEMMA Models from OpenAPI Specification", and get the OpenAPI generation dialog opened with the specification file text field pre-filled with the path to the right-clicked file.
A good starting point for the integration of right-click support in Eclipse' Package and Project Explorers is
lemma/de.fhdo.lemma.data.avro/plugin.xml
Line 32 in 4c1de5a
Currently, properties of technology aspects can only be typed by primitive LEMMA types. Consequently, an aspect property may only receive a single value.
It would however be helpful to enable aspect properties to receive multiple values (of the same type) at once similar to array-typed annotation elements in Java (cf., e.g., the propOrder
element of Jakarta EE's XmlType
annotation).
Possible LEMMA syntax for multi-valued aspect property definition:
aspect XmlType {
list string propOrder;
}
Import of the same files is possible with different relative paths or an absolute path and a relative path. The function is getDuplicateIndex in LemmaUtils.
Example1 :
import technology from "../technology/Protocols.technology" as Protocols
import technology from "../domain/../technology/Protocols.technology" as Protocols2
Example2:
import technology from "../technology/Protocols.technology" as Protocols
import technology from "D:\\gitdata\lemma\example models\technology\Protocols.technology" as Protocols2
Both examples are not detected as errors.
We are currently facing issues with building LEMMA on Apple Silicon. Apparently, this is not an actual LEMMA issue but related to the fact that the eclipse packages were not compatible with Apple until version 2022-03. Since than, eclipse also provides builds for MacOS AArch64.
LEMMA is currently using the eclipse release 2021-03. I.e., we need to lift the version to at least 2022-03 to be compatible with Apple Silicon. @mmitas777 has done some testing on this. Apparently the lift works for most projects, but there are some details that need a little more work.
We are currently working on the issue.
On a related note: I am not sure if there are also issues with executing LEMMA or at least certain LEMMA features (such as live validation of code generation) on Apple. Maybe someone owning a new Mac can clarify this. I.e. what happens when you install Eclipse in >Release 2022-03 and install LEMMA through the updatesite. Does this work?
Currently, the Technology Modeling Language does not provide full MIME type support.
While it is possible to model protocols with data formats, e.g.,
technology Example {
protocols {
sync rest data formats json default with format json;
async amqp data formats json default with format json;
}
}
the following is not possible
technology ExampleWithMimes {
protocols {
sync rest data formats "application/json" default with format "application/json";
async amqp data formats "application/json" default with format "application/json";
}
}
I pushed a branch called mime_type_support to change the DataFormat
production rule in the Technology Modeling Language's grammar specification (and the cross-references to it, e.g., from the Service Modeling Language's grammar) to not rely on ID
, but Xtext's STRING
terminal rule instead. While this change seems to be working on the grammar level, it needs further testing.
If there are no obvious issues, the following issues need to be addressed (and maybe some more):
Finally, this change should make it into master
together with the OpenAPI feature when it's ready.
Currently, there is no modeling means to retrofit LEMMA with types from external libraries. Instead, model processors must always be adapted to support such types. For example, to support code generation for the type LocalDate from Java's Time API, it is required to extend the Java Base Generator class TypeMappings with an entry like
technology {
...
"LocalDate" withImport "java.time.LocalDate"
}
and the have a technology model with
...
types {
...
primitive type LocalDate;
}
...
However, it would be nice to support the specification of types originating from a library of a certain technology (e.g., the standard lib of the Java technology) directly within technology models, e.g., via a new type kind library
and with additional library types (that in the case of Java result in additional imports) so that one could write:
...
types {
...
library type LocalDate from library "java.time"
with additional types "org.example.LibraryClass1", "org.example.LibraryClass2";
}
...
or in the form of "external types", e.g.,
...
types {
...
external type LocalDate with fully-qualified name "java.time.LocalDate"
requiring "org.example.LibraryClass1", "org.example.LibraryClass2";
}
...
The Operation Modeling Languages supports the assignment of more than one technology to an operation node, e.g.,
@technology(ContainerTech)
@technology(BuildManagement)
container MyContainer
deployment technology ContainerTech::_deployment.Kubernetes
deploys Services::org.example.MyService {
aspects {
BuildManagement::_aspects.ArtifactId(serviceName="org.example.MyService", artifactId="my-service");
}
...
}
In this example, the Kubernetes
deployment technology from a ContainerTech
technology model is used to determine the deployment technology of the container and the ArtifactId
aspect from a BuildManagement
technology model is used to determine the artifact ID of the deployed microservice. The approach of allowing more than one technology on an operation node thus increases the expressivity of the Operation Modeling Language and the decomposition of technology models.
However, the ATL specification of the intermediate model transformation and the intermediate operation metamodel don't yet consider multiple technology applications on an operation node. Instead, intermediate operation models always exhibit only one of the applied technologies of an operation node, i.e., either the deployment technology (containers) or the infrastructure technology (infrastructure nodes). Consequently, intermediate operation models lack the information of other technology applications which makes it impossible to recognize them during model processing.
Similarly to intermediate service models, intermediate operation models should thus receive a technologies
association for their IntermediateOperationNode
concept which should then be established in intermediate models by the corresponding ATL specification.
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.