narc0tiq / factorio-updater Goto Github PK
View Code? Open in Web Editor NEWFactorio update helper for headless servers
License: MIT License
Factorio update helper for headless servers
License: MIT License
Hey I tried to update my newly installed version 0.13.8 to 0.13.9 but somehow the udpate was killed. I dont know if this is a problem from your script or from factorio itself
[root@mail opt]# service factorio update
Checking for updates...
New version core-linux_headless64 0.13.9.
Wrote /tmp/factorio-update/core-linux_headless64-0.13.8-0.13.9-update.zip, apply with `factorio --apply-update /tmp/factorio-update/core-linux_headless64-0.13.8-0.13.9-update.zip`
Applying /tmp/factorio-update/core-linux_headless64-0.13.8-0.13.9-update.zip ...
Killed
0.000 2016-07-18 17:05:01; Factorio 0.13.8 (build 23239, linux64, headless)
0.000 Operating system: Linux
0.000 Program arguments: "/opt/factorio/bin/x64/factorio" "--apply-update" "/tmp/factorio-update/core-linux_headless64-0.13.8-0.13.9-update.zip"
0.000 Read data path: /opt/factorio/data
0.000 Write data path: /opt/factorio
0.000 Binaries path: /opt/factorio/bin
0.023 Running in headless mode
0.028 Loading mod core 0.0.0 (data.lua)
0.034 Loading mod base 0.13.8 (data.lua)
0.224 Checksum for core: 714099156
0.224 Checksum for mod base: 1905699976
1.275 Custom inputs active: 0
1.277 Factorio initialised
1.292 Info Updater.cpp:389: Applying update /tmp/factorio-update/core-linux_headless64-0.13.8-0.13.9-update.zip
Error! Failed to apply update
You can try to apply it manually with:
su factorio -c "/opt/factorio/bin/x64/factorio --apply-update /tmp/factorio-update/core-linux_headless64-0.13.8-0.13.9-update.zip"
updating with the command given at the end did not work too.
When pulling user and token from a credentials file, they are used only for get_updater_data, not for actually downloading updates.
Hi,
I recently created a Factorio v0.12.29 server for my own. When I run $ python update_factorio.py -x -d
then I get SNIMissingWarning
and InsecurePlatformWarning
. The result is "No updates available for version None (latest experimental is 0.12.30)."
Do you have ideas what was the problem? Could you fix it?
Thanks,
kP.
For some reason the script refuses to update to experimental builds?
[factorio@mc opt]$ python ./factorio-updater/update_factorio.py -f 0.13.20 -x --dry-run
No updates available for version 0.13.20 (latest experimental is 0.14.8).
-t TOKEN, --token TOKEN Your Factorio updater token, also from player- data.json.
In my player-data.json file there is no token. Is it needed to get updates for a headless server?
I've purchased the game via Steam if this make any difference.
(in fact I have only read the Readme.md, not tested because of fear I could loose my access to the game) ๐ฌ
Unable to determine source version. Please provide either a starting version (with --for-version) or a Factorio binary (with --apply-to).
Happened to me today trying to run it :/
not sure what to do
thanks
Since the Client can update mods, and the headless server can't, this might be a great addition to the script.
In short python2 support has been droped. There are lots of tools and easy guides of upgrading simple scripts like this to python3
I'm on an ubuntu server updating from a working 14.23 trying to get 15.10. I tried running
python /home/factorio-updater/update_factorio.py -p core-linux_headless64 -f 0.14.23 -x
which gave me:
factorio --apply-update /tmp/core-linux_headless64-0.15.9-0.15.10-update.zip
but when I run the command I get this output:
factorio --apply-update /tmp/core-linux_headless64-0.15.9-0.15.10-update.zip
0.000 2017-05-13 21:10:57; Factorio 0.14.23 (build 25374, linux64, headless)
0.091 Operating system: Linux (Ubuntu 16.04)
0.092 Program arguments: "/home/factorio/bin/x64/factorio" "--apply-update" "/tmp/core-linux_headless64-0.15.9-0.15.10-update.zip"
0.092 Read data path: /home/factorio/data
0.092 Write data path: /home/factorio
0.092 Binaries path: /home/factorio/bin
0.107 System info: [CPU: Intel(R) Xeon(R) CPU E5-2630L 0 @ 2.00GHz, 1 core, RAM: 488MB]
0.107 Running in headless mode
0.111 Loading mod core 0.0.0 (data.lua)
0.120 Loading mod base 0.14.23 (data.lua)
0.271 Checksum for core: 1291735968
0.271 Checksum for mod base: 786624017
1.069 Info PlayerData.cpp:55: Local player-data.json available, timestamp 1494709851
1.070 Info PlayerData.cpp:62: Cloud player-data.json unavailable
1.072 Custom inputs active: 0
1.073 Factorio initialised
1.074 Info Updater.cpp:388: Applying update /tmp/core-linux_headless64-0.15.9-0.15.10-update.zip
2.250 Error Util.cpp:57: File /home/factorio/bin/x64/factorio has unexpected content
2.268 Goodbye
Any thoughts?
would be great to have a zip -t integrity check.
I added this in my script that notifies users / shuts down servers / applies update etc.
While trying to get from 0.13.x to 0.13.19 (now stable), factorio-updater wants to get 0.14.0. Example:
python update_factorio.py --for-version 0.13.15 --package core-linux_headless64 --dry-run
Dry run: would have fetched update from 0.13.15 to 0.13.16.
Dry run: would have fetched update from 0.13.16 to 0.13.17.
Dry run: would have fetched update from 0.13.17 to 0.13.18.
Dry run: would have fetched update from 0.13.18 to 0.14.0.
The experimental update is working as expected:
python update_factorio.py --for-version 0.13.15 --package core-linux_headless64 --experimental --dry-run
Dry run: would have fetched update from 0.13.15 to 0.13.16.
Dry run: would have fetched update from 0.13.16 to 0.13.17.
Dry run: would have fetched update from 0.13.17 to 0.13.18.
Dry run: would have fetched update from 0.13.18 to 0.14.0.
Dry run: would have fetched update from 0.14.0 to 0.14.1.
This is the get-available-version i receive:
{
"from": "0.13.17",
"to": "0.13.18"
},
{
"from": "0.13.18",
"to": "0.13.19"
},
{
"from": "0.13.18",
"to": "0.14.0"
},
{
"from": "0.13.2",
"to": "0.13.3"
},
{
"from": "0.13.3",
"to": "0.13.4"
},
{
"from": "0.13.4",
"to": "0.13.5"
},
{
"from": "0.13.5",
"to": "0.13.6"
},
{
"from": "0.13.6",
"to": "0.13.7"
},
{
"from": "0.13.7",
"to": "0.13.8"
},
{
"from": "0.13.8",
"to": "0.13.9"
},
{
"from": "0.13.9",
"to": "0.13.10"
},
{
"from": "0.14.0",
"to": "0.14.1"
},
{
"stable": "0.13.19"
}
After over 8 years, 1.0 has finally come.
This script, however, only sees 0.18.47 as the newest.
I have a local isntallation of the factorio headless server 0.13.20 in /home/jan/factorio/bin/x64/factorio
Thatfor I run python3 update_factorio.py -a /home/jan/factorio/bin/x64/factorio
But that gives a return of
No updates available for version 0.13.20 (latest stable is 0.14.23). Did you want `--experimental`?
It doesn't update the server and it doesn't even seem to recognize that there is a newer version, even though it displays just that. What's the problem here?
Trying to use you script but need little help. I can get this far......
root@fluxcapacitor:/opt/factorio# python3 update_factorio.py -f 1.1.100
Wrote /tmp/core-linux_headless64-1.1.100-1.1.101-update.zip, apply with factorio --apply-update /tmp/core-linux_headless64-1.1.100-1.1.101-update.zip
Looks like I have downloaded the update but I can't figure out the correct syntax to apply it..
Getting a error on ubuntu 18
sudo service factorio update
Checking for updates...
Traceback (most recent call last):
File "/opt/factorio-updater/update_factorio.py", line 4, in <module>
import os, posixpath, requests, re, sys
ImportError: No module named requests
Update check failed!
and yes i have requests
downloaded
Hi,
I get the following error when using your updater script.
I'm using Debian 8.8, can you help me?
I use the following command:
python3 update_factorio.py -p core-linux_headless64 -xDa /home/factorio/factorio
Results in:
Traceback (most recent call last): File "update_factorio.py", line 197, in <module> main() File "update_factorio.py", line 155, in main version_output = subprocess.check_output([args.apply_to, "--version"], universal_newlines=True) File "/usr/lib/python3.4/subprocess.py", line 607, in check_output with Popen(*popenargs, stdout=PIPE, **kwargs) as process: File "/usr/lib/python3.4/subprocess.py", line 859, in __init__ restore_signals, start_new_session) File "/usr/lib/python3.4/subprocess.py", line 1457, in _execute_child raise child_exception_type(errno_num, err_msg) PermissionError: [Errno 13] Permission denied
Best regards,
Chanz
I can't update to latest experiment. My current version is 0.16.51. I did use the -x option to get experimental version.
xxx@xxx:/opt/factorio/bin/x64$ sudo python update_factorio.py -xDa ./factorio
Auto-detected starting version as 0.16.51 from binary.
No updates available for version 0.16.51 (latest experimental is 0.17.25).
After applying upgrade found that factorio was no longer executable and the next update (and start of service) failed. The issue does not allow multiple updates without intervention.
python update_factorio.py -xDa /opt/factorio/bin/x64/factorio -v https://www.factorio.com/get-available-versions?apiVersion=2 Traceback (most recent call last): File "update_factorio.py", line 231, in <module> sys.exit(main()) File "update_factorio.py", line 208, in main for_version = find_version(args) File "update_factorio.py", line 153, in find_version version_output = subprocess.check_output([args.apply_to, "--version"], universal_newlines=True) File "/root/miniconda3/lib/python2.7/subprocess.py", line 212, in check_output process = Popen(stdout=PIPE, *popenargs, **kwargs) File "/root/miniconda3/lib/python2.7/subprocess.py", line 390, in __init__ errread, errwrite) File "/root/miniconda3/lib/python2.7/subprocess.py", line 1025, in _execute_child raise child_exception OSError: [Errno 13] Permission denied
Following helped proceed with next update and was required each time.
chmod +x /opt/factorio/bin/x64/factorio
should be part of script to auto-set execute permissions on factorio binary each time it is updated.
Hello,
we have updated the headless server download mechanism. So I just thought I would give you a heads up. Now the server is for download for free for anyone even without an account. Check it out on the web: https://www.factorio.com/download-headless/stable. Also I don't quite understand what is the point of the user specifying the package name when this is only for headless server (and those are only linux packages).
Edit:
Hmm,now I actually checked the code and see that you are using the updater api, not parsing the website (that was my original impression). So this will be of no use to you then, sorry. We will see how to tackle this properly - I would say by supporting the update in headless natively.
Cheers
Hello, I am trying to run the script and getting a syntax error over SSH on a headless server.
$ python updater.py
File "updater.py", line 242
def parse_credentials(credentials_file: str, user: str, token: str):
^
SyntaxError: invalid syntax
Things I have tried so far separately and together, I'm no coder:
-run directly from server instead of SSH
-verified user and token are in server-settings.json
-changed str values in line 242 to appropriate user and token
-added single quotes in various places in line 242 to make it look like other lines
-read many things in the forum that are above my understanding regarding APIs and authentication
-wiped the server and manually installed 1.1.61 to get the clients working
-run script again
Thank you for any help! If running the script is not possible on my setup, any help to update without wiping would be awesome too. Every time I tried dumping update files or stopping, updating, and restarting it would stay on the older version.
so i am trying to use this on windows and get this when trying to update
D:\szentigrade\Factorio\bin\x64>python update_factorio.py -u Szentigrade -t <excluded> -xDa D:\szentigrade\Factorio\bin\x64\factorio.exe
Version: 0.15.16 (build 30063, win64, alpha)
Binary version: 64
Map input version: 0.12.0-0
Map output version: 0.15.16-1
No updates available for version None (latest experimental is 0.15.18).
When updating my experimental server, I get an error stating that experimental updates are disabled.
python ./update_factorio.py -xDa ~/.factorio/bin/x64/factorio
Auto-detected starting version as 0.15.14 from binary.
Applying update with `/home/ubuntu/.factorio/bin/x64/factorio --apply-update /tmp/core-linux_headless64-0.15.14-0.15.15-update.zip`.
b' 0.000 2017-06-02 15:33:36; Factorio 0.15.14 (build 30011, linux64, headless)\n 0.040 Operating system: Linux (Ubuntu 16.04)\n 0.042 Program arguments: "/home/ubuntu/.factorio/bin/x64/factorio" "--apply-update" "/tmp/core-linux_headless64-0.15.14-0.15.15-update.zip" \n 0.042 Read data path: /home/ubuntu/.factorio/data\n 0.042 Write data path: /home/ubuntu/.factorio\n 0.042 Binaries path: /home/ubuntu/.factorio/bin\n 0.055 System info: [CPU: Intel(R) Xeon(R) CPU E5-2676 v3 @ 2.40GHz, 1 core, RAM: 486MB]\n 0.062 Running in headless mode\n 0.084 Loading mod core 0.0.0 (data.lua)\n 0.094 Loading mod base 0.15.14 (data.lua)\n 0.238 Loading mod base 0.15.14 (data-updates.lua)\n 0.311 Checksum for core: 2224076952\n 0.311 Checksum of base: 2355693671\n 0.456 Info PlayerData.cpp:56: Local player-data.json available, timestamp 1495902333\n 0.456 Info PlayerData.cpp:63: Cloud player-data.json unavailable\n 0.466 Custom inputs active: 0\n 0.466 Info Updater.cpp:751: Downloading https://updater.factorio.com/get-available-versions?username=mckalexee&token=<private>&apiVersion=2\n 0.599 Some core updates would be reachable if experimental updates were enabled.\n 0.599 0 packages available to download (experimental updates disabled).\n 0.603 Factorio initialised\n 0.603 Info Updater.cpp:382: Applying update /tmp/core-linux_headless64-0.15.14-0.15.15-update.zip\n 1.871 Goodbye\n 0.000 Error Util.cpp:62: std::bad_alloc\n'
Traceback (most recent call last):
File "./update_factorio.py", line 197, in <module>
main()
File "./update_factorio.py", line 187, in main
verbose_aware_exec(update_args, args.verbose)
File "./update_factorio.py", line 133, in verbose_aware_exec
captured = subprocess.check_output(exec_args, stderr=subprocess.STDOUT)
File "/usr/lib/python3.5/subprocess.py", line 626, in check_output
**kwargs).stdout
File "/usr/lib/python3.5/subprocess.py", line 708, in run
output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '['/home/ubuntu/.factorio/bin/x64/factorio', '--apply-update', '/tmp/core-linux_headless64-0.15.14-0.15.15-update.zip']' returned non-zero exit status 1
Look into what fac
does and do something similar.
Update player-data.json
as needed and read it when the --user
and/or --token
are left out of the command line.
I'm running Windows and I suspect something weird is happening because of that? I've messed around for awhile trying to redirect factorio's output to a string in python. subprocess.check_output(["ping", "127.0.0.1"]) works fine and actually captures the output, but anything factorio related will print it to the console, but never captures it. this is probably more of a failing of python on windows than with your script directly, but I wonder if you might have any type of workaround for this?
As title. Maybe someone wants to console update their Factorio on a platform where /tmp
isn't available or something.
It's really not nice to have a complete lack of tests, even if it is unclear what can be tested. At the very least, an issue like #11 could be automatically checked for possible regression*.
* - I hesitate to say it wouldn't have happened, since I probably wouldn't have expected a split upgrade path until one actually presented itself, but now we know it can exist and we should make sure we continue supporting it.
https://updater.factorio.com/get-available-versions?apiVersion=2
Unable to determine source version. Please provide either a starting version (with --for-version) or a Factorio binary (with --apply-to).
Did the --version output format change? Seems broken with 0.16.34
At each upgrade the binary lost the execution right.
For the moment I added a chmod +x in my script, but something should be done here no ?
The version under concern is the : d0e6b25 (not the last indeed, but the diff log of 9196fe2 shouldn't change something).
Before that It's working on bae51e9
thk
On windows when you run Factorio with the updater, it seems to relaunch itself:
0.348 Factorio initialised
1.009 Goodbye
Regards from the updater slave
0.000 2016-11-10 18:43:58; Factorio 0.14.19 (build 25291, win64, alpha)
0.000 Operating system: Windows 10 (version 1607)
When that happens for me, my subprocess.check_output call returns, while the updater slave continues to try to do it's work. Unfortunately, when the cleanup happens after the main Factorio process exits, it then makes the update unavailable to the updater slave.
I was wondering if you'd experienced this issue yourself?
Support initial installation of the headless client. This would allow automation of server creation/updating.
I'm not able to get the update script to run. I am receiving an error when trying to run it, even when using the --help switch.
[factorio@localhost factorio-updater-master]$ python update_factorio.py --help
Trackback (most recent call last):
File "update_factorio.py", line 4, in <module>
import os, posixpath, requests, re, sys
ImportError: No module named requests
CentOS 7
Updated everything. Python, PIP and Request installed per instructions.
The script finds no update for version 0.16.51
. But the 0.17.79
is stable since months.
# ./update_factorio.py --for-version 0.16.51
No updates available for version 0.16.51 (latest stable is 0.17.79). Did you want `--experimental`?
Thanks
Just sharing this script which I knocked together to streamline my updating process for my server. I have this script symlinked into each factorio install folder, and a simple ./update
in that folder will pull down and apply the latest version.
#!/bin/sh
FACTORIO_BINARY=./bin/x64/factorio
FACTORIO_PACKAGE=core-linux_headless64
FACTORIO_UPDATEDIR=./updater-temp
key="$1"
case $key in
-s|stable|--stable)
EXPERIMENTAL=
echo "Set to STABLE release mode!"
;;
-e|-x|experimental|--experimental)
EXPERIMENTAL=-x
echo "Set to EXPERIMENTAL release mode!"
;;
*)
EXPERIMENTAL=
echo "Defaulting to STABLE release mode. To set EXPERIMENTAL release mode, please use '$0 experimental'"
;;
esac
mkdir -p $FACTORIO_UPDATEDIR
FACTORIO_VERSION=`$FACTORIO_BINARY --version |awk 'NR==1{print $2}'`
./update_factorio.py -p $FACTORIO_PACKAGE -f $FACTORIO_VERSION $EXPERIMENTAL -O $FACTORIO_UPDATEDIR
if compgen -G "$FACTORIO_UPDATEDIR/*.zip" >/dev/null; then
for f in `ls -tr $FACTORIO_UPDATEDIR/*.zip`
do
$FACTORIO_BINARY --apply-update $f && rm $f
done
fi
FACTORIO_VERSION=`$FACTORIO_BINARY --version |awk 'NR==1{print $2}'`
echo ""
echo "***** ***** ***** ***** ***** ***** ***** ***** *****"
echo "Factorio version is now: $FACTORIO_VERSION"
Hello,
For the moment I have to stop the factorio server just in case of new update is available (the binary doesn't allow to self update if running).
I think that return a error/shell/return code != 0 if new version available in dry-run mode could be interesting before really stop the server and effectively run the update.
Thanks
Python 3.12 updates a DeprecatedWarning
that was added in 3.6 to a SyntaxWarning
./update_factorio.py -h
update_factorio.py:196: SyntaxWarning: invalid escape sequence '\d'
source_version = re.search("Version: (\d+\.\d+\.\d+)", version_output)
Replacing the escapes in the regular expression search from \d
โ \\d
(or \.
โ \\.
fixes it.
See Pull Request #64
I just want to note for anyone who can stuck on problem with SNIMissingWarning messages like this:
/usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/util/ssl_.py:315: SNIMissingWarning: An HTTPS request has been made, but the SNI (Subject Name Indication) extension to TLS is not available on this platform.
... etc.
I've solved this with:
pip install ndg-httpsclient
pip install pyasn1
additionally you can try also (but not needed in my case):
pip install urllib3
pip install pyopenssl
Cheers
Hi,
I have a problem when I just make following comand on my Server (Ubuntu 14.04.5 LTS):
cd /opt/factorio-updater
python update_factorio.py -l
Message I get:
/usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/util/ssl_.py:79: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
InsecurePlatformWarning
Traceback (most recent call last):
File "update_factorio.py", line 138, in <module>
main()
File "update_factorio.py", line 106, in main
j = get_updater_data(args.user, args.token)
File "update_factorio.py", line 47, in get_updater_data
raise DownloadFailed('Could not download version list.', r.status_code)
__main__.DownloadFailed: ('Could not download version list.', 404)
Do you know how I can fix it? I am kind of a beginner in Linux-Usage.
Greetz
Muardin
Command as run:
$ ./update_factorio.py -xDa ../factorio/bin/x64/factorio
Auto-detected starting version as 0.16.4 from binary.
/usr/lib/python2.7/dist-packages/urllib3/connectionpool.py:794: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedoc
s.org/en/latest/security.html
InsecureRequestWarning)
Applying update with `../factorio/bin/x64/factorio --apply-update /tmp/core-linux_headless64-0.16.4-0.16.5-update.zip`.
Update applied, deleting temporary file /tmp/core-linux_headless64-0.16.4-0.16.5-update.zip.
Resulting:
$ ./bin/x64/factorio --server-settings data/server.json --start-server Server --port=34197
-bash: ./bin/x64/factorio: Permission denied
$ ls -la ./bin/x64/factorio
-rw-rw-r-- 1 factorio factorio 97618248 Dec 18 13:54 ./bin/x64/factorio
Easily fixed afterward, but feels like a bug worth reporting.
Done on brand new Ubuntu 16.04 with requests installed from apt.
Looks like https://updater.factorio.com/get-available-versions is missing 0.17
.
Hi all,
Whenever I try and update my headless server using your script I run into the following error (regardless of re-install)
subprocess.CalledProcessError: Command '['/root/factorio/bin/x64/factorio', '--apply-update', '/tmp/core-linux_headless64-0.15.37-0.15.38-update.zip']' returned non-zero exit status -9
Any idea what's causing this?
will be nice if u can make the script to download mods as well when u update factorio it will always download the newest mods as well all in 1 script
it would seem a flag is missing with the url request that when it gets an update this warning is shown
insecurerequestwarning
Look into what fac
does and do that, too.
Also, for experimental/not, we should look at the Factorio config, and use command-line switches to update said config if present.
Hello,
Since I'm using CentOS, with the new experimental version of factorio, I have to use a separately compiled version of glibc (2.18). May I request an argument that would point this script to the proper glibc?
Here is an example on how I start the game:
/opt/glibc-2.18/lib/ld-2.18.so --library-path /opt/glibc-2.18/lib /opt/factorio/bin/x64/factorio --start-server-load-latest --executable-path /opt/factorio/bin/x64/factorio
Thanks,
Dan
As per #22, when passing a directory as the Factorio binary you get the semi-cryptic "Permission denied" (because you don't execute directories -- the execute bit means something else!). Consider doing our own checks:
apply_to
is a directory, try looking for a bin/x64/factorio
executable insideExtra sanity: remember that if the caller includes a --for-version
, we won't be asking the Factorio anything (but perhaps we should?) until it's time to apply the patches. That should fail more gracefully, too.
Would be nice to have an option to skip downloading if the filename already exists.
If you run a lot of servers, its nice not to keep re-downloading the file.
I hacked it to do it, but it would be nicer if it was an option that could be set.
Add --auto-apply
to have the updater make Factorio apply the updates it downloads.
Add --delete-after-apply
to delete the temporary files afterward.
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.