Code Monkey home page Code Monkey logo

mdm-ui's Introduction

mdm-ui

Web front-end for the Mauro Data Mapper

Build status

Branch Build Status
main Build Status
develop Build Status

Requirements

Please use NVM to manage the required node dependencies, and then run npm i -g [email protected] to update to v7 of npm

Installation

  1. Clone the mdm-ui repo
  2. Install NVM environment
  3. Install Angular CLI
  4. Install all dependencies
# Clone repo
$ git clone [email protected]:MauroDataMapper/mdm-ui.git

# Install the NVM environment
# This will use the `.nvmrc` file to install the node versions we need and update to the latest version of npm
$ nvm install --latest-npm

# Install Angular CLI globally
$ npm install -g @angular/cli

# Install the code dependencies
$ npm install

Development & Testing

Run the application

  • To start the application in development mode run ng serve
  • After the terminal finishes compiling, open up your browser and navigate to http://localhost:4200

Testing the application

  • To test the application run npm test

All pushes to the repository will invoke a Jenkins CI build. When Jenkins runs the builds it uses npm ci which uses the package-lock.json to determine dependencies, this is done to ensure the "Jenkins tested build" uses what will be used when we release.

Therefore if you change any dependency versions you must make sure the package-lock file is also updated

MDM-Resources

We have a dependency on another repository (mdm-resources) which we develop.

The package.json file is configured to use the latest release of this module into the NPM registry, however if you are developing mdm-resources alongside mdm-ui or you know there are changes which have not yet been released you will need to do the following

  1. Clone the mdm-resources repository
  2. Link the mdm-resources repository into your global npm
  3. Link mdm-resources into mdm-ui

Once you have linked the mdm-resources repo into the global npm it will remain there until you unlink it, you will have to re-build (npm run build) mdm-resources with each change for those changes to be picked up by mdm-ui, however you dont have to re-link after the rebuild.

Linking to mdm-resources

If you run npm install inside mdm-ui you will have to re-run the final link step below to re-link mdm-resources into mdm-ui.

# Clone mdm-resources
$ git clone [email protected]:MauroDataMapper/mdm-resources.git

# Link mdm-resources to global npm
$ cd mdm-resources
$ npm install
$ npm run build
$ npm link

# Link mdm-resources into mdm-ui
$ cd mdm-ui
$ npm link @maurodatamapper/mdm-resources

Unlinking from mdm-resources

This is surprisingly simple just run npm install or npm ci

Useful Tool for Links

There is a useful npm package (symlinked) which can list what modules are linked into your repository. This is helpful if you want to check if mdm-resources is currently linked to mdm-ui. We recommend installing this globally with npm i -g symlinked then you can call it inside mdm-ui using symlinked names.

Build the application

To 'export' the code for production, run ng build --prod this will compile & minify the code, making it ready for production

mdm-ui's People

Contributors

pjmonks avatar jamesrwelch avatar atpw25 avatar olliefreeman avatar ansh1980 avatar obutlerocc avatar joe-crawford avatar aaronforshaw avatar gbishop-phsa avatar abwilson23 avatar dependabot[bot] avatar cristiangimenez avatar renovate[bot] avatar adjl avatar nigelpalmer avatar jon-bowen avatar ignatg avatar mhocc avatar renovate-bot avatar aysheylmz avatar

Stargazers

Rihards Mantejs avatar  avatar Chris Hills avatar Jelena Dreskai avatar  avatar Peter Hicks avatar  avatar

Watchers

James Cloos avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar Chris Martin avatar  avatar Jelena Dreskai avatar  avatar

mdm-ui's Issues

Ensure consistency with "Log in" and "Log out" buttons

Describe the bug
End to end tests can fail on development instance because of inconsistency between buttons for logging in and out.

To Reproduce

  1. Setup UI to run as: npm run start -- --post 8082
  2. In the mdm-end-to-end-testing repo:
    1. Run npm run webdriver-start to start the Selenium web driver
    2. Run in another process npm run build then npm run test to start the e2e tests.

