code-distortion / adapt Goto Github PK
View Code? Open in Web Editor NEWA Laravel package that builds databases for your tests, improving their speed
License: MIT License
A Laravel package that builds databases for your tests, improving their speed
License: MIT License
When Adapt starts, before building databases, it checks for stale databases to remove. It does this by looping through the present connections, and checking the databases within. However these connections can time-out, adding a delay to the test-process.
This is particularly prevalent when using a PostgreSQL database, because the way Laravel's config is set up means that the (unused) MySQL connection exists, but with the PostgreSQL server's details. Adapt then tries to connect to the PostgreSQL server with the MyQSL client, and this particular combination takes 1 minute before timing out.
[2022-06-21 14:22:12] testing.DEBUG: ADAPT: Looking for stale things to remove
[2022-06-21 14:22:12] testing.DEBUG: ADAPT: Generated a content-based build-source checksum (0ms)
[2022-06-21 14:22:12] testing.DEBUG: ADAPT: Retrieved database list (connection: "sqlite", driver: "sqlite") (0ms)
[2022-06-21 14:22:12] testing.DEBUG: ADAPT: - No databases were found (0ms)
[2022-06-21 14:23:12] testing.WARNING: ADAPT: Could not retrieve database list (connection: "mysql", driver: "mysql") (1m)
[2022-06-21 14:23:12] testing.DEBUG: ADAPT: Retrieved database list (connection: "pgsql", driver: "pgsql") (13ms)
[2022-06-21 14:23:12] testing.DEBUG: ADAPT: - Found database "db_484a0c_399f58dcb9c0" (usable) (7ms)
[2022-06-21 14:23:12] testing.WARNING: ADAPT: Could not retrieve database list (connection: "sqlsrv", driver: "sqlsrv") (1ms)
[2022-06-21 14:23:12] testing.DEBUG: ADAPT: Retrieved snapshot list (0ms)
[2022-06-21 14:23:12] testing.DEBUG: ADAPT: - Found snapshot "/var/www/html/database/adapt-test-storage/snapshots/snapshot.db.484a0c-33d736a4f21d.pgsql" (usable) (0ms)
[2022-06-21 14:23:12] testing.DEBUG: ADAPT: - Found snapshot "/var/www/html/database/adapt-test-storage/snapshots/snapshot.db.484a0c-a858496f4d3b.pgsql" (usable) (0ms)
[2022-06-21 14:23:12] testing.DEBUG: ADAPT: Nothing found to remove - total time taken (1m)
…
Hi, when I try to run tests using the command vendor/bin/phpunit, it throws an error related to transactions.
ADAPT DEBUG: ┌── ADAPT (v0.12.11) ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
ADAPT DEBUG: │ Preparing a database for connection "mysql_testing" │
ADAPT DEBUG: │ For test "Tests\Unit\TestJobTest::test_job_returns_mode" |
ADAPT DEBUG: └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
ADAPT DEBUG: ┌── Software ──────────────────────────────────────┐
ADAPT DEBUG: │ OS: Linux │
ADAPT DEBUG: │ PHP: 8.1.24 │
ADAPT DEBUG: │ Laravel: 9.52.15 │
ADAPT DEBUG: │ PHPUnit: 9.6.11 │
ADAPT DEBUG: │ Adapt: 0.12.11 │
ADAPT DEBUG: │ MySQL: 10.10.2-MariaDB-1:10.10.2+maria~ubu2204 │
ADAPT DEBUG: └──────────────────────────────────────────────────┘
ADAPT DEBUG: ┌── Build Sources ───────────────────────────────────────┐
ADAPT DEBUG: │ Initial imports: None │
ADAPT DEBUG: │ Migrations: "/var/www/html/database/migrations" │
ADAPT DEBUG: │ Seeder: "DatabaseSeeder" │
ADAPT DEBUG: │ Snapshots enabled? No │
ADAPT DEBUG: └────────────────────────────────────────────────────────┘
ADAPT DEBUG: ┌── Build Settings ──────────────────────────────────────┐
ADAPT DEBUG: │ Using scenarios? No │
ADAPT DEBUG: │ Re-use method: Transaction │
ADAPT DEBUG: │ Verify db after? No │
ADAPT DEBUG: │ For a browser test? No │
ADAPT DEBUG: │ Parallel testing? No │
ADAPT DEBUG: │ Build-checksum: "8008831e68a2ad7f2354766cd591e81e" │
ADAPT DEBUG: │ Snapshot-checksum: "e0153c44b18f9325b8f2c1af973e4398" │
ADAPT DEBUG: │ Scenario-checksum: n/a │
ADAPT DEBUG: └────────────────────────────────────────────────────────┘
ADAPT DEBUG: ┌── Resolved Database ────────┐
ADAPT DEBUG: │ Connection: "mysql_testing" │
ADAPT DEBUG: │ Driver: "mysql" │
ADAPT DEBUG: │ Host: "mysql" │
ADAPT DEBUG: │ Database: "tests" │
ADAPT DEBUG: └─────────────────────────────┘
ADAPT DEBUG: Leaving the database for connection "mysql_testing" unchanged as "tests"
ADAPT DEBUG: The existing database "tests" can be reused (2ms)
ADAPT ERROR: ┌── An Exception Occurred - Illuminate\Database\QueryException ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
ADAPT ERROR: │ SQLSTATE[HY000]: General error: 1205 Lock wait timeout exceeded; try restarting transaction (SQL: UPDATE `____adapt____` SET `scenario_checksum` = ?, `last_used` = 2023-10-13 11:43:04) │
ADAPT ERROR: │ /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php on line 760 │
ADAPT ERROR: │ │
ADAPT ERROR: │ Previous Exception - PDOException │
ADAPT ERROR: │ SQLSTATE[HY000]: General error: 1205 Lock wait timeout exceeded; try restarting transaction │
ADAPT ERROR: │ /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php on line 570 │
ADAPT ERROR: └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
So my problem is very simple. I have a table called "user_permissions" where I store a list of user permissions that become gates.
They are defined in the AuthServiceProvider.php file as per the standard documentation, like this:
public function boot()
{
$this->registerPolicies();
foreach ($this->getPermissions() as $permission) {
\Gate::define($permission->name, function (User $user) use ($permission) {
return $user->hasPermission($permission);
});
}
\Log::debug('AuthServiceProvider Is Being Executed for: ' . config('app.env') . ' with ' . count(\Gate::abilities()) . ' gates from ' . count($this->getPermissions()) . ' permissions.');
}
public function getPermissions()
{
try {
return UserPermission::all();
} catch(\Exception $e) {
return [];
}
}
The problem is that when this executes, it's not pointing to the adapt hashed database, it's still pointing to the standard testing database mentioned in my .env.testing file. Which has a totally different state and disconnected from the tests.
I was able to reproduce it this way:
Database mentioned in the .env.testing to be totally empty.
The query will be empty in the AuthServiceProvider.php
Database mentioned in the .env.testing is migrated and seeded
The query will get the results from that database and define the gates.
I don't know the innerworkings of the package, is it possible to override the database name in the in-memory config sooner so that it uses it, or not?
I did not find any other way to ask this, I'm asking it here.
We have a Laravel application that uses 2 databases, some for some models, others for other. Is there a way to have both databases initialized and up and running in the exact same way with the same hashing/versioning features?
Thank you.
Attempted to run an sqlite test (currently fails as in the process of setting this up for our application, looks super useful by the way!) and then a subsequent test run fails, possibly because \CodeDistortion\Adapt\Adapters\LaravelSQLite\LaravelSQLiteReuseMetaDataTable::loadReuseInfo
returns an array and we try and do $reuseInfo->project_name
?
── An Exception Occurred - ErrorException ────────────────────────────────────────────────────────────────────────┐ {"request_id":"oBIL0tPjGZxehr6r"}
[2022-10-20 09:52:40] testing.ERROR: ADAPT: │ Attempt to read property "project_name" on array │ {"request_id":"oBIL0tPjGZxehr6r"}
[2022-10-20 09:52:40] testing.ERROR: ADAPT: │ /opt/project/vendor/code-distortion/adapt/src/Adapters/AbstractClasses/AbstractReuseMetaDataTable.php on line 66 │ {"request_id":"oBIL0tPjGZxehr6r"}
[2022-10-20 09:52:40] testing.ERROR: ADAPT: └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: Disconnecting established database connection "testing" {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: Changed the default connection to: "sqlite" {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: Looking for stale things to remove {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: Generated a build-source checksum based on file modified timestamps (5ms) {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: Retrieved database list (connection: "sqlite", driver: "sqlite") (0ms) {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: - Found database "/opt/project/database/adapt-test-storage/databases/testing.7ac05c-b166cdd8bfb6.sqlite" (stale - within grace period) (3ms) {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: - Found database "/opt/project/database/adapt-test-storage/databases/testing.c18964-e9f3186080bc.sqlite" (stale - within grace period) (3ms) {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: - Found database "/opt/project/database/adapt-test-storage/databases/testing.fc1a39-b166cdd8bfb6.sqlite" (usable) (3ms) {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: Retrieved snapshot list (0ms) {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: - No snapshots were found (0ms) {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: Nothing found to remove - total time taken (15ms)
{"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: ┌── ADAPT (v0.12.0) ─────────────────────────────────────────────────────────────────────────────────┐ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: │ Preparing a database for connection "sqlite" │ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: │ For test "OurTests::TestSomething" │ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: └────────────────────────────────────────────────────────────────────────────────────────────────────┘ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: Detected software versions (1ms) {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: ┌── Software ──────┐ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: │ OS: Linux │ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: │ PHP: 8.1.11 │ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: │ Laravel: 8.83.23 │ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: │ PHPUnit: 9.5.24 │ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: │ Adapt: 0.12.0 │ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: │ SQLite: 3.22.0 │ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: └──────────────────┘ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: ┌── Build Sources ─────────────────────────────────────┐ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: │ Initial imports: None │ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: │ Migrations: Yes │ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: │ Seeder: "Database\Seeders\DatabaseSeeder" │ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: │ Snapshots enabled? No │ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: └──────────────────────────────────────────────────────┘ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: ┌── Build Settings ──────────────────────────────────────┐ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: │ Using scenarios? Yes │ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: │ Re-use method: Transaction │ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: │ Verify db after? No │ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: │ For a browser test? No │ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: │ Parallel testing? No │ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: │ Build-checksum: "fc1a3902d7d9290eadc6857f89fd6715" │ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: │ Snapshot-checksum: "20eae355a0e7a8bd5c97d9a05a384bbe" │ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: │ Scenario-checksum: "b166cdd8bfb6cbb738992fa3bc66c544" │ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: └────────────────────────────────────────────────────────┘ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: ┌── Resolved Database ────────────────────────────────────────────────────────────────────────────────┐ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: │ Connection: "sqlite" │ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: │ Driver: "sqlite" │ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: │ Database: "/opt/project/database/adapt-test-storage/databases/testing.fc1a39-b166cdd8bfb6.sqlite" │ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: └─────────────────────────────────────────────────────────────────────────────────────────────────────┘ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.DEBUG: ADAPT: Changed the database for connection "sqlite" to "/opt/project/database/adapt-test-storage/databases/testing.fc1a39-b166cdd8bfb6.sqlite" {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.ERROR: ADAPT: ┌── An Exception Occurred - ErrorException ────────────────────────────────────────────────────────────────────────┐ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.ERROR: ADAPT: │ Attempt to read property "project_name" on array │ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.ERROR: ADAPT: │ /opt/project/vendor/code-distortion/adapt/src/Adapters/AbstractClasses/AbstractReuseMetaDataTable.php on line 66 │ {"request_id":"dJoFMqf5HvNb1pY8"}
[2022-10-20 09:44:30] testing.ERROR: ADAPT: └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
{"request_id":"dJoFMqf5HvNb1pY8"}
Hi, I found your article about fast database tests and then this package, pgsql driver is in your plans?
Just a general question rather than an issue, does adapt support the following?
./vendor/bin/phpunit --repeat=3
When I run the test command the logs are showing the expected log, but only once.
Either our setup/createsApplication
[2023-01-10 21:29:09] testing.DEBUG: ADAPT: ┌── ADAPT (v0.12.2) ─────────────────────────────────────────────────────────────────────────────────────────────────────┐
[2023-01-10 21:29:09] testing.DEBUG: ADAPT: │ Preparing a database for connection "testing-connection"
[2023-01-10 21:29:09] testing.DEBUG: ADAPT: │ For test "test-folder::testItDoesSomething"
[2023-01-10 21:29:09] testing.DEBUG: ADAPT: └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
etc
Then I get an error saying a table (that we try to seed into) doesn't exist.
This seeding is not actually done through config and a seeder but instead in setup.
I'll have some time to debug and step through this properly next week.
When running the command
php artisan adapt:clear --force
CodeDistortion\Adapt\Exceptions\AdaptBootException
The Database name "" is invalid
at vendor/code-distortion/adapt/src/Exceptions/AdaptBootException.php:58
54▕ * @return self
55▕ */
56▕ public static function databaseNameIsInvalid($database): self
57▕ {
➜ 58▕ return new self("The Database name \"$database\" is invalid");
59▕ }
60▕ }
61▕
+19 vendor frames
20 artisan:37
Illuminate\Foundation\Console\Kernel::handle()```
#### Other Relevant Details:
- Using SSD or HDD storage? (might be relevant for slowness issues):
It's hard to recreate reliably but it happens a lot.
It feels like the first time I run a test CLASS when I haven't run one for a few minutes in PHPSTORM it fails with this error, subsequent runs are fine if I run them back to back.
Same can happen with test methods, run a test class, switch to another class and run a specific test and it can fail in the same way...running it immediately afterwards will always pass.
CodeDistortion\Adapt\Exceptions\AdaptConfigException : The .env.testing file could not be loaded
/opt/project/vendor/code-distortion/adapt/src/Exceptions/AdaptConfigException.php:20
/opt/project/vendor/code-distortion/adapt/src/Boot/BootTestLaravel.php:68
/opt/project/vendor/code-distortion/adapt/src/Boot/BootTestLaravel.php:52
/opt/project/vendor/code-distortion/adapt/src/Boot/BootTestAbstract.php:175
/opt/project/vendor/code-distortion/adapt/src/PreBoot/PreBootTestLaravel.php:114
/opt/project/vendor/code-distortion/adapt/src/Initialise/InitialiseAdapt.php:194
/opt/project/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestCase.php:94
2022-12-30 17:11:57] testing.DEBUG: ADAPT: Disconnecting established database connection "testing"
[2022-12-30 17:11:57] testing.ERROR: ADAPT: ┌── An Exception Occurred - AdaptConfigException ──────────────────────────────────────────────┐
[2022-12-30 17:11:57] testing.ERROR: ADAPT: │ The .env.testing file could not be loaded │
[2022-12-30 17:11:57] testing.ERROR: ADAPT: │ /opt/project/vendor/code-distortion/adapt/src/Exceptions/AdaptConfigException.php on line 20 │
[2022-12-30 17:11:57] testing.ERROR: ADAPT: └──────────────────────────────────────────────────────────────────────────────────────────────┘
[2022-12-30 17:13:00] testing.DEBUG: ADAPT: Disconnecting established database connection "testing"
[2022-12-30 17:13:00] testing.DEBUG: ADAPT: Changed the default connection to: "testing-mysql"
[2022-12-30 17:13:00] testing.DEBUG: ADAPT: Looking for stale things to remove
[2022-12-30 17:13:00] testing.DEBUG: ADAPT: Generated a build-source checksum based on file modified timestamps (6ms)
[2022-12-30 17:13:00] testing.DEBUG: ADAPT: Retrieved database list (connection: "testing-mysql", driver: "mysql") (2ms)
[2022-12-30 17:13:00] testing.DEBUG: ADAPT: - Found database "our-project" (not usable - ignoring) (1ms)
[2022-12-30 17:13:00] testing.DEBUG: ADAPT: - Found database "our-project_integration_2877d4_25f5c604d394" (stale - within grace period) (1ms)
[2022-12-30 17:13:00] testing.DEBUG: ADAPT: - Found database "our-project_integration_2877d4_26890819d052" (stale - within grace period) (1ms)
[2022-12-30 17:13:00] testing.DEBUG: ADAPT: - Found database "our-project_integration_2877d4_88a76f25ae61" (stale - within grace period) (1ms)
[2022-12-30 17:13:00] testing.DEBUG: ADAPT: - Found database "our-project_integration_53cfcf_26890819d052" (usable) (1ms)
[2022-12-30 17:13:00] testing.DEBUG: ADAPT: - Found database "our-project_integration_7a1beb_26890819d052" (stale - within grace period) (1ms)
[2022-12-30 17:13:00] testing.DEBUG: ADAPT: - Found database "our-project_integration_ddfa27_26890819d052" (stale - within grace period) (1ms)
[2022-12-30 17:13:00] testing.DEBUG: ADAPT: Retrieved snapshot list (0ms)
[2022-12-30 17:13:00] testing.DEBUG: ADAPT: - Found snapshot "/opt/project/database/adapt-test-storage/snapshots/snapshot.our-project-integration.2877d4-0c919462cf02.mysql" (stale - within grace period) (0ms)
[2022-12-30 17:13:00] testing.DEBUG: ADAPT: Nothing found to remove - total time taken (17ms)
[docker://kind.local/php-dev-baked:create/]:php /opt/project/vendor/phpunit/phpunit/phpunit --configuration /opt/project/phpunit.xml --filter "/(OurProject\\Tests\\Integration\\TestClass::testFunction)( .*)?$/" --test-suffix TestClass.php /opt/project/tests/integration --teamcity
.env.testing
file always existsA 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.