blefloch / latex-unravel Goto Github PK
View Code? Open in Web Editor NEWWatching TeX digest tokens
Watching TeX digest tokens
The error recovery for non-\long
macros which have simple arguments (#1#2#3...
) when they receive \par
is different in unravel
than in TeX.
\RequirePackage{unravel}
\def\test#1{}
\unravel{\test\par}
internally finds the argument \par
, braces it, then expands \test{\par}
. TeX complains that there is a runaway argument, and drops everything until the \par
. That leaves a brace that has no reason to be there.
This is a question and perhaps a feature request.
Is there a nice way to obtain the unraveled TeX code (the FINAL step shown before the compiler exits)?
Basically, I have to move some math LaTeX code to MathJax, and since MathJax supports less features that LaTeX, the most unravelled code is what I'm after. A good solution would be a script that takes in the LaTeX code and outputs the unravelled code.
\dimen0\relax
gives "Missing number" and "Illegal unit" errors, while
\dimen0\tenrm
gives only the first error (assuming \font\tenrm=cmr10\relax
). Similarly, \muskip0\relax
gives "Missing number" and "Illegal unit", while \musip0\tenrm
gives "Missing number" and "Incompatible glue units" errors.
This is due to the fact that \tenrm
is "something internal" hence is scanned by the TeX procedure scan_something_internal
, which throws a "Missing number" error then inserts the equivalent of \c_zero_dim
.
The list of possible commands should appear in the pdf documentation, with explanations. The detailed behaviour should be explained, and the code altered to reflect the expected behaviour.
Among other things, it should be noted that it is possible to do C\unravelsetup{
<options>
}
to set some options within an \unravel
.
It would be good to have better error messages in case of the rather common "runaway argument" error. However, this is very tricky to do in general since \unravel
must then grab arguments itself, hence must be able to determine the exact delimiters expected by the macro. All this must be done safely. Here is a possible approach.
\escapechar=32
(space). Loop through characters until finding one that does not appear in the macro's \meaning
. If none is available, give up optimizing. Save the character found (assumed below to be the 0
character ^^@
). Close the group.\escapechar=0
and \catcode0=0
(the first and second 0
have to do with the character found above, the last means that we set that character to be of category escape).\meaning
. Set to 11
the catcode of any character which follows ^^@
in this \meaning
, then get a third version of the \meaning
: in it, every control sequence is followed by a space (careful: there may be control sequences containing spaces in their names). Save this \meaning
. Close the group.^^@
<characters>
<space>
with more than one character, set the catcode of every character to 11
(letter), as this was their catcode when the macro was defined (barring trickery). (That step is probably slow and is not needed in the \char_generate:nn
approach below.) If any of the corresponding control sequences is a macro parameter, give up (important!). At the same time, keep track of catcode 1 and catcode 2 characters in between such patterns and give up if the difference ever has the wrong sign. Set \catcode32=10
, as it would not be possible to avoid extraneous spaces otherwise anyway.#
). Using \scantokens
later should be safe (barring \outer
tokens)\meaning
. Split it into prefix, arguments, and replacement code (this is provided by expl3
), then build a proposal for the macro's definition. The prefixes is straightforward. The rest can use \scantokens
. Define a macro using that data. If that matches the original macro, then great! Otherwise give up.Possible improvement: figure out which character is the macro parameter character.
Alternative approach: go through the \meaning
in an \edef
, leaving characters or tokens behind in the input stream using \char_generate:nn
. Some \afterassignment
trickery allows to not keep track of catcode 1/2 characters. One still needs to keep track of the number of parameters.
Cache the results for each macro!
In pdfTeX, \showthe\ignorespaces
will show 0 with no error. In TeX it will cause an error then show 0.
Test behaviour in various engines and make unravel do the same.
Right now, \unravel{\tex_input:D {.tex}}
fails in all engines nowadays because unravel mistakenly searches for the file {.tex}
. In fact all engines seem to search for a general text before falling back to the old syntax. Needs to be tested with \openin
, \openout
too.
e-TeX's \if
-related integer parameters (\currentiflevel
, \currentifbranch
and \currentiftype
) are all zero inside a conditional in\unravel
:
\RequirePackage{unravel}
\unravel{\ifx!!\showthe\currentiflevel\fi}
\stop
If the argument to \unravel
is just a valid \number
expression an error is thrown:
\documentclass{article}
\usepackage{unravel}
\begin{document}
\unravel{\number`a}
\end{document}
This throws:
Runaway argument?
\__unravel_print_outcome: \__unravel_final_test: \__unravel_exit_point: \ETC.
! File ended while scanning use of \__unravel_exit_error:w.
<inserted text>
\par
Hi, I accidentally noticed that an unusual catcode for &
at loading time
\documentclass{article}
\catcode`& 12
\usepackage{unravel}
\catcode`& 4
\begin{document}
\unravel{\romannumeral-`0 1}
\end{document}
compromised the functioning of the package. I hesitate raising this at an issue as I suspect it is an implicit assumption in LaTeX2e
that packages are supposedly loaded under a standard catcode regime (I tried with a few other characters, but finally settled on the &
as the culprit in my initial, a bit convoluted, situation).
Best,
Jean-François
Most error messages given by unravel
lack information. Add more. In particular, the-last-unravel-finished-badly
occurs too often and should have more explanations.
Add \@@_print_action:
somewhere in the code implementing \ignorespaces
, as otherwise the user cannot see what is going on.
\unravel { \ignorespaces \ignorespaces \ignorespaces }
stops immediately.
Glue signs are not treated properly
\unravel{\parskip=-\parskip\showthe\parskip}
eventually shows > 0.0pt plus 1.0pt.
instead of > 0.0pt plus -1.0pt
. This is because the sign only ends up applying to the first part of the skip, but not to the plus or minus parts.
This does not affect the outcome of an \edef
, just what is shown in the terminal. For instance, the first two steps of:
\RequirePackage{unravel}
\unravel{\edef\x#1{\def\noexpand\test\detokenize{hi}{}}\show\x}
\stop
are:
[===== Step 1 =====] \detokenize = \detokenize
|| \edef \x {\def \test
|| \detokenize
|> {hi}{}}\show \x
[===== Step 2 =====] \detokenize {hi}
|| \edef \x {\def \test \detokenize {hi}
|> {}}\show \x
whereas the second step should be:
[===== Step 2 =====] \detokenize {hi}
|| \edef \x {\def \test hi
|> {}}\show \x
I traced the issue back to line 7381 of unravel.dtx
, \@@_prev_input:V \l_@@_head_tl
, where \l_@@_head_tl
contains \detokenize {hi}
. To print correctly, the contents of \l_@@_head_tl
should be expanded to result in the correct hi
. I changed the code in my version of unravel.sty
and it seems to be working...
Hopefully there will be a point where unravel
detects all TeX errors.
Even before that, it would be useful to have the option to stop at the first error detected by unravel
. That probably is not too hard: change all \msg_error
to include code that sets \g_@@_nonstop_int
to the right value.
Since April 2018, LaTeX2e has used \lastnamedcs
in \@ifundefined
for LuaTeX. See commit latex3/latex2e@82b49f5. Since \@ifundefined
is used by many command-defining commands, the fact that \lastnamedcs
is not implemented might bring inconvenience to LuaTeX + unravel
users.
Currently I seldom come to the situation that I must run LuaTeX with unravel
, but not sure if this holds for other unravel
users.
There seems to be an error regarding tokens following a dimension assignment:
\makeatletter
\newdimen\ifdimen@gobbledimen
\long\def\ifdimen@test\ifdimen@false#1#2{#1}
\def\ifdimen@false{\z@\ifdimen@false\@firstofone}
\protected\long\def\ifdimen#1%
{%
\afterassignment\ifdimen@test
\ifdimen@gobbledimen #1 \ifdimen@false
}
\makeatother
\ifdimen{1}{true}{false}
\ifdimen{1pt}{true}{false}
\unravel{\ifdimen{1}{true}{false}}
\unravel{\ifdimen{1pt}{true}{false}}
This definition will work outside of \unravel
but inside \unravel
the space after #1
will not be gobbled if #1
is a valid dimension and therefore \ifdimen@test
will throw an error as it doesn't match its definition.
On the other hand
\makeatletter
\newdimen\ifdimen@gobbledimen
\long\def\ifdimen@test\ifdimen@false#1#2{#1}
\def\ifdimen@false{\z@\ifdimen@false\@firstofone}
\protected\long\def\ifdimen#1%
{%
\afterassignment\ifdimen@test
\ifdimen@gobbledimen #1\ifdimen@false
}
\makeatother
\ifdimen{1}{true}{false}
\ifdimen{1pt}{true}{false}
\unravel{\ifdimen{1}{true}{false}}
\unravel{\ifdimen{1pt}{true}{false}}
will throw an error outside of \ifdimen
if #1
is a valid dimension as \ifdimen@false
will be expanded, but work inside of \unravel
When unravel-ing \footnote
, the \insert
used inside \@footnotetext
raises
! Undefined control sequence.
\__unravel_cmd_37: ...vel_begin_insert_or_adjust:
l.6 content\unravel{\footnote{abc}}
Currently \insert
is not marked as "not implemented", hence \__unravel_begin_insert_or_adjust:
is expected as implemented.
Example:
% unravel-footnote.tex
\documentclass{article}
\usepackage{unravel}
\begin{document}
content\unravel{\footnote{abc}}
\end{document}
Run it with pdflatex unravel-footnote
, then input u\@footnotetext
followed by three "Enter"s.
Expanding an expandable primitive unknown to unravel
, such as \directlua
in LuaTeX, incorrectly puts it into the output (not even into the current prev_input) rather than for instance producing an undefined control sequence error or similar. Example:
\RequirePackage{unravel}
\unravel{\edef\foo{\directlua{}}}
When a macro delimited by \fi
is used in a conditional, \unravel
seems to partially lose track of \if
...\fi
nesting and throws an error at the end:
\RequirePackage{unravel}
\def\aux\fi{}
\unravel{\ifx!!\aux\fi}
\stop
But the code execution seems to be carried out correctly.
Terminal output:
======== Welcome to the unravel package ========
"<|" denotes the output to TeX's stomach.
"||" denotes tokens waiting to be used.
"|>" denotes tokens that we will act on.
Press <enter> to continue; 'h' <enter> for help.
||
|> \ifx !!\aux \fi
[===== Step 1 =====] \ifx = \ifx
|| \ifx
|> !!\aux \fi
[===== Step 2 =====] Compare: \ifx !!=true
||
|> \aux \fi
[===== Step 3 =====] \aux = macro:\fi ->
||
|>
[===== End =====]
! Package unravel Error: Internal error: 'the-last-unravel-finished-badly'.
(unravel) Please report.
Type <return> to continue.
...
l.5 \unravel{\ifx!!\aux\fi}
?
\tl_if_in:nnTF
defines an auxiliary and this is clobbered by unravel
's own use of some tl functions.
\RequirePackage{unravel}
\ExplSyntaxOn
\unravel{\tl_if_in:nnTF { abc } { a } { } { } }
breaks after Step 13.
\RequirePackage{unravel}
\unravel{\showthe\font\relax}
should show \nullfont
, but breaks with the error missing-font-id
.
On my terminal, running
pdftex -8bit '\message{normal\pdfunescapehex{1B5B}1;9;34mFANCY\pdfunescapehex{1B5B}mnormal}'
Gives me "normalFANCYnormal" with "FANCY" written in bold blue font and crossed through. It would sometimes be very useful to have colors distinguishing category codes of tokens, or underlining different macro parameters, etc.
The various prompt_input_clist
variables should be sequences instead. Otherwise,
\RequirePackage{unravel}
\ExplSyntaxOn
\unravel[prompt-input=u\q_nil]{\c_space_tl\boom\q_nil}
(for instance) does not continue unravelling until \q_nil
. Basically, \q_nil
messes up clist internals. This specific case would be fixed by fixing latex3/latex3#593 but unravel
needs to work also for private quarks, so using a sequence is better.
Found by P.O. at https://tex.stackexchange.com/a/496786/2707
There are many situations where it would be a life saver to rewind steps. Typically, I use \unravel
to find what caused a TeX error. It would be nice to let unravel run a few steps at a time, then to stop once I see the error, and rewind a couple of steps to determine what when wrong.
It seems impossible to undo global assignments. But this is not needed! Assignments do not really have to be performed. The values of macros and other parameters, must be saved, but they are only ever used by unravel
, which could be built to look for saved values rather than current values.
The following must be saved. Save input/prev/output stacks every few steps (repeatedly discard every other one once old, like one would do for backups). Save previous values for all assignments. Save the "outcome" of every step.
Some structural changes are needed, so don't expect this issue to be closed any time soon.
That should be a one-line fix, since \pdfstrcmp
is already implemented.
Implicit character tokens should not be allowed in a \csname...\endcsname
construction. But unravel
accepts the following:
\unravel{\let\*=+\csname\*\endcsname}
instead of breaking with a "Missing \endcsname
" error.
It would be really nice if one was able to specify another filename in which unravel
then writes its logs. This would keep the log itself small (and manageable by TeXStudio, etc.). Furthermore this would simplify the automatic processing of the logs as one didn't have to worry about other log messages.
If the \unless
primitive is used with \ifcsname
a low level Missing \endcsname
is thrown in \unravel
. Consider the following MWE:
\documentclass[]{article}
\usepackage{unravel}
\begin{document}
\unravel
{%
\unless\ifcsname section\endcsname
not
\fi
defined
}
\end{document}
The bug will be triggered for both defined and undefined macros being tested.
LuaTeX has "new" ways of accessing Lua, through expandable luacalls. This is for instance used in \file_size:n
. Currently breaks in unravel.
Example
\documentclass{article}
\usepackage{unravel}
\begin{document}
\unravel{\unless\iftrue F\else T\fi}
\end{document}
||
|> \unless \iftrue F\else T\fi
[===== Step 1 =====] \unless = \unless
|| \reverse_if:N \iftrue
|> F\else T\fi
[===== Step 2 =====] \reverse_if:N \iftrue =false => skip to \else
||
|> T\fi
Version
Start from the list of primiives in l3names
. Go through it and write tests for all of them.
At present,
\unravel{\expandafter?}
causes an internal error because it tries to fetch a token beyond the last one in \unravel
. There are probably some other similar cases.
When I use u\foo
to skip some steps, unravel
skips steps until \foo
is in the front of the input stream and then performs one more step. An example interactive session (the last keyboard input was hitting Enter after typing u\new@command
):
> pdflatex
This is pdfTeX, Version 3.14159265-2.6-1.40.20 (MiKTeX 2.9.7050 64-bit)
**\documentclass{article}\usepackage{unravel}\unravel{\newcommand\foo{asdf}}
entering extended mode
LaTeX2e <2018-12-01>
("C:\Program Files\MiKTeX 2.9\tex/latex/base\article.cls"
Document Class: article 2018/09/03 v1.4i Standard LaTeX document class
("C:\Program Files\MiKTeX 2.9\tex/latex/base\size10.clo"))
("C:\Program Files\MiKTeX 2.9\tex/latex/unravel\unravel.sty"
("C:\Program Files\MiKTeX 2.9\tex/latex/l3kernel\expl3.sty"
("C:\Program Files\MiKTeX 2.9\tex/latex/l3kernel\expl3-code.tex")
("C:\Program Files\MiKTeX 2.9\tex/latex/l3kernel\l3pdfmode.def"))
("C:\Program Files\MiKTeX 2.9\tex/latex/l3packages/xparse\xparse.sty")
("C:\Program Files\MiKTeX 2.9\tex/generic/gtl\gtl.sty"))
======== Welcome to the unravel package ========
"<|" denotes the output to TeX's stomach.
"||" denotes tokens waiting to be used.
"|>" denotes tokens that we will act on.
Press <enter> to continue; 'h' <enter> for help.
||
|> \newcommand \foo {asdf}
u\new@command
[===== Step 1 =====] \newcommand = macro:->\@star@or@long \new@command
[===== Step 2 =====] \@star@or@long = macro:#1->\@ifstar {\let \l@ng...
[===== Step 3 =====] \@ifstar = macro:#1->\@ifnextchar *{\@firstoftw...
[===== Step 4 =====] \@ifnextchar = \long macro:#1#2#3->\let \reserv...
[===== Step 5 =====] \let \reserved@d
[===== Step 6 =====] Set \reserved@d=the character *
[===== Step 7 =====] \def \reserved@a {\@firstoftwo {\let \l@ngrel@x...
[===== Step 8 =====] Set \reserved@a=macro:->\@firstoftwo {\let \l@n...
[===== Step 9 =====] \def \reserved@b {\let \l@ngrel@x \long \new@co...
[===== Step 10 =====] Set \reserved@b=macro:->\let \l@ngrel@x \long \...
[===== Step 11 =====] \futurelet \@let@token
[===== Step 12 =====] Set \@let@token=undefined
[===== Step 13 =====] \@ifnch = macro:->\ifx \@let@token \@sptoken \l...
[===== Step 14 =====] \ifx = \ifx
[===== Step 15 =====] Compare: \ifx \@let@token \@sptoken =false => s...
[===== Step 16 =====] \ifx = \ifx
[===== Step 17 =====] Compare: \ifx \@let@token \reserved@d =false =>...
[===== Step 18 =====] \let \reserved@c
[===== Step 19 =====] Set \reserved@c=macro:->\let \l@ngrel@x \long \...
[===== Step 20 =====] \fi = \fi
[===== Step 21 =====] \fi = \fi
[===== Step 22 =====] \reserved@c = macro:->\let \l@ngrel@x \long \ne...
[===== Step 23 =====] \let \l@ngrel@x
[===== Step 24 =====] Set \l@ngrel@x=\long
||
|> \new@command \foo {asdf}
[===== Step 25 =====] \new@command = macro:#1->\@testopt {\@newcomman...
||
|> \@testopt {\@newcommand \foo }0{asdf}
(I am using Windows 10's PowerShell with MiKTeX's pdflatex
.)
I'm not sure whether this is possible but if it was possible to specify a maximal expansion level one could get output that is more or less only about the relevant stages of the expansion instead of all sub-expansions going on inside.
Example:
\def\test{\pgfkeys{/a/b/.store in = \bla} bla}
\def\otherTest{\test}
\def\lastTest{\otherTest}
\unravel[max-expansion=2]{\lastTest}
Above example would then not expand \pgfkeys
which would end in thousands of expansion steps when maybe one is only interested in how \lastTest
expands to the level of \test
.
When I try to do
\documentclass{article}
\usepackage{unravel}
\begin{document}
\unravel{\if\relax\detokenize{}\relax\fi}
\end{document}
unravel inserts \exp_not:N
in the list of tokens waiting to be used:
[===== Step 5 =====] \exp_not:N \relax
|| \if \exp_not:N \relax \exp_not:N \relax
|> \fi
Right now, unravel
is interactive in \errorstopmode
and otherwise gives no prompt. This may be the right thing to do, but I am not yet sure.
Sorry for bad vocabulary (not time to check e.g. TeX by Topic for exact one).
This fails with current master at 9461aa1
\documentclass{article}
\usepackage{unravel}
\begin{document}
% raises error
\unravel{\dimen255=3\catcode`\p\relax}
% this is ok
\dimen255=3\catcode`\p\relax
\number\dimen255 % 33 = 3 times 11
\end{document}
I have inserted the \relax
only for extra safety.
It would be nice to be able to type until \somecs
and have unravel
do all the steps until the first token of the token list is \somecs
. Even better if more than one token can be specified in this way. For instance, one could respond until \begin{document}
after calling \unravel{\input{main.tex}}
.
One would want
\unravel{\scantokens{\catcode`X=12 \showX}}
to show the character X
instead of producing an error "\showX
not defined". A similar comment applies to \input
instead of \scantokens
.
A false \if
-test will skip to \fi
if there is no \else
before \fi
, and to \else
if there is such \else
. But currently the action part shows skipped to \fi
in both occasions.
An example:
\documentclass{article}
\usepackage{unravel}
\begin{document}
\leavevmode
\unravel{%
\ifx\relax\relax T\else F\fi
\ifx\abc\relax T\else F\fi
}
\end{document}
Terminal output
||
|> \ifx \relax \relax T\else F\fi \ifx \abc \relax T\else F\fi
[===== Step 1 =====] \ifx = \ifx
|| \ifx
|> \relax \relax T\else F\fi \ifx \abc \relax T\else F\fi
[===== Step 2 =====] Compare: \ifx \relax \relax =true
||
|> T\else F\fi \ifx \abc \relax T\else F\fi
[===== Step 3 =====] T
<| T
||
|> \else F\fi \ifx \abc \relax T\else F\fi
[===== Step 4 =====] \else = \else => skipped to \fi
<| T
||
|> \ifx \abc \relax T\else F\fi
[===== Step 5 =====] \ifx = \ifx
<| T
|| \ifx
|> \abc \relax T\else F\fi
[===== Step 6 =====] Compare: \ifx \abc \relax =false => skipped to \fi
<| T
||
|> F\fi
[===== Step 7 =====] F
<| TF
||
|> \fi
[===== Step 8 =====] \fi = \fi
<| TF
||
|>
[===== End =====]
In step 6, the action part says
[===== Step 6 =====] Compare: \ifx \abc \relax =false => skipped to \fi
It's better to say skipped to \else
rather than \fi
.
If you do \meaning<explicit begin/end-group token>
, unravel
will show
an internal (implicit) token. The example:
\RequirePackage{unravel}\everypar{}
\unravel{\meaning{\iffalse}\fi}
\csname @@end\endcsname
shows as:
[===== Step 1 =====] \meaning = \meaning
|| \meaning
|> {\iffalse }\fi
[===== Step 2 =====] \l__unravel_head_token
|| \meaning \l__unravel_head_token
|> \iffalse }\fi
whereas the second step should (I think) read:
[===== Step 2 =====] {
|| \meaning {
|> \iffalse }\fi
\RequirePackage{unravel}
\ExplSyntaxOn
\unravel{\string{}}
gives a low-level runaway argument error (of an unravel macro). This issue came up in \tl_if_head_is_group:nTF {{,}.}
Currently, when reading \escapechar=-1
, unravel shows \escapechar=92
instead of -1
, but does the right thing. Namely,
\unravel{\escapechar=-1\message{\the\escapechar}}
gives
|> \escapechar =-1\message {\the \escapechar }
[===== Step 1 =====] \escapechar
|| \escapechar
|> =-1\message {\the \escapechar }
[===== Step 2 =====] =
|| \escapechar =
|> -1\message {\the \escapechar }
[===== Step 3 =====] -
|| \escapechar =-
|> 1\message {\the \escapechar }
[===== Step 4 =====] 1
|| \escapechar =-1
|> \message {\the \escapechar }
[===== Step 5 =====] Set \escapechar(\escapechar)=92
||
|> \message {\the \escapechar }
[===== Step 6 =====] \message = \message
|| \message
|> {\the \escapechar }
[===== Step 7 =====] \message = \message
|| \message
|| {
|| \the
|> \escapechar }
[===== Step 8 =====] \the =>-1
|| \message
|| {-1
|> }
-1
[===== Step 9 =====] \message {-1}
||
|>
[===== The end! =====]
The following code:
\documentclass{article}
\usepackage{unravel}
\ExplSyntaxOn
\prg_new_conditional:Npnn \pho_if_minus:n #1 { TF }
{
\reverse_if:N \if_charcode:w #1 - \exp_not:N \ERROR
\prg_return_false:
\else:
\prg_return_true:
\fi:
}
\cs_new:Npn \test #1 { #1|-> \pho_if_minus:nTF {#1} { T } { F } \par }
\ExplSyntaxOff
\begin{document}
\ttfamily
\test{+}
\test{-}
\unravel{\test{+}}
\unravel{\test{-}}
\end{document}
Produces different output for \test{-}
and \test{+}
if they were used inside \unravel
:
+|->F
-|->T
+|->T
-|->F
With TeXLive 2018 the output is the same:
+|->F
-|->T
+|->F
-|->T
\RequirePackage{unravel}
\ExplSyntaxOn
\unravel{\char_generate:nn{65}{11}}
This stops after 99 steps, despite being in the middle of many expansions.
Currently the notion of "step" in unravel
is a bit haphazard. It would be good to clarify what a step can be. This would probably force the code to be simplified.
Admittedly, this issue is presently very vague.
\RequirePackage{unravel}
\unravel{\iffalse{\fi}}
will issue the TeX error "Too many }'s" as expected, but will do so repeatedly instead of just once.
The unravel code has \@@_prepare_mag:
in every place that original TeX has it. But pdfTeX (at least) adds several more places. Most of them are ultimately only called within \shipout
, and the only other one is \immediate\pdfxform
.
You have \expanded
support in luatex but it's now in pdftex etc as well
! Package unravel Error: Internal error: the primitive 'expanded' is not
(unravel) known.
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.