Expected behavior
All tests should pass with a fully green report.

Additional context
The issue is because the test steps are searching for a "Log in" button on the modal form to submit, when the actual text is "Login".

This should be fixed in the UI as follows:

  1. Ensure all buttons for logging in are labelled "Log in", matching casing and the included space.
  2. Ensure all buttons for logging out are labelled "Log out", matching casing and the included space.

404 Not found after import

Describe the bug
After importing a data model, I get a 404 not found when the UI tries to redirect to the imported model

To Reproduce
Steps to reproduce the behavior:
Import a model using JSON importer (also same result with CSV importer). See attached file. After import, 404.

Expected behavior
Redirect to imported model

Screenshots

Desktop (please complete the following information):
Mac OS, Safari

Additional context
Latest Develop branches of core and ui

DataTypes arent refreshed after a DataClass removal

Describe the bug
There is a ReferenceType DataType which points to a DataClass.
When that DC is deleted the RT is as well, however the UI still shows the RT existing until you click on it and get an error.

To Reproduce
Steps to reproduce the behavior:

  1. Create or copy a DC with a RT (complex model -> parent DC) to another model
  2. There will be an addtl DT in the types page
  3. Delete the parent DC you copied
  4. The DC is gone from schemes but the DT still shows

Expected behavior
DTs need to be refreshed after a DC deletion.

In the same light, deleting a DT will delete all DEs which it is used for, therefore we should refresh the scheme page as well

Consolidate and simplify element access properties for catalogue items

Issue

The SecurityHandlerService.elementAccess() method returns different objects depending on the domain type of the catalogue. However, this poses some long-term issues:

  1. How do we know what access properties are available to the object returned? Currently, these must be inspected from the SecurityHandlerService code.
  2. What if more domain types are added?

Suggestion

The SecurityHandlerService is passed a catalogue item which should, at the very least, have the same properties/traits as a Securable type. So it would make more sense to:

  1. Define one CatalogueItemAccess type with all the boolean properties related to access permissions, e.g. showEdit, canDelete etc
  2. Change SecurityHandlerService.elementAccess() to flatten Securable.availableActions array to these access flags in one go.

If a domain type does not require all the access flag, then these would simply resolve to false and can be ignored. This means multiple functions are no longer needed to define what actions can be performed.

no error issue in details when an error occurs

Describe the bug
When branching a model, that took more then 30 mins, I received a server error. Used inspector to see timeout error, however there was no information in the details grid view.
'''Request
PUT /mauro-data-mapper/api/dataModels/73d373d5-8223-4fd0-86cb-e9a9acc8844b/newBranchModelVersion HTTP/1.1
Content-Type: application/json
Pragma: no-cache
Accept: application/json, text/plain, /
Accept-Language: en-gb
Accept-Encoding: gzip, deflate, br
Cache-Control: no-cache
Host: oxnetdwa02.oxnet.nhs.uk
Origin: https://oxnetdwa02.oxnet.nhs.uk
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Safari/605.1.15
Referer: https://oxnetdwa02.oxnet.nhs.uk/mauro-data-mapper/
Content-Length: 30
Connection: keep-alive
Cookie: JSESSIONID=D924061337AF0D22E109CD931200B6CB; _ga=GA1.3.721931879.1620143590; _gid=GA1.3.1515164793.1620143590
Response
HTTP/1.1 504 Gateway Time-out
Date: Wed, 05 May 2021 10:15:29 GMT
Content-Type: text/html
Connection: keep-alive
Cache-Control: no-store, no-cache, must-revalidate
Content-Length: 192
Server: nginx/1.14.0 (Ubuntu)'''
Screenshot 2021-05-05 at 11 29 35

To Reproduce
Steps to reproduce the behavior:
Go to 'OUH instance'
Branch a large model - wait for it to receive a server error - open details, see that there is nothing there

