Coder Social home page Coder Social logo

luaul's Introduction

Lua-UL uses new capabilities of the LuaTeX engine to provide underlining/strikethrough/highlighting etc. support without breaking ligatures, kerning or restricting input.

Requires LuaTeX version >=1.12.0.

Licensed under the LaTeX Project Public License 1.3c, maintained by Marcel Krüger [email protected]

luaul's People

Contributors

zauguin avatar moewew avatar

Stargazers

N. V. Lang avatar Oliver Kopp avatar Josef Friedrich avatar Martin Sievers avatar Yu Xiong avatar Salim Bou  avatar  avatar

Watchers

James Cloos avatar  avatar Salim Bou  avatar Martin Sievers avatar  avatar

luaul's Issues

Error with texlive 2024

The following test document throws an error if I compile with texlive 2024 (pretest):

% !TeX TS-program = lualatex
\documentclass{article}
\usepackage{lua-ul}

\begin{document}
test
\end{document}

(it works fine with an up-to-date texlive 2023)

Log file:

This is LuaHBTeX, Version 1.18.0 (TeX Live 2024)  (format=lualatex 2024.2.23)  25 FEB 2024 19:31
 restricted system commands enabled.
**document.tex
(./document.tex
LaTeX2e <2023-11-01> patch level 1
L3 programming layer <2024-02-20>
Lua module: luaotfload 2024-02-14 3.27 Lua based OpenType font support
Lua module: lualibs 2023-07-13 2.76 ConTeXt Lua standard libraries.
Lua module: lualibs-extended 2023-07-13 2.76 ConTeXt Lua libraries -- extended c
ollection.
luaotfload | conf : Root cache directory is "/usr/local/texlive/2024/texmf-var/l
uatex-cache/generic/names".
luaotfload | init : Loading fontloader "fontloader-2023-12-28.lua" from kpse-res
olved path "/usr/local/texlive/2024/texmf-dist/tex/luatex/luaotfload/fontloader-
2023-12-28.lua".
Lua-only attribute luaotfload@noligature = 1
luaotfload | init : Context OpenType loader version 3.134
Inserting `luaotfload.node_processor' in `pre_linebreak_filter'.
Inserting `luaotfload.node_processor' in `hpack_filter'.
Inserting `luaotfload.glyph_stream' in `glyph_stream_provider'.
Inserting `luaotfload.define_font' in `define_font'.
Lua-only attribute luaotfload_color_attribute = 2
luaotfload | conf : Root cache directory is "/usr/local/texlive/2024/texmf-var/l
uatex-cache/generic/names".
Inserting `luaotfload.harf.strip_prefix' in `find_opentype_file'.
Inserting `luaotfload.harf.strip_prefix' in `find_truetype_file'.
Removing  `luaotfload.glyph_stream' from `glyph_stream_provider'.
Inserting `luaotfload.harf.glyphstream' in `glyph_stream_provider'.
Inserting `luaotfload.harf.finalize_vlist' in `post_linebreak_filter'.
Inserting `luaotfload.harf.finalize_hlist' in `hpack_filter'.
Inserting `luaotfload.cleanup_files' in `wrapup_run'.
Inserting `luaotfload.harf.finalize_unicode' in `finish_pdffile'.
Inserting `luaotfload.glyphinfo' in `glyph_info'.
Lua-only attribute luaotfload.letterspace_done = 3
Inserting `luaotfload.aux.set_sscale_dimens' in `luaotfload.patch_font'.
Inserting `luaotfload.aux.set_font_index' in `luaotfload.patch_font'.
Inserting `luaotfload.aux.patch_cambria_domh' in `luaotfload.patch_font'.
Inserting `luaotfload.aux.fixup_fontdata' in `luaotfload.patch_font_unsafe'.
Inserting `luaotfload.aux.set_capheight' in `luaotfload.patch_font'.
Inserting `luaotfload.aux.set_xheight' in `luaotfload.patch_font'.
Inserting `luaotfload.rewrite_fontname' in `luaotfload.patch_font'.
Inserting `tracingstacklevels' in `input_level_string'. (/usr/local/texlive/202
4/texmf-dist/tex/latex/base/article.cls
Document Class: article 2023/05/17 v1.4n Standard LaTeX document class
(/usr/local/texlive/2024/texmf-dist/tex/latex/base/size10.clo
File: size10.clo 2023/05/17 v1.4n Standard LaTeX file (size option)
luaotfload | db : Font names database loaded from /usr/local/texlive/2024/texmf-
var/luatex-cache/generic/names/luaotfload-names.luc.gz)
\c@part=\count186
\c@section=\count187
\c@subsection=\count188
\c@subsubsection=\count189
\c@paragraph=\count190
\c@subparagraph=\count191
\c@figure=\count192
\c@table=\count193
\abovecaptionskip=\skip48
\belowcaptionskip=\skip49
\bibindent=\dimen139
)
(/usr/local/texlive/2024/texmf-dist/tex/lualatex/lua-ul/lua-ul.sty
Package: lua-ul 2022-05-31 v0.2.0 Underlining and related functionality for Lua
TeX
Lua function luaul.restore_everyhbox = 25
Lua function luaul.new_underline_type = 26
Lua function luaul.set_underline_func = 27
Lua function luaul.reset_underline_func = 28...-dist/tex/lualatex/lua-ul/pre_app
end_to_vlist_filter.lua:30: attempt to call a nil value (field 'getupvalue')
stack traceback:
	...-dist/tex/lualatex/lua-ul/pre_append_to_vlist_filter.lua:30: in main chunk
	[C]: in function 'require'
	...l/texlive/2024/texmf-dist/tex/lualatex/lua-ul/lua-ul.lua:426: in local 'load
er'
	...cal/texlive/2024/texmf-dist/tex/latex/l3kernel/expl3.lua:233: in upvalue 'tr
y_require'
	...cal/texlive/2024/texmf-dist/tex/latex/l3kernel/expl3.lua:248: in function <.
..cal/texlive/2024/texmf-dist/tex/latex/l3kernel/expl3.lua:247>.
<argument> \__lua_load_module_p:n {lua-ul}
                               
l.36 \lua_load_module:n {lua-ul}
                              
The lua interpreter ran into a problem, so the
remainder of this lua chunk will be ignored.

! Argument of \use_none:nn has an extra }.
<inserted text> 
\par 
l.36 \lua_load_module:n {lua-ul}
                              
