Code Monkey home page Code Monkey logo

exchange-addon-licensing's People

Contributors

timothybjacobs avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

exchange-addon-licensing's Issues

API Version Action

This issue describes the /version/ API action. An outline of the API is specified in issue #8.

The version action is used to retrieve information about the latest version of the software, and a url to the download location.

Request

URL: https://www.youstore.com/itelic-api/version/
Verb: GET

Response

If the request is successful, i.e. a valid, active license key, the following response will be returned.
Code: 200 OK

{
  "success": true,
  "body": {
    "version": "1.2.1",
    "package": "https://www.yourstore.com/itelic-api/secure-download-link",
    "expires": "2015-11-21T16:05:30"
  }
}

Fields

  • success – Boolean field representing if the response is successful, For handling error conditions, see Error.
  • body – Object containing the response body.
    • version – String representing the current version of the software product
    • package – Encoded download URL.
    • expires – ISO 8601 representation of when the download URL expires. Default value is 24 hours after request.

Error

This will cover all possible errors, besides an authentication error resulting from not passing any license key. The message string MAY be changed in the future. The error code MUST NOT be changed.

Expired License Key

Code: 402 Payment Required
Returned when the license key being used is Expired.

{
  "success": false,
  "error": {
    "code": 02,
    "message": "Your license key has expired."
  }
}

Theme Updater Class

A simple drop-in class will be provided for use in WordPress themes to provide automatic updates. Updates will be made available in the typical WordPress fashion.

Plugin Updater Class

A simple drop-in class will be provided for use in WordPress plugins to provide automatic updates. Updates will be made available in the typical WordPress fashion. We will also autofill the various fields in the plugin modal: i.e., name, description, banner images, tested up to, etc... The updater class will make use of the API described in #8.

API Download Action

This issue describes the /download/ API action. An outline of the API is specified in issue #8.

The download action is used to force the download of the latest version of the software.

Request

URL: https://www.yourstore.com/itelic-api/download/
Verb: GET

Success

If the request is successful, i.e. an active API key, the latest version of the software will be downloaded. Most commonly the software will be in zip format.
Code: 200 OK

Error

This will cover all possible errors, besides an authentication error resulting from not passing any license key. The message string MAY be changed in the future. The error code MUST NOT be changed.

Expired License Key

Code: 402 Payment Required
Returned when the license key being used is Expired.

{
  "success": false,
  "error": {
    "code": 02,
    "message": "Your license key has expired."
  }
}

Key Type: From list

Allow for license keys to be pulled from a list per-product. List should be stored in post meta for the product.

The settings form for this key type should display a disabled textfield with a fixed height and width as well as a button. When the button is pressed a WordPress Thickbox should popup that allows for a list of license keys to be copy and pasted into a textfield, and an upload button for uploading keys from a list. When finished, user presses Done – closing the Thickbox and displaying the keys in the disabled textfield.

Reports Tab

In the Licenses admin page, there will be an additional tab called Reports. This will displaying various charts and tables sectioned off in groups by the type of data the charts are representing.

  • Licenses
  • Renewals
  • Upgrades

Account Licenses Page

An additional Account sub-page should be registered call Licenses. This will display a list of all of the customer's licenses, their status, the product, a link to see the initiating transaction, and a link to see the active install locations. On this page, they should be able to remotely deactivate any of those install locations. Additionally, they should be able to activate a license location. This would probably only make sense if the product is something installed on Websites, allowing for an easy UX.

License Renewal

Licenses can be renewed in a variety of manners.

Super Widget. When in the Super Widget for a product, an additional option will be added to Buy Now and Add to Cart called Renew. The system will then look up the originating transaction. This will prompt the user for their license key. If the transaction was a Guest Checkout payment, then the user will be prompted for the email address they initially used. Otherwise the user will be prompted to login. The product will then be added to the cart.

Checkout. On the checkout screen, a button will be presented allowing users to renew their license by entering their license key. If the user is logged in, they'll be able to mark their order as a renewal without having to enter a license key.

Account Purchases Page. A button will be added to the account/purchases page for each licensed purchase allowing users to renew their license key. This will redirect the user into the Super Widget with the renewal option already selected, and, naturally, the license key pre-filled.