Desktop (please complete the following information):

OS: Mac OS 11.3.1
Browser Safari
Version 14.1
Additional context
I've only tried this in the OUH instance, will test others when I get a chance.

multiple Main versions/Documentation versions being overwritten

Describe the bug
When viewing the tree there are muliple Main versions, where they have been branched as a documentation version or the like. This is causing confusion when branching the models finalised models. this is in the CDW instance of MDM, there are two of the "same" models in the tree, but 4 'main' branches listed in the dropdown.

In looking at the code, one of the 'main' versions is a documentation version but has been over written? Talked to @olliefreeman about it this afternoon.

To Reproduce
Steps to reproduce the behavior:

  1. Go to OUH instance, search for modules, view drop down, open inspector to see differences.

Expected behavior
I would expect their to be 1 main model and the branches that come off that finalised version, one of which being documentation. In addition in the dropdown I would either see only thoe visible in the tree or those that have been superseded marked as such.

Screenshots
Screenshot 2021-05-05 at 16 11 43

    "domainType": "DataModel",
    "label": "modules",
    "availableActions": [
        "show",
        "createNewVersions",
        "newForkModel",
        "comment",
        "newModelVersion",
        "newDocumentationVersion",
        "newBranchModelVersion",
        "softDelete",
        "delete"
    ],
    "lastUpdated": "2020-03-18T14:43:05.134Z",
    "type": "Data Asset",
    "branchName": "main",
    "documentationVersion": "2.0.0",
    "finalised": true,
    "readableByEveryone": false,
    "readableByAuthenticatedUsers": false,
    "dateFinalised": "2020-03-18T14:39:16.667Z",
    "modelVersion": "1.0.0",
    "authority": {
        "id": "4dacb991-c0cb-4d46-b865-fea67a8f7d37",
        "url": "https://oxnetdwa02.oxnet.nhs.uk/",
        "label": "OUH-CDW"
    }
}

Desktop (please complete the following information):

  • OS: Mac OS 11.3.1
  • Browser safari
  • Version: 14.1

Incorrect call to retrieve Term relationships

When the relationships for a term are retrieved, the call should pass the parameter type=source. This will ensure that the correct relationships are displayed... at the moment all relationships where the current term is the target, which leads to a confusing display.

Empty string MDM_UI_THEME_NAME env variable breaks the UI theme loading

Describe the bug
If MDM_UI_THEME_NAME is set to an empty string then the UI cannot load any theme resulting in a 404 on assets/themes//logo.png

To Reproduce
Set MDM_UI_THEME_NAME='' then run or build and run the ui

Expected behavior
If the env variable is blank or null or not present then we should use the default theme, we should also probably handle an unknown theme to default to the "default" theme incase someone puts junk in.

Screenshots
Screenshot-2021-04-22-at-12 20 47

Search Bar when cleared not reverting to full Tree view

Describe the bug
When clearing the search bar, the tree view stays on the filtered view rather then reverting back.

To Reproduce
Steps to reproduce the behavior:

  1. Go to 'OUH instance'
  2. Click on 'the search bar' -- search for a model, clear the search bar

Expected behavior
I would expect that when the search bar is cleared of the search the tree would revert back to the main (unfiltered) tree view
Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: Mac OS 11.3.1
  • Browser Safari
  • Version 14.1

Additional context
I've only tried this in the OUH instance, will test others when I get a chance.

Should be able to create a DataModel without adding DefaultDataTypes, and other optional values.

Describe the bug
When creating a model the following values are optional but they're marked as mandatory

  • author
  • organisation

When creating a new DataModel you should not have to select default data types to add. It is an optional thing for users to do if they want

To Reproduce
Steps to reproduce the behavior:

  1. Try to create a DataModel and get through the creation process without filling out any of the above

Refactor BroadcastService to be type safe

Issue

The current BroadcastService broadcasts messages to other unrelated components as follows:

  • Send a message name as a string
  • Send optional data with the message as any data

