GithubHelp home page GithubHelp logo

paketo-buildpacks / builder-jammy-base Goto Github PK

View Code? Open in Web Editor NEW
18.0 18.0 8.0 5.55 MB

A Cloud Native Buildpacks (CNB) builder with the Paketo Jammy Jellyfish Base stack and Paketo buildpacks.

License: Apache License 2.0

Shell 31.25% Go 68.75%

builder-jammy-base's People

Contributors

dependabot[bot] avatar foresteckhardt avatar paketo-bot avatar pivotal-david-osullivan avatar robdimsdale avatar sophiewigmore avatar tisvictress avatar

Stargazers

 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

builder-jammy-base's Issues

Image not runnable when changing gitlab-groups

When moving a Project to another group the images produced by the builder get useless. I guess this is because old layer get reused.

Expected Behavior

The container should be executed normally

Current Behavior

The image exits with the following output:
Setting Active Processor Count to 12 unable to determine class count unable to walk /builds/demob/demo lstat /builds/demob/demo: no such file or directory ERROR: failed to launch: exec.d: failed to execute exec.d file at path '/layers/paketo-buildpacks_bellsoft-liberica/helper/exec.d/memory-calculator': exit status 1

Possible Solution

A quickfix is to create a symbolic link inside the container. However this does not work when overwriting the entrypoint.
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "mkdir /builds/demoa": stat mkdir /builds/demoA: no such file or directory: unknown

Steps to Reproduce

The first image was produces within group demob so demoB/demo and pushed in a central repository. Then the project gets moved to another group, in this case demoa.

I pushed the to images to dockerhub: izphi78/buildpacks:pre and izphi78/buildpacks:post

Motivations

The produced images are not usable anymore.

Some error occur when upgrading bionic-base to jammy-base

From Jammy stack.toml and Bionic stack.toml, I found the uid is different.

In jammy stack, the uid is difference between build and runtime phase, and the final /workspace dir is generated by build user, there is no permission for runtime user to do some write operations in the folder.
image

So when we migrate bionic stack to jammy stack, we may meet some errors. E.g. In the spring boot project, if there are some code like Files.copy(Paths.get(source), Paths.get(destination)), then it will be blocked.
image

So why the uid change between the build and runtime phase, and is there any guide to migrate bionic stack to jammy stack smoothly?

Expected Behavior

Current Behavior

Possible Solution

Steps to Reproduce

Motivations

Mirror images to gcr.io

The builder is currently only published to Docker Hub under the name paketobuildpacks/builder-jammy-base. It is not mirrored to other container image registries like gcr.io as it has been in the past for older images such as gcr.io/paketo-buildpacks/builder:base.
At the time of writing, only gcr.io/paketo-buildpacks/build-jammy-base is mirrored from docker.io/paketobuildpacks/build-jammy-base, but docker.io/paketobuildpacks/builder-jammy-base is not mirroed. Note the difference between build and builder in the image names.

Motivations

Developers might run into rate limits when pulling images from Docker Hub.

Implement Builders RFC 0008: Jammy Builders

Describe the Enhancement

Create a builder that allows users to build with most of the Paketo buildpacks on top of the Jammy base stack.

Possible Solution

Motivation

Per Builders RFC 0008, Paketo wants to distribute a Jammy Base Builder that ultimately supports the same set of buildpacks as the Paketo Bionic Base Builder, but uses the Paketo Jammy Jellyfish stacks.

Sample application for python(pip/poetry) not working with builder-jammy-base

Hi Team,

I'm trying to build sample application of python(pip/poetry) available at https://github.com/paketo-buildpacks/samples/tree/main/python using builder-jammy-base but it is giving error while installing poetry.

Command used:

pack build sample-app --builder paketobuildpacks/builder-jammy-base

Logs:

`7 of 10 buildpacks participating
paketo-buildpacks/ca-certificates 3.6.3
paketo-buildpacks/cpython 1.9.0
paketo-buildpacks/pip 0.18.0
paketo-buildpacks/poetry 0.6.5
paketo-buildpacks/poetry-install 0.3.17
paketo-buildpacks/python-start 0.14.14
paketo-buildpacks/procfile 5.6.4
===> RESTORING
===> BUILDING

Paketo Buildpack for CA Certificates 3.6.3
https://github.com/paketo-buildpacks/ca-certificates
Launch Helper: Contributing to layer
Creating /layers/paketo-buildpacks_ca-certificates/helper/exec.d/ca-certificates-helper
Paketo Buildpack for CPython 1.9.0
Resolving CPython version
Candidate version sources (in priority order):
pyproject.toml -> "^3.10"
-> ""
-> ""

Selected CPython version (using pyproject.toml): 3.11.5

Executing build process
Installing CPython 3.11.5
Completed in 12.875s

Generating SBOM for /layers/paketo-buildpacks_cpython/cpython
Completed in 0s

Configuring build environment
PYTHONPATH -> "/layers/paketo-buildpacks_cpython/cpython"
PYTHONPYCACHEPREFIX -> "/tmp"

Configuring launch environment
PYTHONPATH -> "/layers/paketo-buildpacks_cpython/cpython"

Paketo Buildpack for Pip 0.18.0
Resolving Pip version
Candidate version sources (in priority order):
-> ""

Selected Pip version (using ): 23.2.1

Executing build process
Installing Pip 23.2.1
Completed in 22.339s

Generating SBOM for /layers/paketo-buildpacks_pip/pip
Completed in 0s

Configuring build environment
PIP_FIND_LINKS -> "$PIP_FIND_LINKS /layers/paketo-buildpacks_pip/pip-source"

Configuring build environment
PYTHONPATH -> "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages:$PYTHONPATH"

Configuring launch environment
PYTHONPATH -> "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages:$PYTHONPATH"

Paketo Buildpack for Poetry 0.6.5
Resolving Poetry version
Candidate version sources (in priority order):
-> ""

Selected Poetry version (using <unknown>): 1.4.2

Executing build process
Installing Poetry 1.4.2
failed to configure poetry:
Looking in links: /layers/paketo-buildpacks_pip/pip-source
Collecting poetry==1.4.2
Downloading poetry-1.4.2-py3-none-any.whl (222 kB)
ERROR: Exception:
Traceback (most recent call last):
File "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages/pip/_internal/cli/base_command.py", line 180, in exc_logging_wrapper
status = run_func(*args)
^^^^^^^^^^^^^^^
File "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages/pip/_internal/cli/req_command.py", line 248, in wrapper
return func(self, options, args)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages/pip/_internal/commands/install.py", line 377, in run
requirement_set = resolver.resolve(
^^^^^^^^^^^^^^^^^
File "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/resolver.py", line 92, in resolve
result = self._result = resolver.resolve(
^^^^^^^^^^^^^^^^^
File "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages/pip/_vendor/resolvelib/resolvers.py", line 546, in resolve
state = resolution.resolve(requirements, max_rounds=max_rounds)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages/pip/_vendor/resolvelib/resolvers.py", line 397, in resolve
self._add_to_criteria(self.state.criteria, r, parent=None)
File "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages/pip/_vendor/resolvelib/resolvers.py", line 173, in _add_to_criteria
if not criterion.candidates:
File "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages/pip/_vendor/resolvelib/structs.py", line 156, in bool
return bool(self._sequence)
^^^^^^^^^^^^^^^^^^^^
File "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py", line 155, in bool
return any(self)
^^^^^^^^^
File "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py", line 143, in
return (c for c in iterator if id(c) not in self._incompatible_ids)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py", line 47, in _iter_built
candidate = func()
^^^^^^
File "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/factory.py", line 206, in _make_candidate_from_link
self._link_candidate_cache[link] = LinkCandidate(
^^^^^^^^^^^^^^
File "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/candidates.py", line 293, in init
super().init(
File "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/candidates.py", line 156, in init
self.dist = self._prepare()
^^^^^^^^^^^^^^^
File "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/candidates.py", line 225, in _prepare
dist = self._prepare_distribution()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/candidates.py", line 304, in _prepare_distribution
return preparer.prepare_linked_requirement(self._ireq, parallel_builds=True)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages/pip/_internal/operations/prepare.py", line 538, in prepare_linked_requirement
return self._prepare_linked_requirement(req, parallel_builds)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages/pip/_internal/operations/prepare.py", line 609, in _prepare_linked_requirement
local_file = unpack_url(
^^^^^^^^^^^
File "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages/pip/_internal/operations/prepare.py", line 166, in unpack_url
file = get_http_url(
^^^^^^^^^^^^^
File "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages/pip/_internal/operations/prepare.py", line 107, in get_http_url
from_path, content_type = download(link, temp_dir.path)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages/pip/_internal/network/download.py", line 147, in call
for chunk in chunks:
File "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages/pip/_internal/cli/progress_bars.py", line 52, in _rich_progress_bar
with progress:
File "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages/pip/_vendor/rich/progress.py", line 1169, in enter
self.start()
File "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages/pip/_vendor/rich/progress.py", line 1160, in start
self.live.start(refresh=True)
File "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages/pip/_vendor/rich/live.py", line 132, in start
self._refresh_thread.start()
File "/layers/paketo-buildpacks_cpython/cpython/lib/python3.11/threading.py", line 957, in start
_start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread

[notice] A new release of pip is available: 23.2.1 -> 23.3.1
[notice] To update, run: python -m pip install --upgrade pip

error: exit status 2
ERROR: failed to build: exit status 1`

Observation