I've run across a `}' that doesn't seem to match anything.
For example, `\def\a#1{...}' and `\a}' would produce
this error. If you simply proceed now, the `\par' that
I've just inserted will cause me to report a runaway
argument that might be the root of the problem. But if
your `}' was spurious, just type `2' and it will go away.

Runaway argument?
! Paragraph ended before \use_none:nn was complete.
<to be read again> 
\par 
l.36 \lua_load_module:n {lua-ul}
                              
I suspect you've forgotten a `}', causing me to apply this
control sequence to too much text. How can we recover?
My plan is to forget the whole thing and hope for the best.

! Missing number, treated as zero.
<to be read again> 
)
l.36 \lua_load_module:n {lua-ul}
                              
A number should have been here; I inserted `0'.
(If you can't figure out why I needed to see a number,
look up `weird error' in the index to The TeXbook.)


! LaTeX Error: Lua module `lua-ul' not found.

For immediate help type H <return>.
 ...                                              
                                                  
l.36 \lua_load_module:n {lua-ul}
                              

The file `lua-ul.lua' could not be found. Please ensure that the file was
properly installed and that the filename database is current.

The Lua loader provided this additional information:



\l__luaul_top_dim=\dimen140
\l__luaul_bottom_dim=\dimen141
\l__luaul_height_dim=\dimen142
) (/usr/local/texlive/2024/texmf-dist/tex/latex/l3backend/l3backend-luatex.def
File: l3backend-luatex.def 2024-02-20 L3 backend support: PDF output (LuaTeX)
\l__color_backend_stack_int=\count194
Inserting `l3color' in `luaotfload.parse_color'.
\l__pdf_internal_box=\box51
) (./document.aux)
\openout1 = document.aux

