Git Product home page Git Product logo

boilerplate-net's Introduction

Kontent.ai Boilerplate for ASP.NET Core MVC

Build & Test codecov Stack Overflow Discord

Package Downloads Compatibility
NuGet NuGet net6.0

This boilerplate lets you easily scaffold a web project for development with Kontent.ai and give you a head start in a successful web project. It includes a set of pre-configured features and demonstrates best practices in order to kick off your website development with Kontent.ai smoothly.

What's included

Boilerplate screenshot

Getting started

Installation from NuGet

  1. Run dotnet new --install "Kontent.Ai.Boilerplate::*" to install the boilerplate to your machine
  2. Run dotnet new kontent-ai-mvc --name "MyWebsite" [-pid|project-id "<projectid>"] [-d|domain "<domain_name>"] [--output "<path>"] to init a website from the template
    • You can change the project ID later at any time in appsettings.json
  3. Open in the IDE of your choice and Run

Note: You can install the template from the sourcecode too.

How Tos

How to generate Strongly Typed Models for Content Types

By convention, all strongly-typed Content Type models are generated and stored within the Models/ContentTypes folder. All generated classes are marked as partial to enable further customization without losing the generated code.

The generating is facilitated by a .NET generator tool as pre-build event. If you wish to customize the process, adjust the Tools/GenerateModels.ps1 script.

For instance, to set a different namespace, set the -n command line parameter to [project namespace].Models. Or, to enable usage of Display Templates (MVC) for rich-text elements, set --structuredmodel true.

You can regenerate the models using the included PowerShell script that utilizes the model generator utility. The script is located at .

How to resolve links

Rich text elements in Kontent.ai can contain links to other content items. It's up to a developer to decide how the links should be represented on a live site. Resolution logic can be adjusted in the CustomContentLinkUrlResolver. See the documentation for detailed info.

How to set up webhook-enabled caching

All content retrieved from Kontent.ai is by default cached for 24 minutes. When content is stale (a newer version exists) it is cached for only 2 seconds. You can change the expiration times via the DeliveryCacheOptions in Startup.

If you want to invalidate cache items as soon as they're updated in Kontent, you need to create a webhook and point it to the /Webhooks/Webhooks relative path of your application. The URL of the app needs to be publicly accessible, e.g. https://myboilerplate.azurewebsites.net/Webhooks/Webhooks. Finally, copy the API secret and store it as WebhookOptions::Secret in your Configuration object, typically in the Secret Manager or Azure Key Vault

New webhook configuration

Note: During local development, you can use the ngrok service to route to your workstation. Simply start your application locally and run command .\ngrok.exe http [port] -host-header="localhost:[port]" (e.g. .\ngrok.exe http 59652 -host-header="localhost:59652") and set the webhook URL to the displayed HTTPS address.

Note: Speed of the Delivery/Preview API service is already tuned up because the service uses a geo-distributed CDN network for most of the types of requests. Therefore, the main advantage of caching in Kontent.ai applications is not speed but lowering the amount of requests needed (See pricing for details).

How to render responsive images

The boilerplate contains a sample implementation of the img-asset tag helper from the Kontent.Ai.AspNetCore NuGet package. Using the img-asset tag helper, you can easily create an img tag with srcset and sizes attributes.

How to adjust the sitemap.xml

The boilerplate contains a sample implementation of the SiteMapController. Make sure you specify desired content types in the Index() action method. Also, you can adjust the URL resolution logic in the GetPageUrl() method.

How to handle 404 errors or any other error

Error handling is setup by default. Any server exception or error response within 400-600 status code range is handled by ErrorController. By default, it's configured to display Not Found error page for 404 error and General Error for anything else.

How to adjust URL rewriting

The Boilerplate is configured to load all URL Rewriting rules from IISUrlRewrite.xml file. Add or modify existing rules to match your expected behavior. This is a good way to set up 301 Permanent redirects or www<->non-www redirects.

You can adjust the domain name in the default rewriting rules during the template instantiation by applying the -d|domain parameter.

Get involved

Check out the contributing page to see the best places to file issues, start discussions, and begin contributing.

boilerplate-net's People

Contributors

amoraitis avatar chariths avatar crnd avatar enngage avatar jancerman avatar kashifsoofi avatar kentico-branislavs avatar kontent-ai-bot avatar lextm avatar mirokentico avatar ondrejsevcik avatar petrsvihlik avatar robertgregorywest avatar robvanuden avatar sayedihashimi avatar sevitas avatar simply007 avatar tobiaskamenicky avatar tomasjurasek avatar winklertomas 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  avatar

