ably / ably-php Goto Github PK
View Code? Open in Web Editor NEWPHP client library SDK for Ably realtime messaging service
Home Page: https://ably.com/download
License: Apache License 2.0
PHP client library SDK for Ably realtime messaging service
Home Page: https://ably.com/download
License: Apache License 2.0
Hi,
Recently we keep facing this timeout error. Any guide what is the causes and how we can prevent this?
Laravel Framework version 5.2.45
ably/ably-php-laravel": "^1.0"
Laravel Log:
local.ERROR: exception 'Ably\Exceptions\AblyRequestException' with message 'cURL error: Operation timed out after 10001 milliseconds with 0 out of -1 bytes received' in /var/www/html/www-data/animategame/vendor/ably/ably-php/src/Http.php:150
Stack trace:
#0 /var/www/html/www-data/animategame/vendor/ably/ably-php/src/AblyRest.php(224): Ably\Http->request('POST', 'https://e.ably-...', Array, '{"data":"{\"upd...')
#1 /var/www/html/www-data/animategame/vendor/ably/ably-php/src/AblyRest.php(229): Ably\AblyRest->requestWithFallback('POST', '/channels/unive...', Array, '{"data":"{\"upd...', 3)
#2 /var/www/html/www-data/animategame/vendor/ably/ably-php/src/AblyRest.php(229): Ably\AblyRest->requestWithFallback('POST', '/channels/unive...', Array, '{"data":"{\"upd...', 2)
#3 /var/www/html/www-data/animategame/vendor/ably/ably-php/src/AblyRest.php(229): Ably\AblyRest->requestWithFallback('POST', '/channels/unive...', Array, '{"data":"{\"upd...', 1)
#4 /var/www/html/www-data/animategame/vendor/ably/ably-php/src/AblyRest.php(143): Ably\AblyRest->requestWithFallback('POST', '/channels/unive...', Array, '{"data":"{\"upd...')
#5 /var/www/html/www-data/animategame/vendor/ably/ably-php/src/AblyRest.php(114): Ably\AblyRest->requestInternal('POST', '/channels/unive...', Array, '{"data":"{\"upd...', false, true)
#6 /var/www/html/www-data/animategame/vendor/ably/ably-php/src/Channel.php(104): Ably\AblyRest->post('/channels/unive...', Array, '{"data":"{\"upd...')
#7 /var/www/html/www-data/animategame/app/Http/Controllers/Admin/GameController.php(794): Ably\Channel->publish('update-market', Array)
#8 /var/www/html/www-data/animategame/vendor/laravel/framework/src/Illuminate/Database/Connection.php(543): App\Http\Controllers\Admin\GameController->App\Http\Controllers\Admin{closure}(Object(Illuminate\Database\MySqlConnection))
#9 [internal function]: Illuminate\Database\Connection->transaction(Object(Closure))
#10 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(11804): call_user_func_array(Array, Array)
#11 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(6325): Illuminate\Database\DatabaseManager->__call('transaction', Array)
#12 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(6325): Illuminate\Database\DatabaseManager->transaction(Object(Closure))
#13 /var/www/html/www-data/animategame/app/Http/Controllers/Admin/GameController.php(800): Illuminate\Support\Facades\Facade::__callStatic('transaction', Array)
#14 /var/www/html/www-data/animategame/app/Http/Controllers/Admin/GameController.php(800): Illuminate\Support\Facades\DB::transaction(Object(Closure))
#15 [internal function]: App\Http\Controllers\Admin\GameController->ajaxUpdateUniversalAllManualOddMatch()
#16 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(9424): call_user_func_array(Array, Array)
#17 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(9486): Illuminate\Routing\Controller->callAction('ajaxUpdateUnive...', Array)
#18 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(9466): Illuminate\Routing\ControllerDispatcher->call(Object(App\Http\Controllers\Admin\GameController), Object(Illuminate\Routing\Route), 'ajaxUpdateUnive...')
#19 [internal function]: Illuminate\Routing\ControllerDispatcher->Illuminate\Routing{closure}(Object(Illuminate\Http\Request))
#20 /var/www/html/www-data/animategame/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(52): call_user_func(Object(Closure), Object(Illuminate\Http\Request))
#21 [internal function]: Illuminate\Routing\Pipeline->Illuminate\Routing{closure}(Object(Illuminate\Http\Request))
#22 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(9948): call_user_func(Object(Closure), Object(Illuminate\Http\Request))
#23 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(9467): Illuminate\Pipeline\Pipeline->then(Object(Closure))
#24 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(9454): Illuminate\Routing\ControllerDispatcher->callWithinStack(Object(App\Http\Controllers\Admin\GameController), Object(Illuminate\Routing\Route), Object(Illuminate\Http\Request), 'ajaxUpdateUnive...')
#25 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(8524): Illuminate\Routing\ControllerDispatcher->dispatch(Object(Illuminate\Routing\Route), Object(Illuminate\Http\Request), 'App\Http\Contro...', 'ajaxUpdateUnive...')
#26 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(8511): Illuminate\Routing\Route->runController(Object(Illuminate\Http\Request))
#27 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(8225): Illuminate\Routing\Route->run(Object(Illuminate\Http\Request))
#28 [internal function]: Illuminate\Routing\Router->Illuminate\Routing{closure}(Object(Illuminate\Http\Request))
#29 /var/www/html/www-data/animategame/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(52): call_user_func(Object(Closure), Object(Illuminate\Http\Request))
#30 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(13474): Illuminate\Routing\Pipeline->Illuminate\Routing{closure}(Object(Illuminate\Http\Request))
#31 [internal function]: Illuminate\View\Middleware\ShareErrorsFromSession->handle(Object(Illuminate\Http\Request), Object(Closure))
#32 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(9963): call_user_func_array(Array, Array)
#33 [internal function]: Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))
#34 /var/www/html/www-data/animategame/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(32): call_user_func(Object(Closure), Object(Illuminate\Http\Request))
#35 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(11964): Illuminate\Routing\Pipeline->Illuminate\Routing{closure}(Object(Illuminate\Http\Request))
#36 [internal function]: Illuminate\Session\Middleware\StartSession->handle(Object(Illuminate\Http\Request), Object(Closure))
#37 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(9963): call_user_func_array(Array, Array)
#38 [internal function]: Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))
#39 /var/www/html/www-data/animategame/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(32): call_user_func(Object(Closure), Object(Illuminate\Http\Request))
#40 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(13213): Illuminate\Routing\Pipeline->Illuminate\Routing{closure}(Object(Illuminate\Http\Request))
#41 [internal function]: Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse->handle(Object(Illuminate\Http\Request), Object(Closure))
#42 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(9963): call_user_func_array(Array, Array)
#43 [internal function]: Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))
#44 /var/www/html/www-data/animategame/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(32): call_user_func(Object(Closure), Object(Illuminate\Http\Request))
#45 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(13150): Illuminate\Routing\Pipeline->Illuminate\Routing{closure}(Object(Illuminate\Http\Request))
#46 [internal function]: Illuminate\Cookie\Middleware\EncryptCookies->handle(Object(Illuminate\Http\Request), Object(Closure))
#47 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(9963): call_user_func_array(Array, Array)
#48 [internal function]: Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))
#49 /var/www/html/www-data/animategame/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(32): call_user_func(Object(Closure), Object(Illuminate\Http\Request))
#50 [internal function]: Illuminate\Routing\Pipeline->Illuminate\Routing{closure}(Object(Illuminate\Http\Request))
#51 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(9948): call_user_func(Object(Closure), Object(Illuminate\Http\Request))
#52 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(8226): Illuminate\Pipeline\Pipeline->then(Object(Closure))
#53 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(8217): Illuminate\Routing\Router->runRouteWithinStack(Object(Illuminate\Routing\Route), Object(Illuminate\Http\Request))
#54 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(8207): Illuminate\Routing\Router->dispatchToRoute(Object(Illuminate\Http\Request))
#55 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(2419): Illuminate\Routing\Router->dispatch(Object(Illuminate\Http\Request))
#56 [internal function]: Illuminate\Foundation\Http\Kernel->Illuminate\Foundation\Http{closure}(Object(Illuminate\Http\Request))
#57 /var/www/html/www-data/animategame/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(52): call_user_func(Object(Closure), Object(Illuminate\Http\Request))
#58 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(3286): Illuminate\Routing\Pipeline->Illuminate\Routing{closure}(Object(Illuminate\Http\Request))
#59 [internal function]: Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode->handle(Object(Illuminate\Http\Request), Object(Closure))
#60 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(9963): call_user_func_array(Array, Array)
#61 [internal function]: Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))
#62 /var/www/html/www-data/animategame/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(32): call_user_func(Object(Closure), Object(Illuminate\Http\Request))
#63 [internal function]: Illuminate\Routing\Pipeline->Illuminate\Routing{closure}(Object(Illuminate\Http\Request))
#64 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(9948): call_user_func(Object(Closure), Object(Illuminate\Http\Request))
#65 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(2366): Illuminate\Pipeline\Pipeline->then(Object(Closure))
#66 /var/www/html/www-data/animategame/bootstrap/cache/compiled.php(2350): Illuminate\Foundation\Http\Kernel->sendRequestThroughRouter(Object(Illuminate\Http\Request))
#67 /var/www/html/www-data/animategame/public/index.php(54): Illuminate\Foundation\Http\Kernel->handle(Object(Illuminate\Http\Request))
#68 {main}
What
We need to create PHP Laravel code snippets for the ably homepage as outlined in https://ably.atlassian.net/browse/SDK-878 .
The PHP Laravel snippets needed are:
Please refer to the existing JavaScript snippets:
https://github.com/ably/homepage-snippets/tree/main/javascript
Acceptance criteria
A PR should be raised in the homepage-snippets repository: https://github.com/ably/homepage-snippets/pulls
I am aware that batch message sending is still a "beta" feature of the REST api, and am also aware that this library does current'y seem to support usage of batch mode when sending multiple messages to the same channel.
However it would be very useful if it provided a batch helper for sending different messages to different channels all within one Api call.
┆Issue is synchronized with this Jira Uncategorised by Unito
See RSA4b1
as part of 1.2 spec changes in https://github.com/ably/docs/pull/622/files
Given this impacts users now with significant clock skew, we aim to release a fix for this now.
┆Issue is synchronized with this Jira Story by Unito
We have identified a situation where a client library could, in theory, end in an endless loop of trying to reissue tokens and reattempt requests. We've addressed this now in the spec at ably/docs@b628023.
This library needs to be updated accordingly.
See ably/ably-js#235
See implementation in PHP at
ably-php/tests/ChannelMessagesTest.php
Line 112 in b0e70f2
It would be nice, for consistency, to offer an initialization for a channel that does not require the user to explicitly request the cipher param defaults.
See ably/docs#742 . This is for the same (enterprise) customer as the push work; relatively high-priority. Message me or Paddy in #client-libraries if you have any questions.
Trying to figure out how to get the Channel Meta data information using the SDK.
Here is the docs on ably https://www.ably.io/documentation/realtime/channel-metadata#occupancy.
┆Issue is synchronized with this Jira Story by Unito
@kouno the convention we have used for other libraries is to suffix the library with -rest
if it only supports REST functionality, see https://github.com/ably/ably-python-rest, https://github.com/ably/ably-ruby-rest. I think we should do the same here.
WDYT?
@bladeSk as you have added PHP 7 support, I think it's important that our test suite runs against multiple versions. If you look at https://github.com/ably/ably-php/blob/master/.travis.yml#L3, you will see we only support 5.4 now. Should we not run the test suite against all support PHP versions to make sure we don't introduce regressions in future?
@kouno see https://travis-ci.org/ably/ably-php
Can you fix the error so that this library is passing again?
A few small changes have been made to the 0.8 spec and should be reflected in this API.
See ably/docs@ed2e16b for example. A quick review of changes to the spec should be done to ensure this client library is still up to date.
link to the check in question.
As per RSL1m4 this should instead result in the message being rejected by the server.
┆Issue is synchronized with this Jira Story by Unito
See spec at ably/docs#473
Ruby implementation at ably/ably-ruby#165
Whilst this is technically 1.1 functionality, we can add this now so long as idempotent publishing is disabled by default.
A recent discovery in the iOS library has unearthed a small shortcoming in the spec, corrected at ably/docs@f768f0d
See unified spec, lines 554 and 568
@bladeSk, we have a few minor final changes to the spec to resolve some unaddressed points and reduce ambiguity in the spec.
See https://docs.google.com/spreadsheets/d/1bG_SEVlCi3blQBveGtsncxFGD4ArCtS-JCq6iLW3lGw/edit#gid=2047058158&vpid=B4 for the list of changes, which includes references to all spec items that have changed.
Can you please go through all of those and ensure all items in the unified spec are covered by your tests and documented in the unified spec doc?
@bladeSk, please review ably/docs#96 and add any comments if you notice any issues.
Also, this branch will now be deployed to http://docs.ably.io/rest/ so you can review how the Textile is rendered in place.
See ably/docs#554
We need to add this functionality to all client libraries, but prioritise the server-side ones given they are more affected if a single DC is offline and they are publishing at a high rate.
Simply need to bump the version to 1.0
A customer recently suggested we look at https://github.com/coderstephen/slack-client as they have build a realtime library in PHP using React. Perhaps one to consider if demand increases for a realtime PHP lib
┆Issue is synchronized with this Jira Story by Unito
see PR and spec point for context.
┆Issue is synchronized with this Jira Story by Unito
In TokenRequest
class, $timestamp
field is marked as integer
in PHPDoc but is set a string in
Line 309 in 7271326
When I serialize the whole thing and send it to my client app in Flutter, it breaks trying to cast it to int
here:
https://github.com/ably/ably-flutter/blob/e6a55d0e6691c32e049486a9abee8d0f766dbddd/lib/src/spec/common.dart#L361
Either you should make one type in both places, or in Flutter there must be parsing instead of casting.
┆Issue is synchronized with this Jira Uncategorised by Unito
https://app.intercom.io/a/apps/ua39m1ld/respond/inbox/all/conversations/10861930672
Not sure if this is a bug in ably-php, ably-js, or somewhere inbetween. Can't really see how it could be any of them, to be honest, there doesn't seem room for anything to go wrong in any of the stages that I can see. But it must be going wrong somewhere.
Customer creating token request in php with
$token = $this->ably->auth->createTokenRequest([
'ttl' => 86400000,
'capability'=> [ $channel => $capabilities],
'clientId' => 'customer-'.$user->getId()
]);
By the time it gets to ably-js, it looks like:
{"ttl":null,"capability":"{\"redacted:*\":[\"subscribe\",\"history\"]}","clientId":"customer-38","timestamp":"1500420264269","keyName":"<redacted>","nonce":"6b8c0f7b37bf2d100fa210204f8d80ad","mac":"oAsynffIX9glVWpJcmNlDpgvZx9dMCNF3dctiLk1VGM="}
With the ttl being null. This results in the mac being incorrect, as the ttl was 86400000 at the time the mac was signed -- which I've confirmed by getting the mac to match if I force it to be that manually.
See https://github.com/ably/ably-ruby/blob/master/README.md for an example of a common format used for the client library README. The README must include examples of using the most common features.
We must also include:
Please can we make sure that:
cc @bladeSk
See #32
This is common and leaves people struggling. We should catch this error and point them to the issue and steps to correct, see https://support.ably.io/solution/articles/3000052806-ssl-certificate-issues-communicating-with-ably-
Per RSC15g
, introduced in ably/docs#965.
See ably/ably-js#682 and ably/ably-ruby#196 for reference implementations.
A customer, when using the following auth code, gets "Request mac does not match"
$subscriberClient = new \Ably\AblyRest(array(
'key' => $this->subscribeApiKey
));
$tokenDetails = $subscriberClient->auth->requestToken(array(), array(
'queryTime' => false
));
However, when changing queryTime
to true, the error goes away.
$subscriberClient = new \Ably\AblyRest(array(
'key' => $this->subscribeApiKey
));
$tokenDetails = $subscriberClient->auth->requestToken(array(), array(
'queryTime' => true
));
I checked with the customer, and it seems their local time was within at most a second of the actual time, so I suspect this could be a timezone issue. They are in France, so GMT +1.
I asked them to do the following:
In one console, do:
php -a
echo microtime(true);
and then in another window, at around the same time! do the following:
$ curl rest.ably.io/time
What is the difference in values ignoring the part of the decimalCustomer:
PHP : 1455545827.01
CURL : 1455545827562
@bladeSk see ably/docs#140.
I think supporting this is a very small change which we can probably support without any explicit tests as the only way to test it would be to spawn a realtime client, something we can't do in the PHP only lib. Perhaps you could have a negative test that populates connectionKey
with an invalid value and the message should be rejected. At least then you're getting feedback that the property is being sent.
See ably/docs#276
Per https://docs.ably.io/client-lib-development-guide/features/#RSL6a2
a Message can have extras: { push: { ... }} when published, but the library just silently discards it right now.
They are defined as methods in PHP, yet they are actually defined as attributes in the docs just like items
for PaginatedResult.
Depends on msgpack/msgpack-php#36 and msgpack/msgpack-php#49
┆Issue is synchronized with this Jira Story by Unito
Before our stable release, we agreed to make a few final amends to our client library APIs to improve consistency and reduce ambiguity.
The token related changes are breaking changes, so we need these changes to be rolled out for this client library ASAP as we intend on migrating to the new API early next week. This means that this library will no longer be able to use Token auth when this change is rolled out.
While CI is green now I still get many errors locally:
There were 6 errors:
1) tests\AppStatsTest::testAppstatsPagination0
Trying to get property 'items' of non-object
/home/jdavid/sandboxes/Ably/ably-php/tests/AppStatsTest.php:247
2) tests\AppStatsTest::testAppstatsPagination1
Trying to get property 'items' of non-object
/home/jdavid/sandboxes/Ably/ably-php/tests/AppStatsTest.php:273
3) tests\AppStatsTest::testAppstatsPagination2
Trying to get property 'items' of non-object
/home/jdavid/sandboxes/Ably/ably-php/tests/AppStatsTest.php:299
4) tests\AppStatsTest::testAppstatsPagination3
Trying to get property 'items' of non-object
/home/jdavid/sandboxes/Ably/ably-php/tests/AppStatsTest.php:322
5) tests\PresenceTest::testComparePresenceDataWithFixture
Trying to get property 'items' of non-object
/home/jdavid/sandboxes/Ably/ably-php/tests/PresenceTest.php:80
6) tests\PresenceTest::testComparePresenceHistoryWithFixture
Trying to get property 'items' of non-object
/home/jdavid/sandboxes/Ably/ably-php/tests/PresenceTest.php:116
┆Issue is synchronized with this Jira Uncategorised by Unito
Pretty important for inter-operability.
See https://ably.io/documentation/rest/encryption and the encoding field in the message structure.
Hi,
We are using Ably to maintain the state of our APIs, mainly built using Ruby on Rails. Your Ruby SDK (https://github.com/ably/ably-ruby#subscribing-to-a-channel) allows us to subscribe from the server like this using Ably::Realtime.new
:
Thread.new do
EventMachine.run do
channel = ABLY_REALTIME.channels.get('identity')
channel.subscribe('updateUser') do |msg|
# code
end
end
end
However, we can't seems to be able to find the same feature for the PHP SDK. Is there any particular reason why it is not implemented ? Is there a workaround ? One of our API is built in PHP and we are struggling syncing it with the rest of our stack.
Thanks for reading this.
We've had a report from a customer that when publishing, they'll sometimes see Ably\Exceptions\AblyRequestException cURL error: SSL connection timeout
and try to use the fallback host.
Seeing questions like http://stackoverflow.com/questions/37854005/laravel-event-broadcast-not-work-with-pusher, I can see that deeper integration with a framework such as Laravel would be advantageous.
We should consider this.
The AuthOptions
and TokenParams
arguments are switched.
A number of customers have reported certificate errors in Windows environments. This is caused by the root certificates on the local machine being out of date. This is similar to problems we've seen in our Ruby client, see ably/ably-ruby#87.
The resolution to this problem is to update your local root certificates to the latest. Follow these instructions:
1 Download the following pem file: http://curl.haxx.se/ca/cacert.pem
2 Copy this file to either c:\cert\cacert.pem (Windows) or any other path on your Unix/ Linux / Mac installation
3 Open php.ini file in your favorite editor
If the following configuration string: curl.cainfo exists in your php.ini, please uncomment it by removing ";" and modify the path in order to point it to the cacert.pem file attached to this e-mail, e.g:
;;;;;;;;;;;;;;;;;;;
; Module Settings ;
;;;;;;;;;;;;;;;;;;;
curl.cainfo=c:\cert\cacert.pem
See laravel-notification-channels/channels#6 (comment)
Looks like this functionality for Laravel has not yet been added so we should do it ourselves as a PR
See ably/docs#568
We must ensure that that idempotent is not yet enabled by default and requires the user to explicitly enable.
Related to #56
Do you have any plans to support PHP 8.0? I'm getting the following issue when I try to install this package via composer
ably/ably-php[1.1.0, ..., 1.1.3] require php ^5.6 || ^7.0 -> your php version (8.0.0) does not satisfy that requirement.
┆Issue is synchronized with this Jira Story by Unito
This will be hard to test sadly without mocking or sending requests to a non-realtime server, but we should do our best to confirm request support these verbs.
See ably/docs#493
@bladeSk, before we finish off, can you please do the following so that we can be confident everything is done:
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.