LaTeX Font Info:    Checking defaults for OML/cmm/m/it on input line 5.
LaTeX Font Info:    ... okay on input line 5.
LaTeX Font Info:    Checking defaults for OMS/cmsy/m/n on input line 5.
LaTeX Font Info:    ... okay on input line 5.
LaTeX Font Info:    Checking defaults for OT1/cmr/m/n on input line 5.
LaTeX Font Info:    ... okay on input line 5.
LaTeX Font Info:    Checking defaults for T1/cmr/m/n on input line 5.
LaTeX Font Info:    ... okay on input line 5.
LaTeX Font Info:    Checking defaults for TS1/cmr/m/n on input line 5.
LaTeX Font Info:    Trying to load font information for TS1+cmr on input line 5
.
 (/usr/local/texlive/2024/texmf-dist/tex/latex/base/ts1cmr.fd
File: ts1cmr.fd 2023/04/13 v2.5m Standard LaTeX font definitions
)
LaTeX Font Info:    ... okay on input line 5.
LaTeX Font Info:    Checking defaults for TU/lmr/m/n on input line 5.
LaTeX Font Info:    ... okay on input line 5.
LaTeX Font Info:    Checking defaults for OMX/cmex/m/n on input line 5.
LaTeX Font Info:    ... okay on input line 5.
LaTeX Font Info:    Checking defaults for U/cmr/m/n on input line 5.
LaTeX Font Info:    ... okay on input line 5.
[1

{/usr/local/texlive/2024/texmf-var/fonts/map/pdftex/updmap/pdftex.map}]
(./document.aux)
 ***********
LaTeX2e <2023-11-01> patch level 1
L3 programming layer <2024-02-20>
 ***********
)

Here is how much of LuaTeX's memory you used:
 571 strings out of 476468
 100000,1977958 words of node,token memory allocated
 406 words of node memory still in use:
   3 hlist, 1 vlist, 1 rule, 2 glue, 3 kern, 1 glyph, 4 attribute, 48 glue_spec,
 4 attribute_list, 1 write nodes
   avail lists: 2:22,3:4,4:2,5:22,6:2,7:36,9:18
 22725 multiletter control sequences out of 65536+600000
 15 fonts using 723367 bytes
 35i,5n,55p,149b,125s stack positions out of 10000i,1000n,20000p,200000b,200000s
</Users/username/Library/Fonts/lmroman10-regular.otf>
Output written on document.pdf (1 page, 2858 bytes).

PDF statistics: 15 PDF objects out of 1000 (max. 8388607)
 8 compressed objects within 1 object stream
 0 named destinations out of 1000 (max. 131072)
 1 words of extra memory for PDF output out of 10000 (max. 100000000)

Examples, Use cases

I'm using LuaTeX so this package sounds interesting to me. Thanks for sharing.
Nevertheless, I'm afraid that the effects of lua-ul are still a bit unclear.
Would it be possible to get some representative examples of usage, a comparative of with and w/o the package ?

support for OpTeX

It would be nice to be able to use this package together with the OpTeX format. If you will be willing to do so, i'll request the developer of the format to add the pre_append_to_vlist_filter call back so it would be easier to do so.

Just for a proof of concept:, the following diff works:

diff --git a/lua-ul.dtx b/lua-ul.dtx
index d389573..4cf09ed 100644
--- a/lua-ul.dtx
+++ b/lua-ul.dtx
@@ -455,6 +455,21 @@ local underline_types = {}
 local underline_strict_flag = {}
 local underline_over_flag = {}
 
+local format = tex.formatname
+local latex, optex
+
+if format:find("latex") then 
+	latex = true
+elseif format:find("optex") then
+	optex = true
+	function luatexbase.new_luafunction(name)
+	  return #functions + 1
+	end
+else
+	texerror("Unsupported format", {"Please use LaTeX or OpTeX."})
+end
+
+
 local vmode do
   for k, v in pairs(tex.getmodevalues()) do
   if v == "vertical" then
@@ -610,16 +625,16 @@ local function reset_underline()
   tex.attribute[j] = -0x7FFFFFFF
 end
 local new_underline_type_func =