Watchers

 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  avatar  avatar  avatar  avatar  avatar

boilerplate-net's Issues

Publish the cache and delivery code as a NuGet package

The current boilerplate project is used to start a new web site on Kentico (users are instructed to do so). As such, users get the than-current code at the time of creating a new web site project. All fixes and improvements you made after that moment are usually missed and they never reach production for already existing web sites.

The boilerplate project contains two parts with different usage scenarios:

  • Code encapsulating the official Kentico library and providing additional library-like features (caching, cache reset webhook, signature check etc.). This part tends to be kept intact in the result web site project.
  • Sample website which shows how to get and show data retrieved from Kentico. This part tends to be heavily replaced in the result web site project.

I would like to see the encapsulating code to be published as a somehow-officially-supported NuGet package.

It will have several benefits:

  • It makes sense. Currently, the boilerplate code mixes two different things with two different usage scenarios (encapsulating library vs. example).
  • Users will get the fixes you make even for existing web site projects.
  • Users will save time not being needed to manually transfer the changes you made in the meantime into their copy of the same code.

It will also have few expectations:

  • Users will expect that you will maintain the library part of the code, upgrade it to support new .NET versions in a timely manner (I mean somewhere between RC and RTM) etc.

I did the split for my private projects as it makes no sense to maintain the same library code in several projects so it is feasible.

Why was the webhook signature action filter rewritten into middleware?

Motivation

Middleware was designed by MS to run for all requests, without the notion of routing or other context of MVC.

Conversely, action filters are designed to run for specific controllers/actions.

Given that the webhook secret will never be used throughout the whole app, the rewrite of the SignatureActionFilter class into a middleware makes no sense. The conversion causes that on each and every hit to all controller actions, the request stream is being read and the hash is being calculated, over and over without a use.

Proposed solution

Revert back to an action filter.

Additional context

Blocks #93

LinkedItems returned as null.

I have recently upgraded a site to the latest version on this boilerplate. After the initial build of the site I noticed that most of the pages are missing sections. This is because the response from the API calls, return any linked item objects as null. When debugging I can see that the correct values are in the JSON response.

I am using the following to get the Project Individual Article:
image

The following is what is returned for the ContentModules object (The correct amount of items but all null). This should be a collection of type object as different content types can be used in this section:
image

This functionality was working fine before I upgraded tho the latest version on the boilerplate but can't see why this wouldn't work now. Has there been any changes been made that would stop this from working, that I have missed?

Any help would be much appreciated.

Spike: Pick the best generic cache library

Expected outcome

As it makes sense to support distributed caching along with the existing support of in-memory caching, we'd like to select the most suitable 3rd party caching library to do the job.

Ideally, the library should:

  • be able to handle both distributed and in-mem caching
  • support strongly-typed cache entries
  • be able to set dependencies among cache entries
  • allow the developer to set cache eviction rules (policies) in case of memory pressure

Reference

Note: Rewritten from #52 .

Webhook controller doesn't handle workflow related events

Brief bug description

Workflow related events cannot be deserialized into WebhookModel making the webhook controller action Index not executed since the model is null

Repro steps

Cause the following event to be sent to the webhook:

{
  "data": {
    "items": [
      {
        "item": {
          "id": "76e78624-c7d7-53ae-ab0f-64dfde05e65e"
        },
        "language": {
          "id": "00000000-0000-0000-0000-000000000000"
        },
        "transition_from": {
          "id": "0041a1b3-1820-44d6-bd8a-f252f8f8bf6a"
        },
        "transition_to": {
          "id": "61f60ea5-66e6-4b1e-9c8e-c34e0782f90f"
        }
      }
    ]
  },
  "message": {
    "id": "960a79fc-95b3-42c0-96e3-1493bf6c0193",
    "project_id": "ad8d8eda-c21e-000c-a5e6-7478633c60f3",
    "type": "content_item_variant",
    "operation": "change_workflow_step",
    "api_name": "content_management",
    "created_timestamp": "2019-12-21T00:35:36.2477126Z",
    "webhook_url": "http://2a5a4d10.ngrok.io/webHooks/KenticoKontentWebHook"
  }
}

Expected behavior

There should be support for both type of events either by handling it in different actions or by some other means so both event model to be deserialized by the same action.

Test environment

  • Platform/OS: .NET Core 3.1
  • Boilerplate Version [e.g. 4.0.2]
  • SDK version: 12.3.0