While using "paketobuildpacks/builder:base" builder the sample application is build successfully and docker image is being created successfully.

Please suggest if any additional parameters are required during build or is there issue with builder-jammy-base.

World-Writable Directories Should Have Their Sticky Bits Set

I'm using the following to build my Image

pack set-default-builder paketobuildpacks/builder-jammy-base
pack build buildpack-java-demo --buildpack paketo-buildpacks/azul-zulu --buildpack paketo-buildpacks/java

Our Qualys container image scan is showing the following Vulnerability.
World-Writable Directories Should Have Their Sticky Bits Set for directory /home/cnb

Specify a particular buildpack in /cnb/lifecycle/creator args.

Describe the Enhancement

Currently this command runs detector to detect the buildpacks it need to use. If we can provide the buildpack as a argument maybe we can save time in overall process.

Possible Solution

add -buildpack as an argument which takes buildpack name for eg paketo-buildpacks/web-servers as value.

Motivation

I have used framework detection in my code and from there itself I can determine the buildpack to be use. I am hoping with this feature maybe we can save some time to create the image. pack command already has flag --buildpack in which we can pass the buildpack name.

Please release a new builder

In order to be able to use latest lifecycle v0.19 a new builder is required. When do you plan a release?

Context: ATM it is impossible to build against platform APi v0.13.

Describe the Enhancement

Possible Solution

Motivation

Fatal error: com.oracle.svm.core.util.VMError$HostedError: guarantee failed

Hi, I'm trying to use the paketo-buildpacks for my spring native project. I'm trying paketo as a POC. This is building good, if I have not enabled the datadog agent. Soon after I enabled the datadog agent (BP_DATADOG_ENABLED = true) , Im getting the "Fatal error: com.oracle.svm.core.util.VMError$HostedError: guarantee failed" Im Using graalvm 17 and using the paketo latest (tried old versions aswell) , Ran in windows and also in github actions runner.

Expected Behavior

Should be able to build the native image with the datadog agent enabled.

Current Behavior

Im getting the "Fatal error: com.oracle.svm.core.util.VMError$HostedError: guarantee failed"

Possible Solution

Steps to Reproduce

  1. Create a new spring boot gradle kotlin project (enabled with spring jpa , spring native ).
    Enable the paketo buildpacks and enable the datadog agent.

Motivations

I'm trying to use the paketo-buildpacks for my spring native project. I'm trying paketo as a POC.
Below is the complete error:

[2/8] Performing analysis... [] (76.7s @ 2.22GB) [creator] 30,109 (86.88%) of 34,655 types reachable [creator] 48,519 (63.34%) of 76,601 fields reachable [creator] 127,551 (56.10%) of 227,370 methods reachable [creator] 9,200 types, 801 fields, and 7,282 methods registered for reflection [creator] [creator] Fatal error: com.oracle.svm.core.util.VMError$HostedError: guarantee failed [creator] at org.graalvm.nativeimage.builder/com.oracle.svm.core.util.VMError.shouldNotReachHere(VMError.java:72) [creator] at org.graalvm.nativeimage.builder/com.oracle.svm.core.util.VMError.guarantee(VMError.java:86) [creator] at org.graalvm.nativeimage.builder/com.oracle.svm.core.hub.ClassForNameSupport.registerClass(ClassForNameSupport.java:63) [creator] at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.reflect.ReflectionDataBuilder.registerTypesForGenericSignature(ReflectionDataBuilder.java:726) [creator] at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.reflect.ReflectionDataBuilder.registerTypesForGenericSignature(ReflectionDataBuilder.java:683) [creator] at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.reflect.ReflectionDataBuilder.registerTypesForGenericSignature(ReflectionDataBuilder.java:677) [creator] at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.reflect.ReflectionDataBuilder.registerTypesForClass(ReflectionDataBuilder.java:564) [creator] at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.reflect.ReflectionDataBuilder.registerHeapDynamicHub(ReflectionDataBuilder.java:966) [creator] at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.heap.SVMImageHeapScanner.onObjectReachable(SVMImageHeapScanner.java:155) [creator] at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.heap.ImageHeapScanner.lambda$createImageHeapObject$5(ImageHeapScanner.java:396) [creator] at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.heap.ImageHeapScanner.lambda$postTask$14(ImageHeapScanner.java:759) [creator] at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.util.CompletionExecutor.executeCommand(CompletionExecutor.java:187) [creator] at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.util.CompletionExecutor.lambda$executeService$0(CompletionExecutor.java:171) [creator] at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1395) [creator] at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373) [creator] at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182) [creator] at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655) [creator] at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622) [creator] at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165) [creator] -------------------------------------------------------------------------------- [creator] 15.9s (16.6% of total time) in 87 GCs | Peak RSS: 4.37GB | CPU load: 9.77 [creator] ================================================================================ [creator] Finished generating 'com.emisinsights.medassistant.batch.BatchApplicationKt' in 1m 33s. [creator] unable to invoke layer creator [creator] unable to contribute native-image layer