-    luatexbase.new_luafunction"luaul.new_underline_type"
-local set_underline_func =
-    luatexbase.new_luafunction"luaul.set_underline_func"
-local reset_underline_func =
-    luatexbase.new_luafunction"luaul.reset_underline_func"
+	luatexbase.new_luafunction"luaul.new_underline_type"
 set_lua("LuaULNewUnderlineType", new_underline_type_func)
-set_lua("LuaULSetUnderline", set_underline_func, "protected")
-set_lua("LuaULResetUnderline", reset_underline_func, "protected")
 functions[new_underline_type_func] = new_underline_type
+local set_underline_func =
+	luatexbase.new_luafunction"luaul.set_underline_func"
+set_lua("LuaULSetUnderline", set_underline_func, "protected")
 functions[set_underline_func] = set_underline
+local reset_underline_func =
+	luatexbase.new_luafunction"luaul.reset_underline_func"
+set_lua("LuaULResetUnderline", reset_underline_func, "protected")
 functions[reset_underline_func] = reset_underline
 
 %    \end{macrocode}
@@ -846,8 +861,37 @@ function add_underline_hbox(head, attr, outervalue, set_height_depth)
   end
   set_attribute(head, attr, outervalue and -outervalue or 0)
 end
-require'pre_append_to_vlist_filter'
-luatexbase.add_to_callback('pre_append_to_vlist_filter',
+local filter_callback
+local filter_callback_return
+if optex then 
+	filter_callback = 'append_to_vlist_filter'
+	function filter_callback_return(b, prev, mirror)
+		local new_b = tonode(b)
+	  	local new_prev = mirror and new_b.height or new_b.depth
+		if prev > -65536000 then
+		  local lineglue = tex.baselineskip.width - prev - (mirror and new_b.depth or new_b.height)
+		  local skip
+		  if lineglue < tex.lineskiplimit then
+		    skip = node.new('glue', 1)
+		    node.setglue(skip, node.getglue(tex.lineskip))
+		  else
+		    skip = node.new('glue', 2)
+		    node.setglue(skip, node.getglue(tex.baselineskip))
+		    skip.width = lineglue
+		  end
+		  skip.next = new_b
+		  new_b = skip
+		end
+		return new_b, new_prev
+	end
+else
+	filter_callback = 'pre_append_to_vlist_filter'
+	function filter_callback_return(b, prev, mirror)
+		return tonode(b)
+	end
+	require'pre_append_to_vlist_filter'
+end
+luatexbase.add_to_callback(filter_callback,
     function(b, loc, prev, mirror)
       local props = properties[todirect(texnest.top.head)]
       props = props and props.luaul_attributes
@@ -875,7 +919,7 @@ luatexbase.add_to_callback('pre_append_to_vlist_filter',
           end
         end
       end
-      return tonode(b)
+	  return filter_callback_return(b, prev, mirror)
     end, 'add underlines to list')
 luatexbase.add_to_callback('hpack_filter',
     function(head, group, size, pack, dir, attr)

Test file

\fontfam[lm]
\directlua{require'lua-ul'}
\edef\underLine{\LuaULSetUnderline
		\LuaULNewUnderlineType{\leaders\vrule height-1ptdepth1.5pt\hskip0pt}}
		
{\underLine Hello} World!

\bye

A few notes... if OpTeX will add the pre_append_to_vlist_filter call back, the patch would be much smaller. The only problem is that OpTeX does not use luatexbase, and so it does not define luatexbase.new_luafunction. It only define a small subset of luatexbase functions (or aliases of them) for compatibility with luaotfload.

Failure to underline blank space with \par following the underLine command

Hello! I'm working with @FengChendian in a recent LaTeX project. It is proved that the latest version of luatex-ja successfully fixed the issue with Chinese underlining, and please accept my gratitude for your efforts.

However, there is one thing that remains. In the template I used to follow the underlined text right with \par to force a line break, like the MWE below shows:

\documentclass{article}
\usepackage{lua-ul}
\begin{document}
Here is some text: \underLine{This is a long message. It must be awfully long, so long that it can't be contained in one single line.\hfill}\par
The following text.
\end{document}

It will be noticed that in this example \hfill failed to extend the underline to the end of line.

In the end I have to add an extra \hspace{0em} to protect the \par command, like this:

\documentclass{article}
\usepackage{lua-ul}
\begin{document}
Here is some text: \underLine{This is a long message. It must be awfully long, so long that it can't be contained in one single line.\hfill}\hspace{0em}\par
The following text.
\end{document}

And moving \par to a new line would save the format in English context, but not with Chinese.

So I am concerned whether \par would make the package misjudge the length of underline. I hope this could do some help in the improvement of the package.

Bad interaction with esvect

The following code

\documentclass{standalone}

\usepackage[c]{esvect}
\usepackage[soul]{lua-ul}

\begin{document}

\ul{$\vv{e}$}                                                                                                                                                                                                                                                                  

\end{document}

fails to compile with ! error: (alignment): bad box. It does work with soulutf8 instead of lua-ul, so I’m asking here, but if you have reasons to think this is esvect fault, please tell me why and I’ll forward to the esvect author.

Changing color

I'm trying to define underwave command written using TikZ. However, the source below doesn't work though it seems to work correctly.

\documentclass{article}
\usepackage{lua-ul}
\usepackage{tikz}

\newcommand{\mycolor}{}

\newunderlinetype\beginUnderWavy{\cleaders\hbox to 1.5708ex{%
\hss
\begin{tikzpicture}[x=.25ex,y=.25ex,baseline=.9ex,xscale=1.5708]
\draw[color=\mycolor] (0,0) sin (1,1) cos (2,0) sin (3,-1) cos (4,0);
\end{tikzpicture}%
}}

\NewDocumentCommand\uwave{O{black} +m}{\renewcommand{\mycolor}{#1}{\beginUnderWavy#2}}
\begin{document}\noindent
\uwave{black underwave?}\\
\uwave[red]{red underwave?}\\
\renewcommand{\mycolor}{black}
\begin{tikzpicture}[x=.25ex,y=.25ex,baseline=.9ex,xscale=1.5708]
\draw[color=\mycolor] (0,0) sin (1,1) cos (2,0) sin (3,-1) cos (4,0);
\end{tikzpicture}\\
\renewcommand{\mycolor}{red}
\begin{tikzpicture}[x=.25ex,y=.25ex,baseline=.9ex,xscale=1.5708]
\draw[color=\mycolor] (0,0) sin (1,1) cos (2,0) sin (3,-1) cos (4,0);
\end{tikzpicture}
\end{document}

image

Strikethrough and square brackets

With lua-ul package version 1.7. I cannot write

\strikeThrough{[Note.: }

since the [ is a symbol not recognized properly. Writting {[} or \lbrack fixes the problem. The even simpler fix is to write

\strikeThrough{{}[Note.: }

Perhaps it could be fixed by default?

Rule color changing on new line with changed text color

Consider this MWE:

\documentclass{article}

\usepackage{lua-ul}
\usepackage{color}

\begin{document}

\underLine{This is a very long line that is supposed to break and wrap
  around. The color of the underline should be the default color throughout
  \textcolor{blue}{the whole text. However, if I switch the text color to blue,
    then the underline starts in blue on the next line.}}

\end{document}

Not sure whether this is a bug or a feature. What I would like is that the color of the underline stays the same throughout the whole underlined passage. Any chance of fixing this?

Thank you for your time and the excellent package that you provide. This might be an edge case, but I really appreciate being able to underline while striking through at the same time.

lua-ul loops in compilation with pdflatex

(extracted from https://tex.stackexchange.com/q/718530/2388)

If a document using lua-ul is compiled with pdflatex in nonstopmode it loops:

\documentclass{article}
\usepackage{lua-ul}
\begin{document}
blub
\end{document}
! Undefined control sequence.
<output> {\LuaULResetUnderline 
                               *\let \par \@@par \ifnum \outputpenalty <-\@M...
l.12 \end{document}
                   
The control sequence at the end of the top line
of your error message was never \def'ed. If you have
misspelled it (e.g., `\hobx'), type `I' and the correct
spelling (e.g., `I\hbox'). Otherwise just continue,
and I'll forget about whatever was undefined.

! Undefined control sequence.
<output> {\LuaULResetUnderline 
                               *\let \par \@@par \ifnum \outputpenalty <-\@M...
l.12 \end{document}

I would suggest to add after (or at least before redefining the kernel commands and \output)

\sys_if_engine_luatex:F {
  \msg_error:nn {lua-ul} {luatex-required}
}
\sys_if_engine_luatex:F {
  \endinput
}

Just a noob who who needs some help

I just want to change the styling on my underline. You mention you can pass some options too underLine but this \\underLine[color=red,bottom=2pt]{some text} isn't working me. How do I change the options? Can you provide an example? thanks.

Highlighting of texttt

When I highlight a text which is encapsulated in a texttt the highlighting seems to have random additional space in front. e.g.

\newcommand{\code}[1]{ \highLight[{[HTML]{D3D3D3}}]{\texttt{#1}}}
* Die Kapiteln können nur dann in der Lasche \code{Bearbeiten} gesehen werden, wenn der Benutzer im Gesamtdokument die Berechtigung \code{Zugang} hat.

See as well https://tex.stackexchange.com/q/596753/48642. The reverse order of commands works fine.

0.1.2 version required

#4 is there a release of this package coming soon? Since I need that kind of package quite urgently and download and compile by myself is little bit tricky. Especially since I know what's the root cause of the problem is.

ETA for CTAN?

Conflict with selnolig package (load order matters)

When the selnolig package has been loaded before, defining lua-ul functions fails:

Lua function luaul.reset_underline_func = 14...-dist/tex/lualatex/lua-ul/pre_app
end_to_vlist_filter.lua:30: attempt to index a boolean value (global 'debug').
l.30 \directlua{require'lua-ul'}
                              
The lua interpreter ran into a problem, so the
remainder of this lua chunk will be ignored.

Changing the load order solves the issue. This should at least be documented or if possible be fixed.

MWE:

\documentclass{article}
\usepackage{fontspec}
\usepackage{selnolig}
\usepackage[soul]{lua-ul}
\begin{document}
   Test\st{Test} \ul{TEST}
\end{document}

Extension of the macro `\underLine`

Hi, I'm moving old files to LuaLaTeX and many of the soul capabilities can be done directly with fontspec and lua-ul. I think it would be nice to have an extension like key=val for \undeLine, something like:

\underLine[ul-color=some color, ul-width = some width, ul-depth = some dim]{awesome}

(don't take into account the names of the keys, I'm not very witty)

That is, to be able to better control the colour, width and depth (or vertical spacing) of \underLine. Something like this will be possible?

Saludos

\underLine does not work with align environment

Minimal (non-)working example:

\documentclass{article}
\usepackage{lua-ul}
\usepackage{amsmath}

\begin{document}
\[\underLine{This\ is\ underlined}\]
\begin{align}\underLine{This\ is\ not}\end{align}
\end{document}

Not sure if it should be considered a bug of amsmath or lua-ul…

$ lualatex --version
This is LuaTeX, Version 1.12.0 (TeX Live 2020 Gentoo Linux)

Cheers

unhbox and unvbox not supported?

I found unhbox and unvbox are not supported.
I think these are very important.

(LuaHBTeX, Version 1.17.0 (TeX Live 2023)) + lua-ul [2022-05-31]

\documentclass{article}

\usepackage{luacolor}
\usepackage[soul]{lua-ul}

\begin{document}
Inside underLine / strikeThrough / highLight,
unhbox and unvbox are not affected by the command.

\underLine{This is a test: \setbox0\hbox{abc}\unhbox0, \setbox0\vbox{abc}\unvbox0, OK?}

\strikeThrough{This is a test: \setbox0\hbox{abc}\unhbox0, \setbox0\vbox{abc}\unvbox0, OK?}

\highLight{This is a test: \setbox0\hbox{abc}\unhbox0, \setbox0\vbox{abc}\unvbox0, OK?}

\end{document}

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.