Add support for content type snippets

Kentico Cloud now supports so called content type snippets. These are sets of content elements that can be added to content types to enrich their structure.

They allow you to add several content elements that are managed in one single place, similarly to how inheritance in object oriented programming works. You can add one snippet to a content type. Snippets cannot be added to other snippets, only to content types. The Delivery API responses contain both the elements originating from snippets alongside their own elements. The only difference in them is that elements from snippets have code names prefixed with the code name of the respective snippet. The format of code names is [code name of snippet]__[code name of element].

A shortened example of a content item:

{
    "item": {
        "system": {
            // ...
            "type": "brewer",
	// ...
        },
        "elements": {
	// ...
            "product_name": {
                "type": "text",
                "name": "Product name",
                "value": "AeroPress"
            },
	// ...
            "metadata__meta_title": {
                "type": "text",
                "name": "Meta title",
                "value": null
            },
	// ...
        }
    },
    "modular_content": {}
}

Implement support for rendering content items of content types that utilize a content snippet.

A temporary Dancing Goat project with a preview of snippets is available for everyone who wants to participate in this effort. If you're interested in either adjusting the sample content or implementing the support in the app, let @JanLenoch know and you'll be given access to that project in Kentico Cloud.

The implementation should be in line with how the code generatorworks.

Currently, this issue is blocked by kontent-ai/model-generator-net#43 . But, the models of this app could be modified manually to overcome the block.

Best practice for environment setup

Regarding - Configs for Dev and Production environment
What's the recommended approach to setup environment for development, etc. It would be great to know more details about that, what's the best practice and how boilerplate could help in this manner.

SignatureActionFilter throwing "System.NotSupportedException"

Brief bug description

With an ngrok url setup and the webhook url set to "webhooks/webhooks/index," I put a breakpoint on the Webhooks controller to follow the code - when it arrives at the "request.Body.Position=0" at line 26, it throws a "System.NotSupportedException" - the alternate Seek() method threw the same exception. When I commented out line 26, the system told me to change ReadToEnd() to async methods, but I ran into the same issues there. Kentico support suggested I open an issue for this.

What went wrong?
Webhook crashes on receiving a new message

Repro steps

Step through code in SignatureActionFilter, starting with line 26

  • Platform/OS: .NET Core 3.0, Windows
  • Browser Chrome and Firefox

Add links to screenshots, if possible.
Error

Receiving the wrong object from API when getting item by codename.

Description

I have two objects 'Object1' and 'Object2'. 'Object2' is a child of 'Object1' (according to the CMS structure) and I have created a custom method that gets the correct URL path of the current page by it's codename - i.e. "/{object1Url}/{currentPageUrl}" or "/{object1Url}/{object2Url}/{currentPageUrl}".

I first check to see if the current page is of type 'Object1' by using the following request:

IDeliveryItemResponse<Object1> object1Response = _deliveryClient.GetItemAsync<Object1>(codename, new EqualsFilter("system.type", Object1.Codename), new ElementsParameter(Object1.Field1Codename, Object1.Field2Codename)).Result;

If this object is null, I know that the current page is a child of 'Object1'. So, I then check for 'Object2' by the codename, using the following:

IDeliveryItemResponse<Object2> object2Response = _deliveryClient.GetItemAsync<Object2>(codename, new EqualsFilter("system.type", Object2.Codename), new ElementsParameter(Object2.Field1Codename, Object2.Field2Codename)).Result;

I am then calling this custom method in two separate places and get two different results for the same codename (Content Item). In one of the place I am getting the correct result. But, in the second place, I am getting the Content Item of type 'Object2' returned in the 'object1Response' object, where I check to see if it is of type 'Object1'. So, the URL I build is incorrect for the type of page it is.

This only seems to happen when the current page is a child of the 'Object2' section - i.e. "/{object1Url}/{object2Url}/{currentPageUrl}". The codename I'm passing into the method is definitely for a Content Item of type 'Object2' - I have check this a couple time and also had a colleague double check.

Has anyone come across this as well and have any ways around it?

Add Kentico Cloud Personalization SDK

Motivation

KC has content personalization capabilities. By either placing a predefined JS code into web pages or by using the Tracking API (where JS cannot be used, e.g. native apps), one can start gathering information about visitors, converting them into contacts (after an email address was submitted via any form) and adding them to visitor segments (based on custom rules). Then, a web app may decide which content to render, based on a segment of a particular visitor. The only things needed are adding the JS code, adding the Personalization SDK NuGet package and having some decision logic that operates on the segment information.

