Git Product home page Git Product logo

azuregraph's Introduction

AzureGraph

CRAN Downloads R-CMD-check

A simple interface to the Microsoft Graph API. The companion package to AzureRMR and AzureAuth.

Microsoft Graph is a comprehensive framework for accessing data in various online Microsoft services. Currently, this package aims to provide an R interface only to the Azure Active Directory part, with a view to supporting interoperability of R and Azure: users, groups, registered apps and service principals. Like AzureRMR, it could potentially be extended to cover other services.

The primary repo for this package is at https://github.com/Azure/AzureGraph; please submit issues and PRs there. It is also mirrored at the Cloudyr org at https://github.com/cloudyr/AzureGraph. You can install the development version of the package with devtools::install_github("Azure/AzureGraph").

Authentication

The first time you authenticate with a given Azure Active Directory tenant, you call create_graph_login() and supply your credentials. R will prompt you for permission to create a special data directory in which to save the obtained authentication token and AD Graph login. Once this information is saved on your machine, it can be retrieved in subsequent R sessions with get_graph_login(). Your credentials will be automatically refreshed so you don't have to reauthenticate.

See the "Authentication basics" vignette for more details on how to authenticate with AzureGraph.

Sample workflow

AzureGraph currently includes methods for working with registered apps, service principals, users and groups. A call_graph_endpoint() method is also supplied for making arbitrary REST calls.

library(AzureGraph)

# authenticate with AAD
# - on first login, call create_graph_login()
# - on subsequent logins, call get_graph_login()
gr <- create_graph_login()

# list all users in this tenant
gr$list_users()

# list all app registrations
gr$list_apps()

# my user information
me <- gr$get_user("me")

# my groups
head(me$list_group_memberships())

# my registered apps
me$list_owned_objects(type="application")

# register a new app
# by default, this will have a randomly generated strong password with duration 2 years
app <- gr$create_app("AzureR_newapp")

# get the associated service principal
app$get_service_principal()

# using it in conjunction with AzureRMR RBAC
AzureRMR::get_azure_login()$
    get_subscription("sub_id")$
    get_resource_group("rgname")$
    add_role_assignment(app, "Contributor")

azuregraph's People

Contributors

