jovanbulck / jsh Goto Github PK
View Code? Open in Web Editor NEWA basic UNIX shell implementation in C
License: GNU General Public License v3.0
A basic UNIX shell implementation in C
License: GNU General Public License v3.0
todo --> change this everywhere in the (old) code.
Note the stdbool
header is already included in jsh-common.h
Work in progress -> see jobs-on-background branch
todo list:
cmd
(the whole pipeline!) is the unit of suspension: ^Z will be interpreted as EXIT_FAILURE&
sign --> input
is the unit of explicit backgrounding ?? What todo with thins like sleep 2 && echo done &
??bg
fg
jobs
built-ins that manipulate the background_processes list and send a SIGCONT signal to the child processesCurrent situation:
$ ls
Downloads/
Desktop/
$ cd do ## Press [Tab]: nothing happens
$ cd Do ## Press [Tab]: code completion to cd Downloads/
$ cd Downloads/
Request: complete code disregarding case. For instance:
$ ls
Downloads/
Desktop/
$ cd do ## Press [Tab]: code completion to cd Downloads/:
$ cd Downloads/
We should create a --fun-mode
, for experimenting with cool stuff. For example:
sl
with jo-shell
on it in two goods wagons.IDEA: push the cwd on a stack on each call to cd and write a simple built_in to e.g. pop the top cwd and cd into it; have a user_defined number of directories to remember (eg via an environment variable?)
--> would be really usefull and probably also easy to implement...
(I think something familiar is done in bash and zsh.)
list search show install remove edit-sources update upgrade full-upgrade
update upgrade install remove autoremove purge source build-dep dist-upgrade dselect-upgrade clean autoclean check changelog download
gencaches showpkg showsrc stats dump dumpavail unmet search show depends rdepends pkgnames dotty xvcg policy
eth0 lo wlan0
--help-all
--calendar
--entry
--error
--info
--file-selection
--list
--notification
--progress
--question
--warning
--scale
--text-info
--color-selection
--password
--forms
start
stop
restart
reload
status
is-enabled
enable
disable
help
daemon-reload
--all
--kernel-name
--nodename
--kernel-release
--kernel-version
--machine
--processor
--hardware-platform
Normally, cd -
gets you in the previous directory.
Expected behaviour:
$ pwd
/etc/apt
$ cd /mnt/Data
$ pwd
/mnt/Data
$ cd -
$ pwd
/etc/apt
Actual behaviour:
$ pwd
/etc/apt
$ cd /mnt/Data
$ pwd
/mnt/Data
$ cd -
[DEBUG: You entered: 'cd -']
[DEBUG: readcmd: cmd 'cd -' expanded to 'cd -']
[DEBUG: alias: input resolved to: 'cd -']
jsh: cd: No such file or directory
[DEBUG: built-in: executed 'cd']
[DEBUG: freeing comd struct for 'cd']
[DEBUG: parseexpr: expr evaluated with return value 1]
[DEBUG: readcmd: freeing memory for: 'cd']
$ pwd
/mnt/Data
minimal reproduction:
$ alias key val
$ unalias key
$ alias key anotherval # exits successfully
$ alias # BUG: key is not in the alias table?
We should also include a 32 bit (Linux) build in the release. To do so, build a release-version on a 32 bit system with sudo make install
and upload /usr/local/bin/jsh to the release page
There may be a possibility we can get the shell working on android too :).
TODO:
has something to do with the "F", "T" uppercase elements in the beginning. I"ll look into it
malloc(arg) macro to auto check the return value of malloc calls
see also https://www.gnu.org/software/gnulib/manual/html_node/Safe-Allocation-Macros.html
Maybe write a wrapper macro for printdebug
statements so that the pre-compiler only includes the statements when DEBUG=1
See https://en.wikipedia.org/wiki/Variadic_macro and http://stackoverflow.com/questions/679979/how-to-make-a-variadic-macro-variable-number-of-arguments
sed
mac versiongmake
instead of makeThis is a nasty bug that took me some time ;-)
The problem is the OS limits the size of a pipe buffer and jsh
doesn't start a built_in-producer in parallel with its consumer-follower in the pipeline (since jsh
is mono-threaded).
To clarify: let's take an easy non-built_in example cat some_file | grep some_string
. This is more or less what happens:
jsh
parses the string and construct the pipeline of comd
's in its data structuresjsh
then opens the necessary pipe buffers using libc
functions (OS system calls)jsh
then starts a loop where it forks all the commands in the pipeline on after the other, redirecting stdin and stdout to the correct pipe file descriptors just before calling execv
to replace the forked jsh
child with the correct UNIX command (e.g. cat
or grep
)jsh
waits for the completion of all childrenThe point is jsh
doesn't block after one process in the pipeline is started (forked). Instead it directly creates the next one. This implies the consumer process (eg grep) can start consuming data from the pipe filled by the producer (eg cat). The OS limits the size of a pipe buffer, refusing any more data when the pipe buffer is full. The rationale here is that the consumer should consume some data, freeing up space, before the producer can continue producing.
Now the problem: jsh
deals with built_ins in a pipeline different then with normal "forkable" commands. For example consider history | grep some_string
jsh
starts the actual pipe processes in the fork loop above; when it detects one of the processes is a built_in, it first redirect stdin and stdout to the pipes and then calls the parse_built_in()
function, blocking the loop till completion...Of course this is the problem: a built_in will write all of its data to the pipe before the consumer process is started (since jsh
executes in a single thread). When the history file is very large, the pipe buffer fills up... (e.g. + 60.000 bytes of history; +5000 lines)
Some solution sketches:
~/.jsh_history
e.g. simple cat
--> this fixes the problem, by hacking around it; no real general solutionComments? Feedback? Ideas?
If anyone feels like it, claim! This is a nice bugfix for getting to know the jhs
internals :-)
We should have a bitcoin address, to fund continued development of jsh
.
Request: implement .po translation files
Current behaviour:
Suppose the following alias is defined: ll='ls -la'.
Suppose ~/.jshrc contains the instruction: alias ll "ls -l"
$ alias
alias ll="ls -la"
$ source ~/.jshrc
$ alias
alias ll="ls -la"
alias ll="ls-l"
According to POSIX, in the case of a double aliasdefinition, the older alias should be overwritten with the newer one.
Expected behaviour:
$ alias
alias ll="ls -la"
$ source ~/.jshrc
$ alias
alias ll="ls -l"
just a test -- ignore
todo
--> push to master
For elegance and efficiency, we should probably change the datastructure for aliases from a linked list of structs to a hashmap<char *key, char *value>
As far as I know, there's no native support in libc
for hashmaps. We should probably look to an optimized GPL licensed hashmap implementation and include it in the project...
Advanced users know how to use a Makefile, rookies don't. We should create an executable that installs jsh
. The executable should use dialog
for ease of use. You can find some images of what's possible with dialog right here.
Our installer should do the following:
/usr/bin
jsh
:
apt-get
, pacman
, tce-load
)jsh
: ask the user to search for the needed libraries himself before continuing installation.checklist
modulejsh
config files in $HOME
; if they are not there, ask the user if he wants the installer to create default jsh
config files. The user should be able to edit the config files via the editbox
module.make
output with the progressbox
module, or show the installation progress via the gauge
or mixedgauge
modulejsh
as the default shell (with the chsh
command)chmod
ing it and copy to /usr/bin/
if wantedmake
sh
script as much portable as possibleAlternative: we can also use zenity
. Not my weapon of choice, but we should consider it.
Currently, jsh is not on AUR!
Current behaviour
$ yaourt -Ss jsh
community/jshon 20131105-1
A json parser for the shell.
aur/heirloom-sh-cvs 2011.06.22-1 (5)
Traditional sh [jsh(1)], derived from OpenSolaris code. CVS repository
aur/heirloom-sh-musl-cvs 20120609-1 (1)
sh [jsh(1)], derived OpenSolaris code, statically linked to musl libc
aur/nodejs-jshint 2.5.6-1 (33)
Static analysis tool for JavaScript
aur/vim-lint-git 20130427-1 (1)
Vim + JSHint + CSSLint + V8
Expected behaviour
$ yaourt -Ss jsh
community/jshon 20131105-1
A json parser for the shell.
aur/jsh 1.1.0 [installed]
A basic UNIX shell implementation in C
aur/heirloom-sh-cvs 2011.06.22-1 (5)
Traditional sh [jsh(1)], derived from OpenSolaris code. CVS repository
aur/heirloom-sh-musl-cvs 20120609-1 (1)
sh [jsh(1)], derived OpenSolaris code, statically linked to musl libc
aur/nodejs-jshint 2.5.6-1 (33)
Static analysis tool for JavaScript
aur/vim-lint-git 20130427-1 (1)
Vim + JSHint + CSSLint + V8
e.g. !!
will be expanded to the previous entered command
use the GNU history library?
--> see http://tiswww.case.edu/php/chet/readline/history.html#SEC3
installer.sh
should be executable from the get-go. Current situation:
[gijs@therion /tmp]$ git clone https://github.com/jovanbulck/jo-shell.git
Cloning into 'jo-shell'...
remote: Counting objects: 762, done.
remote: Compressing objects: 100% (57/57), done.
remote: Total 762 (delta 26), reused 0 (delta 0)
Receiving objects: 100% (762/762), 456.96 KiB | 357.00 KiB/s, done.
Resolving deltas: 100% (456/456), done.
Checking connectivity... done.
[gijs@therion /tmp]$ cd jo-shell
[gijs@therion jo-shell]$ ls -hl
totaal 180K
-rw-rw-r-- 1 gijs gijs 8,0K dec 6 11:36 alias.c
-rw-rw-r-- 1 gijs gijs 1,1K dec 6 11:36 alias.h
-rw-rw-r-- 1 gijs gijs 14K dec 6 11:36 installer.sh
-rw-rw-r-- 1 gijs gijs 390 dec 6 11:36 jo-shell.txt
-rw-rw-r-- 1 gijs gijs 26K dec 6 11:36 jsh.c
-rw-rw-r-- 1 gijs gijs 2,4K dec 6 11:36 jsh-colors.h
-rw-rw-r-- 1 gijs gijs 7,1K dec 6 11:36 jsh-common.c
-rw-rw-r-- 1 gijs gijs 3,6K dec 6 11:36 jsh-common.h
-rw-rw-r-- 1 gijs gijs 9,3K dec 6 11:36 jsh-completion.c
-rw-rw-r-- 1 gijs gijs 1,7K dec 6 11:36 jsh-completion.h
-rw-rw-r-- 1 gijs gijs 3,5K dec 6 11:36 jsh-man.1
-rw-rw-r-- 1 gijs gijs 21K dec 6 11:36 jsh-parse.c
-rw-rw-r-- 1 gijs gijs 2,2K dec 6 11:36 jsh-parse.h
-rw-rw-r-- 1 gijs gijs 35K dec 6 11:36 LICENSE
-rw-rw-r-- 1 gijs gijs 6,8K dec 6 11:36 Makefile
-rw-rw-r-- 1 gijs gijs 4,3K dec 6 11:36 mini-grep.c
-rw-rw-r-- 1 gijs gijs 3,4K dec 6 11:36 README.md
Desired situation:
[gijs@therion /tmp]$ git clone https://github.com/jovanbulck/jo-shell.git
Cloning into 'jo-shell'...
remote: Counting objects: 762, done.
remote: Compressing objects: 100% (57/57), done.
remote: Total 762 (delta 26), reused 0 (delta 0)
Receiving objects: 100% (762/762), 456.96 KiB | 357.00 KiB/s, done.
Resolving deltas: 100% (456/456), done.
Checking connectivity... done.
[gijs@therion /tmp]$ cd jo-shell
[gijs@therion jo-shell]$ ls -hl
totaal 180K
-rw-rw-r-- 1 gijs gijs 8,0K dec 6 11:36 alias.c
-rw-rw-r-- 1 gijs gijs 1,1K dec 6 11:36 alias.h
-rwxrwxr-x 1 gijs gijs 14K dec 6 11:36 installer.sh
-rw-rw-r-- 1 gijs gijs 390 dec 6 11:36 jo-shell.txt
-rw-rw-r-- 1 gijs gijs 26K dec 6 11:36 jsh.c
-rw-rw-r-- 1 gijs gijs 2,4K dec 6 11:36 jsh-colors.h
-rw-rw-r-- 1 gijs gijs 7,1K dec 6 11:36 jsh-common.c
-rw-rw-r-- 1 gijs gijs 3,6K dec 6 11:36 jsh-common.h
-rw-rw-r-- 1 gijs gijs 9,3K dec 6 11:36 jsh-completion.c
-rw-rw-r-- 1 gijs gijs 1,7K dec 6 11:36 jsh-completion.h
-rw-rw-r-- 1 gijs gijs 3,5K dec 6 11:36 jsh-man.1
-rw-rw-r-- 1 gijs gijs 21K dec 6 11:36 jsh-parse.c
-rw-rw-r-- 1 gijs gijs 2,2K dec 6 11:36 jsh-parse.h
-rw-rw-r-- 1 gijs gijs 35K dec 6 11:36 LICENSE
-rw-rw-r-- 1 gijs gijs 6,8K dec 6 11:36 Makefile
-rw-rw-r-- 1 gijs gijs 4,3K dec 6 11:36 mini-grep.c
-rw-rw-r-- 1 gijs gijs 3,4K dec 6 11:36 README.md
When you click the button, you should be referred to log.txt
, which contains:
uname -a
Future: set up a build farm with a couple of VirtualBox appliances. Make the farm compile for each target, return binaries and the build logs, and upload them to github in a clean fashion. For example:
[gijs@ubuntu test]$ tree
.
├── lin
│ ├── build
│ │ ├── arch
│ │ │ ├── x86
│ │ │ │ └── jsh-1.2.0
│ │ │ └── x86_64
│ │ │ └── jsh-1.2.0
│ │ ├── debian
│ │ │ ├── x86
│ │ │ │ └── jsh-1.2.0
│ │ │ └── x86_64
│ │ │ └── jsh-1.2.0
│ │ ├── fedora
│ │ │ ├── x86
│ │ │ │ └── jsh-1.2.0
│ │ │ └── x86_64
│ │ │ └── jsh-1.2.0
│ │ ├── redhat
│ │ │ ├── x86
│ │ │ │ └── jsh-1.2.0
│ │ │ └── x86_64
│ │ │ └── jsh-1.2.0
│ │ └── ubuntu
│ │ ├── x86
│ │ │ └── jsh-1.2.0
│ │ └── x86_64
│ │ └── jsh-1.2.0
│ └── source
│ └── jsh-1.2.0.tar.gz
└── mac
├── build
│ └── jsh-1.2.0.tar.gz
└── source
└── jsh-1.2.0.tar.gz
21 directories, 13 files
Or: use the OpenSuse Build Service
Joclock should be a builtin feature of jsh. Posting the command required to fire up joclock here for future reference.
xclock -norender -hd green -hl green -bg black -fg white -update 1 &
things todo:
getprompt
:
gethostname(hostname, HOST_NAME_MAX);
results in make error "‘HOST_NAME_MAX’ undeclared". The POSIX specification doesn't seem to be very clear here. Changing to "_POSIX_HOST_NAME_MAX" compiles on Mac.homebrew
(http://brew.sh/): `brew install readline --> hisotry not workingif this feature is stable we release jsh 1.1.0
Since we're currently drowning in cd (autocompletion) feature requests, I think it's probably best to group them together here. See also issues #16 and #35 and #50 Moreover we should sketch an approach to handle them here
A (non-exhaustive) list of cd
autocompletion work, partially ordered by importance. I also added an indicator of task-difficulty-estimation:
easy: As I sketched out in issue #16 , we should change some of readline defaults and allow a user to override them in ~/.inputrc
challenging: autocomplete for cd
should only complete directory names, no file names. This can be tricky , since readline API sucks here, I think. This feature is probably the most useful cd
enhancement however. e.g.
$ ls directory
a_filename a_directoryname
$ cd a<TAB>
$ cd a_directoryname/ # detects a_filename isn't an appropriate completion
easy: not really autocompletion, rather a bug, see issue #22
moderate: a feature request to support "cd -
" and maybe some more "cd history" You're free to invent some usefull syntax here, but maybe look at zsh
syntax as a starting point. See issue #33
challenging: cd
autocompletion should escape spaces in directory names, see issue #35 I started on this, but readline API is very confusing here. If someone wants to look at it --> go ahead. I think we'll need some Stackoverflow help here. Probably not very difficult once API is clear. Don't hesitate to claim this one, if you feel like it ;-)
challenging: program name autocompletion now is only a hack, using a predefined array of program names. This array of program names should be constructed dynamically, when booting the shell, by scanning the $PATH
variable.
challenging: @GijsTimmers ' ideas for smart autocompletion: correct wrong directory names, autocomplete at deeper levels, etc. To start on this one, we should have fixed the "only completing of directories" above
I think it's probably best to implement the things above and put a hold on more cd
feauture requests for the moment. If you want, you can group all "future cd work" in a (single) separate issue, but probably best not in this issue. I'll also lock the other cd
issues, so all discussion happens in this central issue.
Then, finally, we need developers here! The tasks above vary in difficulty, so feel free to claim one of them and open a pull request. Comment below to "claim" an item and discuss various difficulties on implementing...
cd
also updates the PWD env var, but the supplied dir can also be relative (. or ..) and should then be resolved in the PWD var. Here's the code:
case CD: ; // (hackhackhack to allow declarions inside a switch)
char *dir;
if (comd->length == 1)
dir = getenv("HOME");
else {
CHK_ARGC("cd",1);
dir = comd->cmd[1];
}
CHK_ERR(chdir(dir), "cd");
setenv("PWD", dir, 1); // BUG: dir can be relative and should then be resolved
return EXIT_SUCCESS;
break;
things todo:
setenv <name> <value>
built_in that calls setenv(3)
extern
keywordenv_var="value"
instead of env env_var "value"
?Who is kevinsawicki? checkout my branch. github is using my commits with other names
when executing make install a man
page should be generated
when using the shell, it is not possible to update the shell to a newer version because of next error:
"cp: cannot create regular file ‘/opt/jsh’: Text file busy"
Probably trivial using the parsefile(2)
function in jsh-common
after the update about -lncurses, my system (ubuntu 14.04) is unable to compile the code:
/usr/bin/ld: cannot find -lncurses
How can I solve this?
solution and install libreadline6
and libreadline6-dev
all: jsh-common alias jsh link
@echo "<<<< All done >>>>"
jsh-common: jsh-common.c jsh-common.h
gcc -g -c jsh-common.c -o jsh-common.o
alias: alias.c alias.h jsh-common.h
gcc -g -c alias.c -o alias.o
jsh: jsh-parse.c jsh.c jsh-common.h
gcc -g -c jsh.c -o jsh.o
link: jsh-common.o jsh.o alias.o
gcc -g jsh-common.o jsh.o alias.o -o jsh -l readline
when running shcat on a large file: shcat < documentationMitsuba.txt
a segmentation fault occurs.
this is the end of the output from gdb:
13.2.5. Taking control of the logging system
Many operations in Mitsuba will print one or more log messages during their execution. By default,
they will be printed to the console, which may be undesirable. Similar to the C++ side, it is possible
to define custom Formatter and Appender classes to interpret and direct the flow of these messages.
This is also useful to keep track of the progress of rendering jobs.
Roughly, a Formatter turns detailed information about a logging event into a human-readable
string, and a Appender routes it to some destination (e.g. by appending it to a file or a log viewer in
a graphical user interface). Here is an example of how to activate such extensions:
import mitsuba
from mitsuba.core import *
class MyFormatter(Formatter):
def format(self, logLevel, sourceClass, sourceThread, message, filename, line):Program received signal SIGSEGV, Segmentation fault.
0x00007ffff78198f3 in _IO_vfprintf_internal (s=, format=, ap=ap@entry=0x7fffffffda68) at vfprintf.c:1661
1661 vfprintf.c: No such file or directory.
(gdb)
What needs to be done:
getprompt()
int hostlen = sysconf(_SC_HOST_NAME_MAX);
-L<path_to_readline_lib> -lreadline
.memalloc(sizeof(alias))
-> memalloc(sizeof(struct alias))
in alias()
Allow a custom prompt. Things todo:
prompt "user defined prompt string"
built_in shell commandchar* getprompt(int status)
function in jsh.c
char* getprompt(int status, char *user_prompt_string)
%l max_value
?) for the cur directory and truncating it to min{curdir, max_value} and if truncated -> delete the beginning of the string until the first '/'Updated todo list:
Todo for release 1.0:
CustomizingPrompt
MAX_DIR_LENGTH
. This should be user definable, maybe in the prompt string (as in zsh) or using yet another built_in set
or so? Note the MAX_PROMPT_LENGTH
can remain hardcoded as we always need a (reasonable) limit for the prompt. When a user tries to set a prompt of more then 100 chars, he's probably hacking :pTodo for future releases:
#
when sudo is activated~
git
support (would be really cool ;-) )
Take, for example, this directory structure:
[gijs@therion /tmp]$ tree
.
├── Appels
├── Bramen
├── Clementijnen
├── Druiven
└── Groenten
├── Bloemkool
├── Bonen
├── Broccoli
└── Paprika
Note that the current working directory is still /tmp
. Typing cd Bloem
Tab should yield: cd Groenten/Bloemkool/
.
In other words, when we cd
to a directory, jsh
should make a list of subdirectory's subdirectories (got it?). We should also look into the possibility of autocompleting parent directories:
[gijs@therion /tmp]$ cd Groenten/
[gijs@therion Groenten]$ pwd
/tmp/Groenten
Now, pressing cd Drui
Tab should yield: cd ../Druiven
We should test whether this is feasible. We should make sure that jsh
stays snappy. We could limit the number of subdirectories / levels if necessary.
I want to be able to install jsh
system-wide. When it's installed, I might want to remove it. I should be able to do so with a script, because it's hard to find out which files I should remove by hand.
It would be nice if this option could be embedded as a flag in make
or something like that. Maybe we can also put it in the installer.
Expected behaviour:
$ pwd
/mnt/Data
$ cd Muziek/Franki<TAB>
$ cd Muziek/Frankie Knuckles\ -\ Beyond\ The\ Mix/
$ pwd
/mnt/Data/Muziek/Frankie Knuckles - Beyond The Mix/
Actual behaviour:
$ pwd
/mnt/Data
$ cd Muziek/Franki<TAB>
$ cd Muziek/Frankie Knuckles - Beyond The Mix/ ## No escaping!
[DEBUG: You entered: 'cd Muziek/Frankie Knuckles - Beyond The Mix/']
[DEBUG: alias: input resolved to: 'cd Muziek/Frankie Knuckles - Beyond The Mix/']
jsh: cd: wrong number of arguments (expected = 1)
[DEBUG: built-in: executed 'cd']
[DEBUG: freeing comd struct for 'cd']
[DEBUG: parseexpr: expr evaluated with return value 1]
[DEBUG: readcmd: freeing memory for: 'cd']
$ pwd
/mnt/Data
Since the jsh
code base is growing, we should think more about structuring. Currently the code is far from cohesive. This of course limits readability and makes adding new features harder.
Ideally, the code should be divided into small cohesive 'modules', communicating via C header interfaces. Just like the alias.c & alias.h
files now. I therefore drafted out a first idea on paper:
Sorry for the crappy quality ;-) Also, don't worry about the arrows to much. Most of them are just #includes
for jsh-common.h
, containing some helper functions. I marked the important relationships in green. Since all functionality in a shell is related, I think the coupling will never be very satisfying, but at least this way it's more controlled.
As you can see, functionality is divided in different header files. This will make adding new features (e.g. new autocompleters, new built_ins, grammar enhancement, prompt customizing, ...) more local and thus also easier. Separating the command line interface in particular, will allow implementing a alternative simpler 'fall-back' modus for readline
. Being more independent from readline
can be nice, I think ;-) Especially if we want to port to Android, see issue #23 .
Drop your thoughts! However, since jsh
is not a master-thesis, I started a zero-code policy till Thursday so I won't be starting on this yet... ;-)
the description of the project "A proof-of-concept UNIX shell implementation in C" is outdated. It is more than a proof-of-concept. If changed, this description in the code should be updated as well.
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.