Java Native image not working on Kubernetes

After creating the native image with gradle wrapper ./gradlew bootBuildImage I can run launch the image locally with docker, but when i deploy it to kubernetes the pod starts a crashbackoff loop, and the logs are empty. I tried this both locally with the docker desktop kubernetes cluster, and in my azure aks cluster.

My gradle configurations is

bootBuildImage {
	environment = [
			"BP_JVM_VERSION" : "21",
			"BP_NATIVE_IMAGE": "true",
			"BP_NATIVE_IMAGE_BUILD_ARGUMENTS": "-H:-UseContainerSupport"
	]
	builder = "paketobuildpacks/builder-jammy-base:latest"
}

Expected Behavior

The pod should run as the container does locally.

Current Behavior

The pod enters a crashbackoff loop and no logs are shown.

Steps to Reproduce

  1. Create a sample spring boot 3 project with gradle as build tool, version 8.4 and java 21
  2. run ./gradlew bootBuildImage
  3. run it locally with docker and check it works
  4. run it in a kubernetes cluster

Tekton Pipeline Migrating From paketobuildpacks/builder:base To paketobuildpacks/builder-jammy-base

The Tekton pipeline was working fine until the migration to Jammy. The only pipeline code changed was the image builder name.

  1. On the "buildpacks" (https://hub.tekton.dev/tekton/task/buildpacks) task the "prepare" step works fine and I can see the permissions being applied:
> Setting permissions on '/workspace/cache'...
> Setting permissions on '/tekton/home'...
> Setting permissions on '/layers'...
> Setting permissions on '/workspace/source'...
> Parsing additional configuration...
-> Parsing env variables...
> Processing any environment variables...
--> Creating 'env' directory: /platform/env
--> Writing /platform/env/BP_NATIVE_IMAGE...
--> Writing /platform/env/BP_JVM_VERSION...
--> Writing /platform/env/BP_GRADLE_BUILD_ARGUMENTS...
--> Writing /platform/env/BP_GRADLE_BUILT_ARTIFACT...
--> Writing /platform/env/REPOSITORY_NAME...
--> Writing /platform/env/REPOSITORY_URL...
--> Writing /platform/env/REPOSITORY_USERNAME...
--> Writing /platform/env/REPOSITORY_PASSWORD...
  1. Then the second task "create" fails with the error below:
2024/02/10 19:44:47 warning: unsuccessful cred copy: ".docker" from "/tekton/creds" to "/": unable to create destination directory: mkdir /.docker: permission denied

ERROR: failed to set environment for user 1000: user: unknown userid 1000

Extra utilities like curl, netstat for docker image

Hi Team,

As observed in docker image being created using jammy-base builder the extra utilities like curl, netstat are not available.

Enhancement:

Possibility to add extra utility like curl, netstat through command line .

Is there any possibility we can pass any arguments to install curl and other utilities so that teams/developer can debug if there is any issue as right now there is no utility being present for debugging purpose.

Permission problem with using Jammy builder

Expected Behavior

We can run the container without permission trouble in case using React APP (npm start for development).
As a successful example, I will show the case of using bionic based builder.

$ pack build test-bionic --builder paketobuildpacks/builder:base
(snip..)
Successfully built image test-bionic

$ docker run -p 3000:3000 test-bionic:latest
(snip..)
Starting the development server...
(snip..)
Compiled successfully!
(snip..)
webpack compiled successfully
Compiling...
Compiled successfully!
webpack compiled successfully

Current Behavior

Failed to run the container with permission trouble when using Jammy based builder.

$ pack build test-jammy --builder paketobuildpacks/builder-jammy-base
(snip..)
Successfully built image test-jammy

$ docker run -p 3000:3000 test-jammy:latest
(snip..)
Starting the development server...
(snip..)
Failed to compile.

[eslint] EACCES: permission denied, open '/workspace/node_modules/.cache/.eslintcache'
ERROR in [eslint] EACCES: permission denied, open '/workspace/node_modules/.cache/.eslintcache'

webpack compiled with 1 error

I guess #278 may be related.

Possible Solution

I will probably go back to bionic based builder for a while for React development.
However, bionic is not good for a security perspective. So I hope this issue will be fixed.

Steps to Reproduce

  1. Prepare react app
$ npx create-react-app my-app
(snip..)
Happy hacking!
$ cd my-app
$ ls -a
.                 .git              README.md         package-lock.json public
..                .gitignore        node_modules      package.json      src
  1. Just try Expected (or Current) Behavior

Motivations

I think it's a very basic scenario when we develop React App.
If we can't do it, we need to go back dockerfile.

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.