Screen Options Help Tab

We should add Help tabs to all of the admin screens. We'll need a way to filter based on the current tab, and current view.

Renewal Reminders

An arbitrary number of renewal notifications can be created. These can be fired n days before and n days after a license key expires. There should be a distinction made between renewal notifications for automatic renewing keys and manual renewing keys.

The following substitutions should be made available.

  • Customer First Name
  • Customer Last Name
  • License Key
  • Product
  • Transaction #
  • Expiry date
  • Number of days before/after expiration date
  • Renewal discount – displays amount and type ( $5 or 5% )

The renewal reminders should be automatically sent out via a daily cron job.

Initial API Outline

Licensing will ship with a basic API for interacting with license keys. Initially, the plugin will have to register its own endpoints, because the WP REST API is not yet released. When the WP API is released into WP Core, Licensing will register its endpoints through the WP API, while retaining back-compat with the old endpoints. As such, the handling of global state, super globals, URLs, etc... should be abstracted away as much as possible from the core API to facilitate an easier transition process.

This Issue will describe the overall API. Specifics on endpoints and actions will be covered in their own issues.

The API will be consumed using JSON. The API will be accessible at site_url()/itelic-api/{$action}/.

The following are the currently supported API actions.

  • /activate/ POST. Activate an API key for a certain location.
  • /deactivate POST. Deactivate an API key for a certain location.
  • /info/ GET. Retrieve information about a key: status, expiry date, location, etc...
  • /version/ GET. Retrieve the latest version for the product the API key grants access to. Includes download URL.
  • /download/ GET. Force download of latest version.
  • /product/ GET. Retrieve information about the product. Tested up to, Version, Banners, etc...

All requests require a license key passed via the BasicAuth username field. The password field is left blank. If an API key is not present, 401 Not Authorized header will be returned. For actions that require an active key, but the key passed is expired, a 403 Forbidden header will be returned.

All requests SHOULD be made over HTTPS. But the API will not reject HTTP requests.

Filter releases table by start date

Another filter action should be implemented to filter the releases table by the expiry date. You should be able to filter by month, six months prior to and twelve months after the current month.

Changelog Editing with tinyMCE

Allow for editing the changelog with tinyMCE, instead of just a plain text area.

Currently, when trying to make the substitution, tinyMCE freezes, unless the page was initially loaded with tinyMCE in the "text" mode.

Archive Scheduling

We need an automated way to archive releases. There are a couple of options.

  1. Keep the last n releases.
  2. Keep the last n major releases, x minor releases.
  3. Keep releases for n days.

Lastly this could be either a UI configuration or a filter.

Single License View

Admin page showing information about a particular license key.

License Key Information

Viewable Information

  • Key
  • Product
  • Status
  • Customer
  • Max activations
  • Expiry date
  • Transaction

Editable Information

  • Status
  • Max activations
  • Expiry date

Activations

A table of all activations of a particular license, including not only active activations, but deactivated and expired activations as well.

Viewable Information

  • ID
  • Location
  • Status
  • Activation Date
  • Deactivation Date

Editing

An active activation can be deactivated, and any deactivated activation can be reactivated. Additionally, an activation record can optionally be completely removed from the DB.

Creation

License keys can be activated for an installation location. This will be done using a regular text input for capturing the installation location, and an "Activate" button for triggering the remote activation.

Licenses List Table

In the Licensing admin page, see #17, on the Licenses view, a paginated list table should be displayed representing all of the licenses created on the site.

The list table will have the following columns. Nested list items represent row actions.

  • Key – The license key.
    • View – Brings the admin to a page displaying in-depth information about this key.
  • Status – The status of this key.
  • Product – The product name this key licenses. Linked to the edit product page.
  • Customer – The customer's name. Linked to the customer view page.
  • Expires – The date when the license key expires.
    • Extend – Extends the license expiry date by the original length. Ex. For yearly license, expiry date increased by a year. For monthly license, expiry date increased by a month.
  • Active Installs – Count of the number of active installs.
  • Max Active – Maximum number of activations allowed concurrently.
    • Increase – Increase the total number of activations allowed by one.
    • Decrease – Decrease the total number of activations allowed by one.
  • Transaction – Transaction that generated this key. Linked to the view transaction page.