This does introduce technical debt because of the copy/paste aspect of broadcasting/subscribing to these events. For example, to trigger the model tree to reload:

service.broadcast('$reloadFoldersTree');

If this were mispelled or the message name was changed in the future, re-testing this would have to be manual instead of found during compile time.

Suggestion

It is possible to create a type-safe broadcast service where:

  • Message names are defined as constants
  • Expected data can be defined with generics

An example of interface for this could be:

export enum BroadcastEvent {
  ReloadFolderTree,
  // etc...
}

export class BroadcastMessage<T> {
  constructor(public event: BroadcastEvent, public data?: T) { }
}

export class BroadcastService {
  private handler = new Subject<BroadcastMessage<any>>();

  // Call this to subscribe to certain events
  on<T>(event: BroadcastEvent): Observable<T> { }

  // Call this to dispatch/broadcast events
  dispatch<T>(event: BroadcastEvent, data?: T): void { }
}

Tasks

  • Refactor the BroadcastService to use the type-safe methods
  • Add the necessary BroadcastEvent enums. Search the codebase for all instances of the string name usage as a start
  • Replace the old string broadcast names with BroadcastEvent
  • Ensure all subscription points still work

Default folder location when importing

When you import a model (data model, terminology, etc) using the UI, there's a field to decide which folder the newly created model(s) are imported into. If a folder is selected in the tree, it would be nice if the folder selector could default to this location.

Add Link Fails when adding custom Links

Describe the bug
Add Link Fails when adding custom Links

To Reproduce
Steps to reproduce the behavior:
Go To A DM
Click on Context
Click Add link
Fill in required info click green tick

Notice it doesn't save

Deleting SourceFlowDataModel Throws exception