eitsupi avatar gwd666 avatar hongooi73 avatar jonocarroll avatar microsoft-github-policy-service[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

azuregraph's Issues

Switch to 1.0 API

Once all app/service principal calls have been ported over from beta.

Handle 503 errors

When using the APIs, I am frequently running into 503s when I overwhelm the servers. In that case, there should be a Retry-After header asking me to delay and try again.

Can the library handle these errors automatically? Ideally there is a maximum delay one is willing to wait, so if service is down for longer than that, you get an error anyway.

Get user by email address

Thank you for providing an easy-to-use library.
I wanted to get the user information from the user's email address, so I ran the code like this.

library(AzureGraph)
gr <- create_graph_login()
usr <- gr$get_user("[email protected]")

However, it seems that only userPrincipalName can be used as an argument in gr$get_user() at the moment, and I couldn't get the user infomation with the user's email address.

Is there any other way to get user information from the email address?

Response using call_graph_url() is different from Graph Explorer

Hi, I'm trying to use Graph API to read One Drive Excel values, for that I'm using the AzureGraph library.

For this example, I'm trying to GET all the items in my drive.

Using the Graph Explorer I get a valid response, where the field "value" is not empty, and I can see my excel files.

image

However in R:

`login <- create_graph_login(tenant = "3e0289c2-e351-4c79-998b-8167c83a06d3", auth_type = "resource_owner", username = "[email protected]", password = "mypassword")

call_graph_endpoint(login$token, operation = "me/drive/root/children")`

This works and I get a 200 response, but the "value" filed is empty.

image

I don't know what is the difference or what I may be doing wrong.

Add app methods

  • list/add/remove permissions
  • list/add/remove OAuth id
  • grant admin consent

setting permission to something other than {read, write, owner}

Is there a way to assign a permission level to a drive item?

My main goal is to let users read, but not download, the documents in the folder.

image

library(Microsoft365R)

sp <- list_sharepoint_sites()

general_drive <- sp[[1]]$list_drives()[[2]]

general_drive$create_folder('test folder')

item <- general_drive$get_item('test folder')

my_body <- list(
  recipients = list(list(email= '[email protected]')),
  sendInvitation = FALSE,  
  requireSignIn = TRUE,  
  roles = list('read')
  )

item$do_operation(op = 'invite', http_verb = 'POST', body = my_body)

# status 200

perms <- item$do_operation(op = 'permissions')

item$do_operation(op = file.path('permissions',perms$value[[6]]$id),
                  http_verb = 'PATCH', 
                  body = list(roles = c('read','write')))

# status 200

item$do_operation(op = file.path('permissions',perms$value[[6]]$id),
                  http_verb = 'PATCH', 
                  body = list(roles = c('resticted view')))

#> Error in process_response(res, match.arg(http_status_handler), simplify) : 
#>   Bad Request (HTTP 400). Failed to complete operation. Message:
#> [permissionInformation] An unexpected 'PrimitiveValue' node was found when reading from the JSON reader. A
#> 'StartArray' node was expected.

item$do_operation(op = file.path('permissions',perms$value[[6]]$id),
                  http_verb = 'PATCH', 
                  body = list(roles = list('restricted view')))

#> Error in process_response(res, match.arg(http_status_handler), simplify) : 
#>   Bad Request (HTTP 400). Failed to complete operation. Message:
#> Invalid value for role.

If I do set it manually on the site and then query what it is using the API I get back an empty list

perms <- item$do_operation(op = 'permissions')
perms$value[[6]]
#> $id
#> [1] "aTowIy5mfG1lbWJlcnNoaXB8d2lsbGlhbS5oYXllc0BzYWdlcnguY29t"
#> 
#> $roles
#> list()

/me endpoint fails for externally added user

GET https://graph.microsoft.com/v1.0/me

Not Found (HTTP 404)
Resource 'c03ad8ca-598a-4119-b8ce-7e7e1bee9322' does not exist or one of its
queried reference-property objects are not present.

GET /users/{GUID} and GET /users/{email#EXT#@tenant.onmicrosoft.com} still work.

How to list drive items

Thanks for the great package. I'm trying to access OneDrive Files and programmatically download items, but I can't seem to get the endpoint down. I've been trying different combinations of drive/item endpoints as referenced here: https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_get?view=odsp-graph-online

library(AzureGraph)
library(glue)
token = readRDS("~/Desktop/token.rds")
gr = create_graph_login(token = token)
me = gr$get_user()

# this works fine
shared = me$do_operation("drive/sharedWithMe")
df = dplyr::bind_rows(sapply(shared$value, 
    as.data.frame, stringsAsFactors = FALSE))
print(dim(df))
#> [1]  8 49

iid = 1
idf = df[iid, ]

# this works fine
drive = me$do_operation("drive")
attr(drive, "status")
#> [1] 200
drive$quota
#> $deleted
#> [1] 0
#> 
#> $remaining
#> [1] 0
#> 
#> $total
#> [1] 0
#> 
#> $used
#> [1] 0

# this works fine
drive_id = idf$remoteItem.parentReference.driveId
item_id = idf$remoteItem.id

path = glue::glue("drives/{drive_id}/items/{item_id}")
try(me$do_operation(path))
#> Error in process_response(res, match.arg(http_status_handler)) : 
#>   Not Found (HTTP 404). Failed to complete operation. Message:
#> The resource could not be found.
try(gr$call_graph_endpoint(path))
#> Error in process_response(res, match.arg(http_status_handler)) : 
#>   Not Found (HTTP 404). Failed to complete operation. Message:
#> The resource could not be found.
path = glue::glue("/drives/{drive_id}/items/{item_id}")
try(me$do_operation(path))
#> Error in process_response(res, match.arg(http_status_handler)) : 
#>   Not Found (HTTP 404). Failed to complete operation. Message:
#> The resource could not be found.
try(gr$call_graph_endpoint(path))
#> Error in process_response(res, match.arg(http_status_handler)) : 
#>   Not Found (HTTP 404). Failed to complete operation. Message:
#> The resource could not be found.


drive_id = urltools::url_encode(drive_id)
item_id = urltools::url_encode(item_id)

path = glue::glue("drives/{drive_id}/items/{item_id}")
try(me$do_operation(path))
#> Error in process_response(res, match.arg(http_status_handler)) : 
#>   Not Found (HTTP 404). Failed to complete operation. Message:
#> The resource could not be found.
try(gr$call_graph_endpoint(path))
#> Error in process_response(res, match.arg(http_status_handler)) : 
#>   Not Found (HTTP 404). Failed to complete operation. Message:
#> The resource could not be found.
path = glue::glue("/drives/{drive_id}/items/{item_id}")
try(me$do_operation(path))
#> Error in process_response(res, match.arg(http_status_handler)) : 
#>   Not Found (HTTP 404). Failed to complete operation. Message:
#> The resource could not be found.
try(gr$call_graph_endpoint(path))
#> Error in process_response(res, match.arg(http_status_handler)) : 
#>   Not Found (HTTP 404). Failed to complete operation. Message:
#> The resource could not be found.

Created on 2020-03-30 by the reprex package (v0.3.0.9001)

Session info
sessioninfo::session_info()
#> ─ Session info ───────────────────────────────────────────────────────────────
#>  setting  value                       
#>  version  R version 3.6.3 (2020-02-29)
#>  os       macOS Mojave 10.14.6        
#>  system   x86_64, darwin15.6.0        
#>  ui       X11                         
#>  language (EN)                        
#>  collate  en_US.UTF-8                 
#>  ctype    en_US.UTF-8                 
#>  tz       America/New_York            
#>  date     2020-03-30                  
#> 
#> ─ Packages ───────────────────────────────────────────────────────────────────
#>  package     * version     date       lib source                             
#>  askpass       1.1         2019-01-13 [1] CRAN (R 3.6.0)                     
#>  assertthat    0.2.1       2019-03-21 [1] CRAN (R 3.6.0)                     
#>  AzureAuth     1.2.3       2019-11-12 [1] CRAN (R 3.6.0)                     
#>  AzureGraph  * 1.1.0       2019-11-08 [1] CRAN (R 3.6.0)                     
#>  backports     1.1.5       2019-10-02 [1] CRAN (R 3.6.0)                     
#>  cli           2.0.2       2020-02-28 [1] CRAN (R 3.6.0)                     
#>  crayon        1.3.4       2017-09-16 [1] CRAN (R 3.6.0)                     
#>  curl          4.3         2019-12-02 [1] CRAN (R 3.6.0)                     
#>  digest        0.6.25      2020-02-23 [1] CRAN (R 3.6.0)                     
#>  dplyr         0.8.99.9002 2020-03-24 [1] Github (tidyverse/dplyr@dd0ddbe)   
#>  evaluate      0.14        2019-05-28 [1] CRAN (R 3.6.0)                     
#>  fansi         0.4.1       2020-01-08 [1] CRAN (R 3.6.0)                     
#>  fs            1.3.2       2020-03-05 [1] CRAN (R 3.6.0)                     
#>  glue        * 1.3.2       2020-03-12 [1] CRAN (R 3.6.0)                     
#>  highr         0.8         2019-03-20 [1] CRAN (R 3.6.0)                     
#>  htmltools     0.4.0       2019-10-04 [1] CRAN (R 3.6.0)                     
#>  httr          1.4.1       2019-08-05 [1] CRAN (R 3.6.0)                     
#>  jsonlite      1.6.1       2020-02-02 [1] CRAN (R 3.6.0)                     
#>  knitr         1.28        2020-02-06 [1] CRAN (R 3.6.0)                     
#>  lifecycle     0.2.0       2020-03-06 [1] CRAN (R 3.6.0)                     
#>  magrittr      1.5         2014-11-22 [1] CRAN (R 3.6.0)                     
#>  openssl       1.4.1       2019-07-18 [1] CRAN (R 3.6.0)                     
#>  pillar        1.4.3       2019-12-20 [1] CRAN (R 3.6.0)                     
#>  pkgconfig     2.0.3       2019-09-22 [1] CRAN (R 3.6.0)                     
#>  purrr         0.3.3       2019-10-18 [1] CRAN (R 3.6.0)                     
#>  R6            2.4.1       2019-11-12 [1] CRAN (R 3.6.0)                     
#>  rappdirs      0.3.1       2016-03-28 [1] CRAN (R 3.6.0)                     
#>  Rcpp          1.0.4.5     2020-03-29 [1] Github (RcppCore/Rcpp@80a1d48)     
#>  reprex        0.3.0.9001  2020-01-05 [1] Github (tidyverse/reprex@5ae0b29)  
#>  rlang         0.4.5.9000  2020-03-24 [1] Github (r-lib/rlang@a90b04b)       
#>  rmarkdown     2.1         2020-01-20 [1] CRAN (R 3.6.0)                     
#>  rstudioapi    0.11.0-9000 2020-02-19 [1] Github (rstudio/rstudioapi@deb9c47)
#>  sessioninfo   1.1.1       2018-11-05 [1] CRAN (R 3.6.0)                     
#>  stringi       1.4.6       2020-02-17 [1] CRAN (R 3.6.0)                     
#>  stringr       1.4.0       2019-02-10 [1] CRAN (R 3.6.0)                     
#>  styler        1.3.2       2020-02-23 [1] CRAN (R 3.6.2)                     
#>  tibble        2.1.3       2019-06-06 [1] CRAN (R 3.6.0)                     
#>  tidyselect    1.0.0       2020-01-27 [1] CRAN (R 3.6.0)                     
#>  triebeard     0.3.0       2016-08-04 [1] CRAN (R 3.6.0)                     
#>  urltools      1.7.3       2019-04-14 [1] CRAN (R 3.6.0)                     
#>  vctrs         0.2.99.9010 2020-03-24 [1] Github (r-lib/vctrs@71aedcf)       
#>  withr         2.1.2       2018-03-15 [1] CRAN (R 3.6.0)                     
#>  xfun          0.12        2020-01-13 [1] CRAN (R 3.6.0)                     
#>  yaml          2.2.1       2020-02-01 [1] CRAN (R 3.6.0)                     
#> 
#> [1] /Library/Frameworks/R.framework/Versions/3.6/Resources/library

Access denied when trying to send email

Hello,

I'm trying to use your package to send emails from my outlook account. I have a created an app on Azure and given it the correct permission (at least I hope I did: send.mail). I now have the following code

library(AzureGraph)

gr <- get_graph_login()
myApp = gr$get_app("<token not shown>")

bodyJson = list(message = list(
  subject = "Hello from R",
  body=list(
    content="Hello from R",
    contentType="text"
  ),
  toRecipients=list(list(emailAddress = list(address = "[email protected]")))
), saveToSentItems = "false")

req <- graph_request$new("me/sendMail",
                         body=bodyJson,
                         http_verb="POST"
)

call_batch_endpoint(myApp$token, list(req), api_version="v1.0")

However, when I run this I get the following error

Error: Graph batch job encountered errors on requests 1
Messages:
Access is denied. Check credentials and try again.

Do you have any feedback on what I should do next?

Kind regards

Expose `op` to update custom metadata fields on items

I am trying to update some custom metadata of a sharepoint item (additional columns added, not just "name") with this package. I am able to achieve this via the mgc cli with e.g.

mgc sites lists items fields patch --list-id $listID --site-id $siteID --list-item-id 5 --body '{"metadataValue": "123"}'

With AzureGraph, following this workflow:

gr <- get_graph_login()
site <- gr$get_sharepoint_site(sp_url)
lists <- site$get_lists()[[1]]
item <- lists$get_item(5)
item$update("metadataValue" = "123")

the path that is constructed does not include the "fields" path. It appears that the op argument to do_operation() would be where this could/should be set, but this is not exposed to the outer update() function

AzureGraph/R/ms_object.R

Lines 81 to 86 in 983aaaa

update=function(...)
{
self$do_operation(body=list(...), encode="json", http_verb="PATCH")
self$properties <- self$do_operation()
self
},

...

AzureGraph/R/ms_object.R

Lines 113 to 117 in 983aaaa

do_operation=function(op="", ...)
{
op <- construct_path(private$api_type, self$properties$id, op)
call_graph_endpoint(self$token, op, ...)
},

Could this be modified to update(op="", ...) (or some other equivalent approach)? It is difficult to inject this since the class is R6, but my workaround for the moment is

field_update <- function(obj, ...) {
  obj$do_operation(op = "fields", body = list(...), encode = "json", http_verb = "PATCH")
}
field_update(item, "metadataValue" = "123")

Unable to pass custom headers to Graph endpoint

The call_graph_endpoint function does not support the addition of custom headers to the Graph API requests.

One particular use case where this would be helpful is when using the Graph API to work with OneDrive Excel, where the usage of Sessions can provide greater efficiency: https://docs.microsoft.com/en-us/graph/api/resources/excel?view=graph-rest-1.0#sessions-and-persistence

To use these Sessions, we would need to be able to include an additional field in the header called workbook-session-id. If the addition of a general custom header seems too broad, then at the very least the ability to include a Session ID in the request headers would solve this issue.

Setting item permission problem

I am trying to create a folder and set its permission using the documentation here

I am not sure why the values that i am passing into the body arguments are being ignored.

library(Microsoft365R)

sp <- list_sharepoint_sites()
#> Loading Microsoft Graph login for default tenant

general_drive <- sp[[1]]$list_drives()[[2]]

general_drive$create_folder('test folder')

item <- general_drive$get_item('test folder')

my_body <- list(
  recipients = list(list(email= '[email protected]')),
  SendInvitation = FALSE,  
  RequireSignIn = TRUE,  
  roles = list('read')
  )

my_body |>
  jsonlite::toJSON(pretty = TRUE, auto_unbox = TRUE, digits = 22, null = "null")
#> {
#>   "recipients": [
#>     {
#>       "email": "[email protected]"
#>     }
#>   ],
#>   "SendInvitation": false,
#>   "RequireSignIn": true,
#>   "roles": [
#>     "read"
#>   ]
#> }

item$do_operation(op = 'invite',
                  http_verb = 'PUT',
                  body = my_body)
#> Error in process_response(res, match.arg(http_status_handler), simplify): Bad Request (HTTP 400). Failed to complete operation. Message:
#> RequireSignIn and SendInvitation cannot both be false.

details::details(sessioninfo::session_info(), summary = 'si')
si
- Session info ---------------------------------------------------------------
 setting  value                       
 version  R version 4.1.0 (2021-05-18)
 os       Windows 10 x64              
 system   x86_64, mingw32             
 ui       RTerm                       
 language (EN)                        
 collate  English_United States.1252  
 ctype    English_United States.1252  
 tz       America/New_York            
 date     2022-07-02                  

- Packages -------------------------------------------------------------------
 ! package       * version date       lib source                              
 P assertthat      0.2.1   2019-03-21 [?] CRAN (R 4.1.0)                      
   AzureAuth       1.3.2   2021-05-19 [1] standard (@1.3.2)                   
   AzureGraph      1.3.1   2021-06-04 [1] standard (@1.3.1)                   
   backports       1.2.1   2020-12-09 [1] standard (@1.2.1)                   
 P cli             3.3.0   2022-04-25 [?] CRAN (R 4.1.0)                      
 P clipr           0.7.0   2019-07-23 [?] CRAN (R 4.1.0)                      
 P crayon          1.4.1   2021-02-08 [?] CRAN (R 4.1.0)                      
   curl            4.3.2   2021-06-23 [1] standard (@4.3.2)                   
 P desc            1.2.0   2018-05-01 [?] CRAN (R 4.1.0)                      
 P details         0.2.1   2020-01-12 [?] CRAN (R 4.1.0)                      
   digest          0.6.27  2020-10-24 [1] CRAN (R 4.1.0)                      
 P ellipsis        0.3.2   2021-04-29 [?] CRAN (R 4.1.0)                      
 P evaluate        0.14    2019-05-28 [?] CRAN (R 4.1.0)                      
   fansi           0.5.0   2021-05-25 [1] standard (@0.5.0)                   
 P fastmap         1.1.0   2021-01-25 [?] CRAN (R 4.1.0)                      
 P fs              1.5.0   2020-07-31 [?] CRAN (R 4.1.0)                      
 P glue            1.6.2   2022-02-24 [?] CRAN (R 4.1.2)                      
 P highr           0.8     2019-03-20 [?] CRAN (R 4.1.0)                      
 P htmltools       0.5.2   2021-08-25 [?] CRAN (R 4.1.2)                      
 P httr            1.4.2   2020-07-20 [?] CRAN (R 4.1.0)                      
   jsonlite        1.7.2   2020-12-09 [1] CRAN (R 4.1.0)                      
 P knitr           1.37    2021-12-16 [?] CRAN (R 4.1.2)                      
 P lifecycle       1.0.1   2021-09-24 [?] CRAN (R 4.1.2)                      
 P magrittr        2.0.1   2020-11-17 [?] standard (@2.0.1)                   
 P Microsoft365R * 2.3.3   2022-02-15 [?] Github (Azure/Microsoft365R@6f43ccc)
 P pillar          1.7.0   2022-02-01 [?] CRAN (R 4.1.2)                      
 P pkgconfig       2.0.3   2019-09-22 [?] CRAN (R 4.1.0)                      
 P png             0.1-7   2013-12-03 [?] CRAN (R 4.1.0)                      
 P purrr           0.3.4   2020-04-17 [?] CRAN (R 4.1.0)                      
   R.cache         0.15.0  2021-04-30 [1] standard (@0.15.0)                  
   R.methodsS3     1.8.1   2020-08-26 [1] standard (@1.8.1)                   
   R.oo            1.24.0  2020-08-26 [1] standard (@1.24.0)                  
   R.utils         2.10.1  2020-08-26 [1] standard (@2.10.1)                  
   R6              2.5.0   2020-10-28 [1] CRAN (R 4.1.0)                      
   rappdirs        0.3.3   2021-01-31 [1] standard (@0.3.3)                   
   reprex          2.0.0   2021-04-02 [1] standard (@2.0.0)                   
 P rlang           1.0.3   2022-06-27 [?] CRAN (R 4.1.0)                      
   rmarkdown       2.10    2021-08-06 [1] standard (@2.10)                    
 P rprojroot       1.3-2   2018-01-03 [?] CRAN (R 4.1.0)                      
 P rstudioapi      0.13    2020-11-12 [?] CRAN (R 4.1.0)                      
 P sessioninfo     1.1.1   2018-11-05 [?] CRAN (R 4.1.0)                      
 P stringi         1.4.6   2020-02-17 [?] CRAN (R 4.1.0)                      
 P stringr         1.4.0   2019-02-10 [?] CRAN (R 4.1.0)                      
 P styler          1.6.2   2021-09-23 [?] CRAN (R 4.1.1)                      
 P tibble          3.1.7   2022-05-03 [?] CRAN (R 4.1.3)                      
 P utf8            1.2.1   2021-03-12 [?] CRAN (R 4.1.0)                      
 P vctrs           0.4.1   2022-04-13 [?] CRAN (R 4.1.3)                      
 P withr           2.4.3   2021-11-30 [?] CRAN (R 4.1.2)                      
 P xfun            0.29    2021-12-14 [?] CRAN (R 4.1.2)                      
   xml2            1.3.2   2020-04-23 [1] CRAN (R 4.1.0)                      
 P yaml            2.2.1   2020-02-01 [?] CRAN (R 4.1.0)                      

[1] C:/trials/217-cross-study/renv/library/R-4.1/x86_64-w64-mingw32
[2] C:/Program Files/R/R-4.1.0/library

 P -- Loaded and on-disk path mismatch.

Created on 2022-07-02 by the reprex package (v2.0.0)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.