Licensing Admin Page

An additional admin page should be registered under the Exchange menu called Licensing. Similar to how it is handled in Classes, there will be a tab interface on the top of the page.

Admins can toggle between the Licenses view and the Reports view. In brief, the Licenses view contains information about all of the license keys created on the site and the Reports view graphs renewals over time.

Products Report

One section in the reports tab (#40) is called Products. The following information will be displayed.

  • Pie chart showing the 5 most popular versions of the software installed.

Active License Period

By default licenses last forever. If the Recurring Payments add-on is activated, then the license key's active period will be restricted to the options set out in RP.

If auto-renewal is disabled, then after the purchase period is finished, the license should no longer be valid.

If auto-renewal is enabled, then the license will be valid, for as long as the recurring payment persists.

Upgrade License

Customer's need to have a way to easily upgrade from one license type to another license type.

This would probably be done in a similar manner to how we handle renewals. We will add an additional button to the Super Widget prompting people to upgrade their license if they have an existing license for this product.

The upgrade price would be the new price, minus the existing price.

Add New License Key

To add a new license key by hand, the Manual Purchases add-on must be active. The user will do this through the manual purchases flow.

If a user selects a digital download with licensing enabled, the following fields will appear.

  • Activation limit.
  • Expiry date.
  • License key. If desired, the user can override the license key that would be automatically generated.

Once the key has been generated, the user will be redirected to the license single view.

Release Types

Each release has its own type.

Major releases are from 1.5 to 1.6. In the admin, these releases will be marked as major, and will recommend backing up before updating.

Minor releases are from 1.5.1 to 1.5.2. These do not have any special demarkations.

Security releases fix a security bug. In the admin these are marked as such, and recommend immediate upgrading.

Pre-release releases are alpha or beta releases. These releases won't appear by default. Instead when a user activates a license key, they need to sign up for pre-releases. An activation can be PATCHed to enable or disable pre-releases.

Restricted releases are limited to only certain license keys. These license keys can be specified when creating a release, or while editing a release.

Restricted Release Type UI

The user interface for restricted releases is a bit complex. Releases are restricted by license keys. The restricted releases also require an incrementing version number see issue #33.

The UI for this is a bit tricky. Ideally, a user can search for a license key directly, by customer, or by activation location ( website ). Each of these search options will return results formatted in a list, with each result displaying the license key, license status, and customer. If the user searches by activation location, the user will need visual confirmation of some kind.

When the result is selected, it will be appended to the list of whitelisted license keys. This will be saved via ajax.

Prevent activating or creating a release with a lower version number

When a customer goes to create a release, we display the current version number next to the text input. There is currently nothing preventing the user from creating a release with a version number less than the current one. We should validate the version number in javascript as the version number is inputted.

Users can draft releases. This makes it possible for a user to draft a release, r1, with version 1.1. Then create another release, r2, with version 1.2. If the user then activates r2, we need to prevent the user from releasing r1 because its version number is now outdated. To accomplish this, we should display a warning message on top of the outdated release and prevent the user from toggling the status to Active.

Release and Update Data structure

Releases and upgrades will be stored in separate tables.

Releases

  • ID. Unique, auto-generated, primary key.
  • product. ID of the corresponding product.
  • download. ID of the corresponding Exchange download post.
  • version. Varchar storing the version number.
  • status. Varchar of the status.
  • type. Varchar of the Release type.
  • changelog. Text of what changed just in this version.
  • start_date. Date and time of when the releases was started.

Updates

  • ID. Unique, auto-generated, primary key.
  • activation. ID of the activation record.
  • release. ID of the corresponding release.
  • date. Time of the upgrade.

License Renewal Discount

Store owners can optionally setup a license renewal discount that will be automatically applied at checkout – see #3. The renewal discount can be overwritten on a per-product basis. This should be treated as a separate product feature, that is only displayed if licensing is enabled for the current product by checking the enable checkbox. The product feature should always be registered, and rendered. However, the product feature should be initially hidden from view. When the enable checkbox is checked, the product feature should automatically be displayed.

The discount has a variety of options.

  • Type. Percent or Flat.
  • Amount. Either the percent amount, or the dollar amount subtracted.
  • Expiry date. The renewal discount can only be used within n days after the license key has expired.

Renewal Record Storage

How should renewal records be stored? Renewals will be charged as a child transaction. So that will take care of the detailed information about renewals.

The main requirement is that we need someway to report on the rate of renewals. i.e. in the month of September, 150 licenses expired, and 100 were renewed. This is complicated by the fact a license often could not be renewed at the same time as the license expires.

The child transaction does have a post date, and references the parent transaction which would have generated the original transaction. The question is if that'd be efficient. We'd have to do something along the following to get all of the renewals.

SELECT * FROM wp_posts WHERE post_parent IN ( SELECT transaction_id FROM wp_itelic_keys )

Add New Release

Users can create a new release from the Releases tab in the licensing admin area. The following are the steps the user will go through. Each step should only reveal itself as necessary.

  1. Select a product
  2. Enter in new version number
  3. Upload release file.
  4. Select release type
  5. If release type is not pre-release or restricted, enter in change log for this version
  6. Click "Publish" or "Save as Draft"

At this point the view will transition to a clear screen, with a button prompting them to "Notify Your Customers" or "Continue to Release".

If they select Notify:

  1. Customize subject preset to "Announcing {product_name} version {version number}"
  2. Enter in text through a wp_editor instance. Template tags will be made available.
  3. Click Send.

add new release jpeg

Front-end Display of License Keys

License keys should be displayed in the following places on the front-end.

  • Order confirmation page.
  • Downloads page. Need to consider how not to make it clear it is different from the download hash.
  • Account licenses page. See #6.

API Activate Action

This issue describes the /activate/ API action. An outline of the API is specified in issue #8.

The activate action is used to activate a license key for a particular location.

Request

URL: https://www.yourstore.com/itelic-api/activate/

{
  "location": "http://www.install-location.com"
}

Fields

  • location – Location of this install. For plugins and themes, this would be the URL of the website it was installed on. Otherwise any unique identifier can be used. Ideally, this should be human readable, but could be appended with a unique hash. Max length: 255 chars.

Success

If the request is successful, i.e. an active API key, the following response will be returned.

Code: 201 Created

{
  "success": true,
  "body": {
    "id": 143,
    "activation": "2015-05-22T13:45:56",
    "deactivation": "",
    "location": "http://www.install-location.com",
    "status": "active"
  }
}

Fields

  • success – Boolean field representing if the response is successful. For handling error conditions, see Error.
  • body – Object containing the response body.
    • id – Unique ID representing this install location.
    • activation – ISO 8601 representation of the time of activation.
    • deactivation – ISO 8601 representing the time of deactivation.
    • location – Location of this install.
    • status – The status of the activation. One of active, deactivated, expired. This will be active for a fresh activation.

Error

This will cover all possible errors, besides an authentication error resulting from not passing any license key. The message string MAY be changed in the future. The error code MUST NOT be changed.

Maximum Activations Reached

Code: 403 Forbidden
Returned when the maximum number of activations has been reached before this request.

{
  "success": false,
  "error": {
    "code": 01,
    "message": "The maximum number of activations of this license key has been reached.."
  }
}

Expired License Key

Code: 402 Payment Required
Returned when the license key being used is Expired.

{
  "success": false,
  "error": {
    "code": 02,
    "message": "Your license key has expired."
  }
}

Display key renewals

On the single key view we should display a list of renewals for that key.

This would display the date that the renewal took place, and a link to the renewing transaction.

Release Automation

Ideally, it'd be nice for releases to be automated via services like GitHub. For example, whenever a new release is made on GitHub, a release could be drafted by pulling the version number, changelog and new download file.

Release Single View

Each release has its own view/edit page in the admin. This is accessed via the releases list page.

On the top of the page the following information will be displayed.

  • Percent of licenses upgraded. Hovering over this will reveal the actual numbers
  • Status.
  • Action. If the status is Draft a publish button will be displayed. Otherwise a pause button, which pauses the release.

The percentage of licenses upgraded will update automatically via the Heartbeat API. A cool looking and useful graph would be nice. Perhaps a graph of upgrades over time.

Optionally, the user can click a button to reveal all of the upgrade records. This will be a table paginated with AJAX.

Finally, a user can write an email to be sent to all of the users who have not yet upgraded to the latest version.

Variants Support for Max Activations

We should add support for variants.

We would be registering a new variant type, similar to colors. The user would be able to control the name of the variant, and how many activations the variant would be good for. So a user could setup an option for selling a license with a max activation count of 1, or 5, or unlimited.

Licensing Reports

One section in the reports tab (#40) is called Licensing. The following information will be displayed.

  • Licenses created over time. Can drill down over multiple date ranges. Optionally, the user can compare to the previous period. For example: display this quarters licenses overlaid last quarters licenses.

Renewal Reports

One section in the reports tab (#40) is called Renewals. The following information will be displayed.

  • Pie chart showing percent of licenses which have been renewed.
  • Renewals overtime.
  • Renewal revenue overtime.

Filter Releases List Table

The releases list table should support filtering by the following:

  • Product.
  • Status.
  • Type.
  • Start Date. Setup similarly to the months dropdown.

API Info Action

This issue describes the /info/ API action. An outline of the API is specified in issue #8.

The info action is used to retrieve information about a license key.

Request

URL: https://www.yourstore.com/itelic-api/meta/
Verb: GET

Success

As long as a license key is used for authentication, this request will always be successful.

Code: 200 OK

{
  "success": true,
  "body": {
    "transaction": 423,
    "product": 231,
    "customer": 32,
    "status": "active",
    "max": 5,
    "activations": {
      "count": 2,
      "count_active": 1,
      "list": [
        {
          "id": 143,
          "activation": "2015-05-22T13:45:56",
          "deactivation": "2015-05-29T01:31:45",
          "location": "http://www.install-location.com",
          "status": "deactivated"
        },
        {
          "id": 147,
          "activation": "2015-05-22T13:45:56",
          "deactivation": "",
          "location": "http://www.other-install-location.com",
          "status": "active"
        }
      ]
    }
  }
}

Fields

  • success – Boolean field representing if the request was successful.
  • body – Object contain the response body.
    • transaction – Originating transaction ID.
    • product – Product this key is licensed to.
    • customer – Customer ID this key belongs to.
    • status – Status of this license key. One of active or expired.
    • max – Maximum number of concurrent activations.
    • activations – Object containing information about this key's activation history.
      • count – Number of total activations.
      • count_active – Number of active activations.
      • count_deactivated – Number of deactivate activations.
      • list – Array listing the activation history of this key.
        • id – Unique id identifying this activation.
        • activation – ISO 8601 representation of the time of activation.
        • deactivation – ISO 8601 representation of the time of deactivation. MAY be empty.
        • location – Location of this activation. SHOULD be unique.
        • status – Status of this activation. One of active, deactivated, expired.

API Deactivate Action

This issue describes the /deactivate/ API action. An outline of the API is specified in issue #8.

The deactivate action is used to deactivate a license key for a particular location. The location can be specified using the activation id returned by a successful activation OR the unique location value passed when activating, see #9.

Request

URL: https://www.yourstore.com/itelic-api/deactivate/

{
  "location_id": 143
}

Fields

  • location_id – Activation id returned from #9.

Success

If the request is successful, i.e. a valid identifier, the following response will be returned.

Code: 200 OK

{
  "success": true,
  "body": {
    "id": 143,
    "activation": "2015-05-22T13:45:56",
    "deactivation": "2015-05-29T01:31:45",
    "location": "http://www.install-location.com",
    "status": "deactivated"
  }
}

Fields

  • success – Boolean field representing if the response is successful. For handling error conditions, see Error.
  • body – Object containing the response body.
    • id – Unique ID representing this install location.
    • activation – ISO 8601 representation of the time of activation.
    • deactivation – ISO 8601 representing the time of deactivation.
    • location – Location of this install.
    • status – The status of the activation. One of active, deactivated, expired. This will be deactivated for a fresh deactivation.

Error

This will cover all possible errors, besides an authentication error resulting from not passing any license. The message string MAY be changed in the future. The error code MUST NOT be changed.

Not Found

Code: 404 Not Found
Returned when the activation could not be found. Either because of an invalid activation id or install location.

{
  "success": false,
  "error": {
    "code": 03,
    "message": "Activation record could not be found."
  }
}

Upgrade Reports

One section in the reports tab (#40) is called Upgrades. The following information will be displayed.

  • Upgrades overtime
  • Revenue from upgrades overtime
  • Time until upgrade.

Releases

This is a tracking ticket for the overarching goal of "Releases." Instead of developers changing the update file, updating the version, and updating the changelog to initiate a new release, developers will use a custom release interface. This will provide more power and customization, while making the process more intuitive.

Releases will be a new tab in the licensing admin page. The index page will list all of the releases in a WP_List_Table. The releases can be filtered down by product and/or status. Additionally, an Add New button will be on the top of the screen. From here a user can create a new release.

A release has three choices for a status:

  • Draft. Releases which have been created, but not yet available.
  • Active. Releases which have been publicly released, and customers can now upgrade.
  • Partially Complete. Releases where 90% ( configurable ) of customers have upgraded.
  • Complete. Releases where 100% of customers have upgraded.

There are also multiple types of releases:

  • Major Release. Changing from 1.5 -> 1.6 for example.
  • Minor Release. These are point releases. 1.5.1 -> 1.5.2.
  • Security Release. These are also point releases, but primarily fix security bugs.
  • Pre-release. These are releases that will only be available to customers who have signed up for beta-testing.
  • Restricted. These are releases that are only made available to certain customers.
    Each release type will appear differently in the WordPress admin area.

Filter Licenses List Table

The licenses list table should support filtering by the following:

  • Product.
  • Status.
  • Expiry Date. Can select from the next twelve months and the previous six.

The list table should allow for passing a customer parameter in the $_GET variable.

Archive Release

Releases need a way to be archived. Archiving a release reduces the amount of data we have to store.

A release can only be archived if it isn't the latest release. Releases can be automatically archived after a certain amount of time.

When an archived is released, we aggregate all of the data in the itelic_updates table for that release, and delete all of those rows.

  • Number of updates for each day for the 14 days after release
  • Aggregate data of the 5 most popular previous version
  • Percent complete

Support for Bulk Products in the Future

Although bulk products are not yet a think in Exchange, we should plan to be able to support bulk products in the future. There are two mechanisms in which this could work.

  1. Generate a separate license key for each product in the bundle.
  2. Generate a single license key for the bundled product, that can be used for all products.

Customer Licenses

An additional tab in the customer data area should be added called Licensing.

This will display a list of the users license keys. Both expired and active. Each license key should link to the single license view.

API Product Action

This issue describes the /product/ API action. An outline of the API is specified in issue #8.

The product action is used to retrieve information about the licensed product.

Request

URL: https://www.yoursite.com/itelic-api/product/
Verb: GET

Success

If the request is successful, i.e. an active API key, the following response will be returned.

Code: 200 OK

{
  "success": true,
  "body": {
    "name": "Your Licensed Product",
    "description": "This is the description of the licensed product.",
    "version": "1.5.4",
    "tested": "4.1",
    "author": "TimothyBlynJacobs",
    "last_updated": "2015-02-15",
    "banner_low": "https://www.yourstore.com/product/banner-low.png",
    "banner_high": "https://www.yourstore.com/product/banner-high.png",
    "package_url": "https://www.yourstore.com/itelic-api/secure-download-link",
    "description_url": "https://www.yourstore.com/product/",
    "changelog": "This is the changelog of your product"
  }
}

Error

This will cover all possible errors, besides an authentication error resulting from not passing any license key. The message string MAY be changed in the future. The error code MUST NOT be changed.

Expired License Key

Code: 402 Payment Required
Returned when the license key being used is Expired.

{
  "success": false,
  "error": {
    "code": 02,
    "message": "Your license key has expired."
  }
}

Filter keys table by expiry date

Another filter action should be implemented to filter the keys table by the expiry date. You should be able to filter by month, six months prior to and twelve months after the current month.

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.