Using the Bootstrap dataclasses delete SourceFlowDataModel the following error is returned

  "headers": {
    "normalizedNames": {},
    "lazyUpdate": null
  },
  "status": 500,
  "statusText": "OK",
  "url": "http://localhost:8080/api/dataModels/6aaf8e1e-b91e-415c-9d86-e4fc2ccc87f8?permanent=true",
  "ok": false,
  "name": "HttpErrorResponse",
  "message": "Http failure response for http://localhost:8080/api/dataModels/6aaf8e1e-b91e-415c-9d86-e4fc2ccc87f8?permanent=true: 500 OK",
  "error": {
    "status": 500,
    "reason": "Internal Server Error",
    "errorCode": "UEX--",
    "message": "No signature of method: uk.ac.ox.softeng.maurodatamapper.dataflow.component.DataElementComponentService.deleteAllFacetsByCatalogueItemIds() is applicable for argument types: (ArrayList, String) values: [[24a4dd67-2548-4acd-bd2c-0ba977649a69, 32772381-b2c8-44ee-b1a4-1d2fee0087aa, ...], ...]",
    "path": "/api/dataModels/6aaf8e1e-b91e-415c-9d86-e4fc2ccc87f8",
    "devMode": true,
    "version": "4.5.0-SNAPSHOT",
    "exception": {
      "type": "MissingMethodException",
      "message": "No signature of method: uk.ac.ox.softeng.maurodatamapper.dataflow.component.DataElementComponentService.deleteAllFacetsByCatalogueItemIds() is applicable for argument types: (ArrayList, String) values: [[24a4dd67-2548-4acd-bd2c-0ba977649a69, 32772381-b2c8-44ee-b1a4-1d2fee0087aa, ...], ...]",
      "stacktrace": [
        "uk.ac.ox.softeng.maurodatamapper.dataflow.component.DataElementComponentService.$tt__dataElementComponentService_deleteAllByModelId(DataElementComponentService.groovy:123)",
        "jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)",
        "jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)",
        "jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)",
        "jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)",
        "grails.gorm.transactions.GrailsTransactionTemplate$2.doInTransaction(GrailsTransactionTemplate.groovy:94)",
        "org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)",
        "grails.gorm.transactions.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:91)",
        "uk.ac.ox.softeng.maurodatamapper.dataflow.component.DataClassComponentService.$tt__dataClassComponentService_deleteAllByModelId(DataClassComponentService.groovy:115)",
        "jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)",
        "jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)",
        "jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)",
        "jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)",
        "grails.gorm.transactions.GrailsTransactionTemplate$2.doInTransaction(GrailsTransactionTemplate.groovy:94)",
        "org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)",
        "grails.gorm.transactions.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:91)",
        "uk.ac.ox.softeng.maurodatamapper.dataflow.DataFlowService.$tt__dataFlowService_deleteAllByModelId(DataFlowService.groovy:103)",
        "jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)",
        "jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)",
        "jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)",
        "jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)",
        "grails.gorm.transactions.GrailsTransactionTemplate$2.doInTransaction(GrailsTransactionTemplate.groovy:94)",
        "org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)",
        "grails.gorm.transactions.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:91)",
        "uk.ac.ox.softeng.maurodatamapper.datamodel.DataModelService$__tt__dataModelService_deleteModelAndContent_closure93.doCall(DataModelService.groovy:352)",
        "jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)",
        "jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)",
        "uk.ac.ox.softeng.maurodatamapper.datamodel.DataModelService.$tt__dataModelService_deleteModelAndContent(DataModelService.groovy:347)",
        "jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)",
        "jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)",
        "jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)",
        "jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)",
        "grails.gorm.transactions.GrailsTransactionTemplate$2.doInTransaction(GrailsTransactionTemplate.groovy:94)",
        "org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)",
        "grails.gorm.transactions.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:91)",
        "uk.ac.ox.softeng.maurodatamapper.datamodel.DataModelService.$tt__dataModelService_delete(DataModelService.groovy:161)",
        "jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)",
        "jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)",
        "jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)",
        "jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)",
        "grails.gorm.transactions.GrailsTransactionTemplate$2.doInTransaction(GrailsTransactionTemplate.groovy:94)",
        "org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)",
        "grails.gorm.transactions.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:91)",
        "uk.ac.ox.softeng.maurodatamapper.core.model.ModelService.permanentDeleteModel(ModelService.groovy:166)",
        "uk.ac.ox.softeng.maurodatamapper.core.controller.ModelController.$tt__modelController_delete(ModelController.groovy:144)",
        "jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)",
        "jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)",
        "jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)",
        "jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)",
        "grails.gorm.transactions.GrailsTransactionTemplate$2.doInTransaction(GrailsTransactionTemplate.groovy:94)",
        "org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)",
        "grails.gorm.transactions.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:91)",
        "jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)",
        "jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)",
        "org.grails.core.DefaultGrailsControllerClass$ReflectionInvoker.invoke(DefaultGrailsControllerClass.java:211)",
        "org.grails.core.DefaultGrailsControllerClass.invoke(DefaultGrailsControllerClass.java:188)",
        "org.grails.web.mapping.mvc.UrlMappingsInfoHandlerAdapter.handle(UrlMappingsInfoHandlerAdapter.groovy:90)",
        "org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)",
        "org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)",
        "org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)",
        "org.springframework.web.servlet.FrameworkServlet.doDelete(FrameworkServlet.java:931)",
        "org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)",
        "org.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:77)",
        "org.grails.web.filters.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:67)",
        "java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)",
        "java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)",
        "java.lang.Thread.run(Thread.java:835)"
      ]
    }
  }
}

Delete not available on Terminologies

I have a draft terminology - 'delete' is coming from the back end as an available action, but the delete option isn't appearing in the action dropdown.

Remove redundant code from Detailed views

There is a lot of redundant code within the detailed views of most catalogue items, to improve code readable this should be reviewed and refactored to make the code more clean

Update notice

The NOTICE file (and code file headers) still have the old notice file on (with an old date). Needs updating across the board.

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.