Design guidelines

  • Let's add the personalization SDK to the template.
  • Ideally, make it optional (through a dotnet new parameter).

Reference

Article's <img> tag is generated with </img> closing even it is a void element

The HtmlHelperExtensions.AssetImage method builds an img tag which than renders as

<img โ€ฆ></img>

The img tag is a void element. So it should be rendered as just <img> (HTML5, HTML) or self-closed <img/> (HTML5, XHTML).

I suggest to add one of the following lines just before the return image; statement to fix this.

image.TagRenderMode = TagRenderMode.SelfClosing; // XHTML-like <img/>

image.TagRenderMode = TagRenderMode.StartTag; // HTML-like <img>

Caching with Kentico Cloud

Simple fixed-time caching - Could you please provide more details about this functionality?
How it works, when people should use it/should not, what's the best practice for caching in general.

Missing robots.txt

Motivation

Readme.md says it includes a robots.txt, but it does not.

Proposed solution

Add the robots.txt

Additional context

AbstractResponse.HasStaleContent is always false

Trying to get the caching to work so that when an item is Published or Unpublished, the cache is cleared straight away on the Live site.

I have noticed within the InvalidatingCacheManager.cs object, there is an if condition checking if the value object is an AbstractResponse object and that the value has the 'HasStaleContent' property set to true (line 54 - attached screenshot below). But, when debugging this functionality, the 'HasStaleContent' value is also returning false.

I was expected this value to be true when an item has been Published or Unpublished.

Screenshots

image

Improve readme

  • setting up caching #26

  • domain redirect #27

  • robots

  • sitemap

  • link resolver #25

  • by @matodanko from #28 :
    Regarding - Configs for Dev and Production environment
    What's the recommended approach to setup environment for development, etc. It would be great to know more details about that, what's the best practice and how boilerplate could help in this manner.

Update Boilerplate to use v8 of SDK

Motivation

KenticoCloud Delivery SDK has significant breaking changes in version 8, so code based on this boiler plate cannot be updated to version 8, needing it to stay with version 6.

Migrate to ASP.NET Core 2.0

  • compare with the standard ASP.NET Core 2.0 template to see if there are any new patterns that we should embrace
  • migrate the code

404 on webhook endpoint

Brief bug description

According to the webhook debug, new requests sometimes end up with a 404 error. The webhook endpoint is configured on ~/webhooks/webhooks. The 404 status sometimes switches to 200 after some time for already performed webhooks

Repro steps of customer

  1. Setup webhook according to https://github.com/Kentico/kontent-boilerplate-net#how-to-set-up-webhook-enabled-caching
  2. Publish items
  3. Watch status codes in Webhook debug in Kontent UI

Expected behavior

All requests return 200 unless the server is unavailable. Never get 404.

Test environment

  • Platform/OS: .NET Core 3.1
  • Latest Boilerplate version (v4.0.2)

Additional context

The Event log of the webhook endpoint show following stack trace:

System.InvalidOperationException: Unable to resolve service for type 'NoahMedia.Caching.Webhooks.ICacheManager' while attempting to activate 'NoahMedia.Areas.WebHooks.Controllers.WebhooksController'.
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
at lambda_method(Closure , IServiceProvider , Object[] )
at Microsoft.AspNetCore.Mvc.Controllers.ControllerActivatorProvider.<>c__DisplayClass4_0.<CreateActivator>b__0(ControllerContext controllerContext)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.<CreateControllerFactory>g__CreateController|0(ControllerContext controllerContext)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at NoahMedia.Middleware.SignatureMiddleware.InvokeAsync(HttpContext httpContext, IOptions`1 projectOptions) in C:\Development\Noah\noah-media-group-kentico-cloud-main-website\Middleware\SignatureMiddleware.cs:line 39
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task

Conversation

All details and maybe other beneficial info can be found in conversation 26023165963 and 26078540426.

Live site not updated after new item's version is published

Brief bug description

Publishing a new version of an item and a corresponding webhook is being received with status code 200. This however leaves the live site still showing the old version of that item.
It seems to be a cache issue as it doesn't get updated with the webhook.

Repro steps

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior

The cache would get updated and the live site would show the new version of the item.

Test environment

  • Platform/OS: [e.g. .NET Core 2.1, iOS]
  • Browser [e.g. chrome, safari]
  • Version [e.g. 22]

Additional context

Add any other context about the problem here.

Screenshots

Add links to screenshots, if possible.

Simple caching

Update the template to ASP.NET Core 2.1

Updating Boilerplate found a new issue, possibly?

In an early release of the boilerplate I could use the CachedDeliveryClient's GetItemAsync method without any parameters:

var response = await DeliverClient.GetItemAsync<FullWidthContentPage>(PageCodeName);

I updated to the latest release code as of yesterday, and now I receive an error on that line: "parameter cannot be null". To get around it I was able to pass in an empty List but that was the only way I could get it to work. Like so:

var response = await DeliverClient.GetItemAsync<FullWidthContentPage>(PageCodeName, new List<IQueryParameter>());

I believe the issue is in how the code is written in KenticoCloudCacheHelper.cs for the GetIdentifiersFromParameters method, but I am not 100%.

I'm hoping someone can validate my findings, or tell me if I am wrong?

Make it work with "dotnet new"

Add code-generation as a pre-build event

Motivation

Let's help developers keep their models in-sync with Kentico Kontent content models.

Design guidelines

Run the code generator as a pre-build event target.

PoC: https://github.com/Kentico/kontent-boilerplate-net/blob/master/src/content/Kentico.Kontent.Boilerplate/Tools/GenerateModels.ps1

Add full support for IISUrlRewrite.xml file format

So far it's not fully implemented in asp.net core 1.1, but it's implemented in asp.net core 1.2 that should be released in Q2/2017 (source). Once released, we should update boilerplate and add support for fully implemented support for IISUrlRewrite.xml file format.

It will allow our users to use rewrite maps (i.g.: static redirects - old url -> new url).

<rewrite>
  <rewriteMaps>
    <!-- TODO: not supported yet, waiting for asp.net core 1.2 release -->
    <!-- Example of 301 - Permanent redirect with old -> new URL mapping -->
    <rewriteMap name="Static rewrites" defaultValue="">
      <add key="/old-url" value="/?new-url=1" />
    </rewriteMap>
  </rewriteMaps>
</rewrite>

Currently, they have to use workaround or own solution.

Make the template parametrizable

Motivation

The dotnet new templates can be made parametrizable. Supplying a parameter value saves manual work needed when the template has been instantiated.

We can think of at least these two potential parameters:

If we eventually add code with integrations into this boilerplate and if we split the boilerplate into smaller projects with their NuGet packages, we might also allow the developer to list parts that they want to be in the form of a NuGet package (instead of raw code) right from the start (when starting a new project). One such integration would be the Personalization SDK.

Reference

Rewrite CachedDeliveryClient so that it follows the decorator pattern

Motivation

Currently, the CachedDeliveryClient references protected DeliveryClient DeliveryClient { get; } which is wrong. It should reference IDeliveryClient.

Design guidelines

  • CachedDeliveryClient should accept IDeliveryClient in the constructor
  • The current constructor should be removed/altered
  • Instances of DeliveryClient should be created outside the CachedDeliveryClient
  • public HttpClient HttpClient will no longer be necessary in the CachedDeliveryClient
    • tests will create fake HttpClient and pass it to an instance of the DeliveryClient which will be passed to CachedDeliveryClient

Reference

Should we use a generic cache manager?

There are several cache manager libraries in the wild. One of the nice ones is https://github.com/MichaCo/CacheManager . It supports various caching technologies (incl. distributed ones) and is designed to store various types of data in the cache (not only Kentico Cloud data).

Would you welcome such a generic cache manager in our boilerplate?

Pros:

  • support for multiple caching technologies
  • state-of-the-art caching patterns implemented (failover mechanisms, geo-replication, etc.)
  • optimized for performance

Cons:

  • lack of support for cache item dependencies
  • lack of support for type dependencies (eg. if one content item is cached twice as both strongly-typed object and an object of type "dynamic", then both should be invalidated at the same time)

Pros and cons (at the same time):

  • designed for generic usage (not with Kentico Cloud data in mind)

Boilerplate support for .NET Core 3.0

The current Kentico Kontent .NET Core boilerplate only supports .NET Core 2.1. Some of our systems may have limitations for versions of .NET Core under version 3.0 (.NET Core 3.0 added some connectivity functionality for a legacy database system that we use), so an upgrade to .NET Core 3.0 would make using Kentico Kontent simpler in our case. Plus it would keep it in line with our current development plans to implement .NET Core 3.0.

Support VSIX Templates

Enhance readme

Adjust the part for generating models:

  • the boilerplate expects <websitename>.Models, while the utility generates KenticoCloudModels by default

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.