jooq / jooq-mcve Goto Github PK
View Code? Open in Web Editor NEWA simple example project that can be used to create MCVE's to report jOOQ issues
License: Apache License 2.0
A simple example project that can be used to create MCVE's to report jOOQ issues
License: Apache License 2.0
This warning is logged when running the mcve build:
[WARNING] Some problems were encountered while building the effective model for org.jooq:jooq-mcve-java-mariadb:jar:1.0
[WARNING] 'build.plugins.plugin.version' for org.apache.maven.plugins:maven-surefire-plugin is missing. @ line 220, column 21
[WARNING]
[WARNING] Some problems were encountered while building the effective model for org.jooq:jooq-mcve-java-mysql:jar:1.0
[WARNING] 'build.plugins.plugin.version' for org.apache.maven.plugins:maven-surefire-plugin is missing. @ line 220, column 21
[WARNING]
[WARNING] Some problems were encountered while building the effective model for org.jooq:jooq-mcve-java-oracle:jar:1.0
[WARNING] 'build.plugins.plugin.version' for org.apache.maven.plugins:maven-surefire-plugin is missing. @ line 233, column 21
[WARNING]
[WARNING] Some problems were encountered while building the effective model for org.jooq:jooq-mcve-java-postgres:jar:1.0
[WARNING] 'build.plugins.plugin.version' for org.apache.maven.plugins:maven-surefire-plugin is missing. @ line 213, column 21
The version mismatch warning appears in the logs:
15:42:53,418 WARN [jooq.impl.DefaultExecuteContext.logVersionSupport ] - Version mismatch : Database version is older than what dialect H2 supports: 2.1.210 (2022-01-17). Consider https://www.jooq.org/download/support-matrix to see what jOOQ version and edition supports which RDBMS versions.
And indeed, we're not using the latest H2 version. Let's upgrade to 2.1.214
diff --git a/pom.xml b/pom.xml
index bce6874..407642f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -14,8 +14,8 @@
</properties>
<modules>
- <module>jooq-mcve-java</module>
- <module>jooq-mcve-kotlin</module>
- <module>jooq-mcve-scala</module>
+ <module>jOOQ-mcve-java</module>
+ <module>jOOQ-mcve-kotlin</module>
+ <module>jOOQ-mcve-scala</module>
</modules>
</project>
This is a problem on Linux where case matters.
In addition to supporting PostgreSQL with testcontainers (#21), let's support templates as well for:
These won't be part of the modules listed in the parent project, as the commercial dependency won't be available from Maven Central (users tend to build only the relevant child module, so we should be fine)
We're now using the commercial artifact repository in the jOOQ-mcve
repo:
723533a
But given that:
It would probably be better to list Maven Central first, only then the commercial repo, also as a hint that end users should do things this way.
When using the batch insert, the process just used the first bind parameter for all the batch statements
When running a mvn clean install
on the repository, this is the last output:
Exception in thread "Thread-26" Exception in thread "Thread-46" Exception in thread "Thread-34" java.lang.NoClassDefFoundError: org/testcontainers/utility/PathUtils
at org.testcontainers.utility.MountableFile.lambda$deleteOnExit$0(MountableFile.java:318)
at java.base/java.lang.Thread.run(Thread.java:1589)
Caused by: java.lang.ClassNotFoundException: org.testcontainers.utility.PathUtils
... 2 more
java.lang.NoClassDefFoundError: org/testcontainers/utility/PathUtils
at org.testcontainers.utility.MountableFile.lambda$deleteOnExit$0(MountableFile.java:318)
at java.base/java.lang.Thread.run(Thread.java:1589)
Caused by: java.lang.ClassNotFoundException: org.testcontainers.utility.PathUtils
at org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy.loadClass(SelfFirstStrategy.java:50)
at org.codehaus.plexus.classworlds.realm.ClassRealm.unsynchronizedLoadClass(ClassRealm.java:271)
at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:247)
at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:239)
... 2 more
java.lang.NoClassDefFoundError: org/testcontainers/utility/PathUtils
at org.testcontainers.utility.MountableFile.lambda$deleteOnExit$0(MountableFile.java:318)
at java.base/java.lang.Thread.run(Thread.java:1589)
Caused by: java.lang.ClassNotFoundException: org.testcontainers.utility.PathUtils
... 2 more
It appears to be irrelevant to the MCVE, but is still a distraction worth solving.
The default MCVE uses H2, which can be sufficient for a lot of cases that aren't really vendor specific. However, when users want to show something vendor specific, a testcontainers based PostgreSQL MCVE would be more useful. In the future, we might support other dialects, too, but as an example, PostgreSQL should be fine.
To simplify MCVE builds, we can use our own initScript
property instead of the sql-maven-plugin
. The property should only be used once 3.19 is no longer maintained, i.e. a few years from now, perhaps.
This error appears when running the PostgreSQL mcve from within IntelliJ:
org.testcontainers.containers.ContainerLaunchException: Container startup failed
at org.testcontainers.containers.GenericContainer.doStart(GenericContainer.java:349)
at org.testcontainers.containers.GenericContainer.start(GenericContainer.java:322)
at org.jooq.mcve.test.java.postgres.JavaTest.init(JavaTest.java:42)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.RunBefores.invokeMethod(RunBefores.java:33)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: org.rnorth.ducttape.RetryCountExceededException: Retry limit hit with exception
at org.rnorth.ducttape.unreliables.Unreliables.retryUntilSuccess(Unreliables.java:88)
at org.testcontainers.containers.GenericContainer.doStart(GenericContainer.java:334)
... 21 more
Caused by: org.testcontainers.containers.ContainerLaunchException: Could not create/start container
at org.testcontainers.containers.GenericContainer.tryStart(GenericContainer.java:542)
at org.testcontainers.containers.GenericContainer.lambda$doStart$0(GenericContainer.java:344)
at org.rnorth.ducttape.unreliables.Unreliables.retryUntilSuccess(Unreliables.java:81)
... 22 more
Caused by: org.testcontainers.ext.ScriptUtils$ScriptLoadException: Could not load classpath init script: /db/migration/init.sql. Resource not found.
at org.testcontainers.ext.ScriptUtils.runInitScript(ScriptUtils.java:357)
at org.testcontainers.containers.JdbcDatabaseContainer.runInitScriptIfRequired(JdbcDatabaseContainer.java:323)
at org.testcontainers.containers.JdbcDatabaseContainer.containerIsStarted(JdbcDatabaseContainer.java:188)
at org.testcontainers.containers.GenericContainer.containerIsStarted(GenericContainer.java:701)
at org.testcontainers.containers.GenericContainer.tryStart(GenericContainer.java:521)
... 24 more
We'll soon be able to generate code using gradle:
So the MCVE template could offer both Maven and Gradle
Add scripts for
jOOQ supports a few system properties in its code generator:
If we use these (e.g. jooq.codegen.jdbc.url
) instead of ad-hoc ones (e.g. db.url
), then we can save some code and remove some redundancy between maven/gradle scripts
Just like the demo, this project should have an up to date jOOQ dependency: jOOQ/demo#5
Some users can't upgrade to the latest version of jOOQ for good reasons, so it would be useful to have the usual branches in this project as well.
This would allow:
Having trouble using Flyway for the new MySQL template, but for our case, we don't need it. Testcontainers initscripts will be sufficient.:
In addition to supporting PostgreSQL with testcontainers (#21), let's support MySQL templates as well.
When running tests from within the IDE, the testcontainers database isn't ready, because the IDE doesn't run the Maven plugins in this case.
This template project works with jOOQ up to v3.14.12. With jOOQ v3.15.0 a mvn verify
will end in a NullPointerException
.
Steps to reproduce:
mvn verify
-> successpom.xml
line 16mvn verify
-> NullPointerException
This is the stacktrace:
[INFO] --- scala-maven-plugin:4.3.0:compile (default) @ jooq-mcve ---
[INFO] Using incremental compilation using Mixed compile order
[INFO] Compiler bridge file: /Users/mcpringle/.sbt/1.0/zinc/org.scala-sbt/org.scala-sbt-compiler-bridge_2.13-1.3.1-bin_2.13.1__55.0-1.3.1_20191012T045515.jar
[INFO] Compiling 6 Scala sources and 6 Java sources to /Users/mcpringle/IdeaProjects/jOOQ-mcve/target/classes ...
[ERROR] ## Exception when compiling 12 sources to /Users/mcpringle/IdeaProjects/jOOQ-mcve/target/classes
java.lang.NullPointerException
scala.tools.nsc.transform.Erasure$ErasureTransformer$$anon$4.preErase(Erasure.scala:1273)
scala.tools.nsc.transform.Erasure$ErasureTransformer$$anon$4.transform(Erasure.scala:1328)
scala.tools.nsc.transform.Erasure$ErasureTransformer$$anon$4.transform(Erasure.scala:988)
scala.reflect.internal.Trees$Apply.transform(Trees.scala:759)
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:51)
scala.tools.nsc.transform.Erasure$ErasureTransformer$$anon$4.transform(Erasure.scala:1364)
scala.tools.nsc.transform.Erasure$ErasureTransformer$$anon$4.transform(Erasure.scala:988)
scala.reflect.internal.Trees$DefDef.$anonfun$transform$5(Trees.scala:427)
scala.reflect.api.Trees$Transformer.atOwner(Trees.scala:2625)
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:37)
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:32)
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:24)
scala.reflect.internal.Trees$DefDef.transform(Trees.scala:425)
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:51)
scala.tools.nsc.transform.Erasure$ErasureTransformer$$anon$4.transform(Erasure.scala:1354)
scala.tools.nsc.transform.Erasure$ErasureTransformer$$anon$4.transform(Erasure.scala:988)
scala.reflect.api.Trees$Transformer.$anonfun$transformStats$1(Trees.scala:2614)
scala.reflect.api.Trees$Transformer.transformStats(Trees.scala:2612)
scala.reflect.internal.Trees$Template.transform(Trees.scala:517)
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.$anonfun$transform$1(TypingTransformers.scala:47)
scala.reflect.api.Trees$Transformer.atOwner(Trees.scala:2625)
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:37)
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:32)
scala.tools.nsc.transform.Erasure$ErasureTransformer$$anon$4.transform(Erasure.scala:1364)
scala.tools.nsc.transform.Erasure$ErasureTransformer$$anon$4.transform(Erasure.scala:988)
scala.reflect.api.Trees$Transformer.transformTemplate(Trees.scala:2587)
scala.reflect.internal.Trees$ClassDef.$anonfun$transform$2(Trees.scala:335)
scala.reflect.api.Trees$Transformer.atOwner(Trees.scala:2625)
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:37)
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:32)
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:24)
scala.reflect.internal.Trees$ClassDef.transform(Trees.scala:334)
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:51)
scala.tools.nsc.transform.Erasure$ErasureTransformer$$anon$4.transform(Erasure.scala:1364)
scala.tools.nsc.transform.Erasure$ErasureTransformer$$anon$4.transform(Erasure.scala:988)
scala.reflect.api.Trees$Transformer.$anonfun$transformStats$1(Trees.scala:2614)
scala.reflect.api.Trees$Transformer.transformStats(Trees.scala:2612)
scala.reflect.internal.Trees$PackageDef.$anonfun$transform$1(Trees.scala:316)
scala.reflect.api.Trees$Transformer.atOwner(Trees.scala:2625)
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:37)
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:32)
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:24)
scala.reflect.internal.Trees$PackageDef.transform(Trees.scala:316)
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.$anonfun$transform$2(TypingTransformers.scala:49)
scala.reflect.api.Trees$Transformer.atOwner(Trees.scala:2625)
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:37)
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:32)
scala.tools.nsc.transform.Erasure$ErasureTransformer$$anon$4.transform(Erasure.scala:1364)
scala.tools.nsc.transform.Erasure$ErasureTransformer.transform(Erasure.scala:1374)
scala.tools.nsc.ast.Trees$Transformer.transformUnit(Trees.scala:162)
scala.tools.nsc.transform.Transform$Phase.apply(Transform.scala:36)
scala.tools.nsc.Global$GlobalPhase.applyPhase(Global.scala:452)
scala.tools.nsc.Global$GlobalPhase.run(Global.scala:397)
scala.tools.nsc.Global$Run.compileUnitsInternal(Global.scala:1506)
scala.tools.nsc.Global$Run.compileUnits(Global.scala:1490)
scala.tools.nsc.Global$Run.compileSources(Global.scala:1482)
scala.tools.nsc.Global$Run.compile(Global.scala:1614)
xsbt.CachedCompiler0.run(CompilerInterface.scala:153)
xsbt.CachedCompiler0.run(CompilerInterface.scala:125)
xsbt.CompilerInterface.run(CompilerInterface.scala:39)
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.base/java.lang.reflect.Method.invoke(Method.java:566)
sbt.internal.inc.AnalyzingCompiler.call(AnalyzingCompiler.scala:248)
sbt.internal.inc.AnalyzingCompiler.compile(AnalyzingCompiler.scala:122)
sbt.internal.inc.AnalyzingCompiler.compile(AnalyzingCompiler.scala:95)
sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$4(MixedAnalyzingCompiler.scala:91)
scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
sbt.internal.inc.MixedAnalyzingCompiler.timed(MixedAnalyzingCompiler.scala:186)
sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$3(MixedAnalyzingCompiler.scala:82)
sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$3$adapted(MixedAnalyzingCompiler.scala:77)
sbt.internal.inc.JarUtils$.withPreviousJar(JarUtils.scala:215)
sbt.internal.inc.MixedAnalyzingCompiler.compileScala$1(MixedAnalyzingCompiler.scala:77)
sbt.internal.inc.MixedAnalyzingCompiler.compile(MixedAnalyzingCompiler.scala:146)
sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1(IncrementalCompilerImpl.scala:343)
sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1$adapted(IncrementalCompilerImpl.scala:343)
sbt.internal.inc.Incremental$.doCompile(Incremental.scala:120)
sbt.internal.inc.Incremental$.$anonfun$compile$4(Incremental.scala:100)
sbt.internal.inc.IncrementalCommon.recompileClasses(IncrementalCommon.scala:180)
sbt.internal.inc.IncrementalCommon.cycle(IncrementalCommon.scala:98)
sbt.internal.inc.Incremental$.$anonfun$compile$3(Incremental.scala:102)
sbt.internal.inc.Incremental$.manageClassfiles(Incremental.scala:155)
sbt.internal.inc.Incremental$.compile(Incremental.scala:92)
sbt.internal.inc.IncrementalCompile$.apply(Compile.scala:75)
sbt.internal.inc.IncrementalCompilerImpl.compileInternal(IncrementalCompilerImpl.scala:348)
sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileIncrementally$1(IncrementalCompilerImpl.scala:301)
sbt.internal.inc.IncrementalCompilerImpl.handleCompilationError(IncrementalCompilerImpl.scala:168)
sbt.internal.inc.IncrementalCompilerImpl.compileIncrementally(IncrementalCompilerImpl.scala:248)
sbt.internal.inc.IncrementalCompilerImpl.compile(IncrementalCompilerImpl.scala:74)
sbt_inc.SbtIncrementalCompiler.compile(SbtIncrementalCompiler.java:173)
scala_maven.ScalaCompilerSupport.incrementalCompile(ScalaCompilerSupport.java:297)
scala_maven.ScalaCompilerSupport.compile(ScalaCompilerSupport.java:109)
scala_maven.ScalaCompilerSupport.doExecute(ScalaCompilerSupport.java:91)
scala_maven.ScalaMojoSupport.execute(ScalaMojoSupport.java:554)
org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:137)
org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:210)
org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:156)
org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:148)
org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:117)
org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:81)
org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:56)
org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:305)
org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:192)
org.apache.maven.DefaultMaven.execute(DefaultMaven.java:105)
org.apache.maven.cli.MavenCli.execute(MavenCli.java:957)
org.apache.maven.cli.MavenCli.doMain(MavenCli.java:289)
org.apache.maven.cli.MavenCli.main(MavenCli.java:193)
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.base/java.lang.reflect.Method.invoke(Method.java:566)
org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:282)
org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:225)
org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:406)
org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:347)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 27.307 s
[INFO] Finished at: 2021-07-07T18:28:17+02:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal net.alchim31.maven:scala-maven-plugin:4.3.0:compile (default) on project jooq-mcve: Execution default of goal net.alchim31.maven:scala-maven-plugin:4.3.0:compile failed.: NullPointerException -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/PluginExecutionException
Tested with AdoptOpenJDK-11.0.11+9 on macOS Big Sur 11.4 (M1).
Gradle users may have issues setting up an MCVE using Maven. If the problem is purely jOOQ related, then a Maven wrapper might help those users, without them having to set up a Gradle scripts.
(Obviously, it might still be worth supporting Gradle as well, but that's another task for another day).
Apparently, the currently used version doesn't work well with Podman (which can be used instead of Docker):
jOOQ/jOOQ#15766 (comment)
A lot of kotlin users use these optoinal modules, which we could add as dependencies for the MCVE
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.