Git Product home page Git Product logo

site's Introduction

Crowdin

Moleculer official website

This is the official website of Moleculer project. This site is built with hexo. Site content is written in Markdown format and located in source.

Development

$ git clone [email protected]:moleculerjs/site.git
$ cd site
$ npm install
$ npm run dev

Open the http://localhost:4000 in your browser.

Generate static files

$ npm run build

Deployment

All changes are deployed to Netlify automatically. No need any operation.

Translations

Do you speak multiple languages? We need your help! To get started translating, visit https://moleculer.crowdin.com/moleculer-documentation and log in with your GitHub account. Select your language and you can start translating.

Here are some guidelines to keep in mind as a translator:

  • Don't open pull requests to translate Moleculer documentation; instead, do all translations on Crowdin.
  • Do not translate JavaScript keywords like String, Event, Array, Class, etc.
  • Do not translate Moleculer classes, method names, event names, etc.
  • If you find an error in the source English docs, open a pull request on the moleculerjs/site repository.
  • If you've been working as a translator and want to have more influence over the approved translations in your language, let us know and we'll make you a proofreader.

Moleculer's localization effort uses Crowdin, an awesome platform for collaborative translation. Changes on Crowdin are automatically turned into pull requests on this GitHub repository.

Contact

Copyright (c) 2016-2020 Moleculer JS

@icebob @icebob

site's People

Stargazers

 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

site's Issues

Headings on index page are linked to undefined

Capture

I was checking out the site and I happened to notice an issue with the links on the main page. Decided to try and track it down and it looks like helpers.js isn't checking to see if headers have id.

site/scripts/helpers.js

Lines 210 to 212 in 121b604

headings.each(function(){
var id = $(this).attr('id');

Figured I may as well open an issue/PR.

"Services.md#Actions" example

Hi,

In the example of services.md#Actions it's referred that

// The action properties are accessible as ctx.action.*

but earlier it's given:

...
add(ctx) {
    return Number(ctx.params.a) + Number(ctx.params.b);
},
...

Shouldn't it be

...
add(ctx) {
    return Number(ctx.mult.params.a) + Number(ctx.mult.params.b);
},
...

So, the example should be

module.exports = {
    name: "math",
    actions: {
        // Shorthand definition, only a handler function
        add(ctx) {
            return Number(ctx.mult.params.a) + Number(ctx.mult.params.b);
        },

        // Normal definition with other properties. In this case
        // the `handler` function is required!
        mult: {
            cache: false,
            params: {
                a: "number",
                b: "number"
            },
            handler(ctx) {
                // The action properties are accessible as `ctx.action.*`
                if (!ctx.mult.cache)
                    return Number(ctx.mult.params.a) * Number(ctx.mult.params.b);
            }
        }
    }
};

Tia

A Simple Docker Example to Illustrate Discovery

Your example projects are fantastic, but I think a simple 2 service docker project would show the power of Moleculer's killer ability to facilitate microservice discovery better than anything else.

For people familiar with Docker, it is a low risk, quick way to validate if something does what you expect.

We almost went the traditional route of using Consul and something like Zeit's micro. Man, I'm so glad we spun up the Conduit test project which I happen to find.

In my mind, a dead simple 2 service project with hot reloading enabled by default is what Moleculer needs to really hockey stick adoption.

"moleculer connect" command

Hi,

moleculer-cli.md#Start a broker and connect to a transporter page,
refers that

This command ..., connects to a transporter server and ...

and the output of $moleculer --help refers

moleculer connect [connectionString] Connect to a remote Moleculer broker.

Does the above mean a static endpoint or a list of them in file?

Tia

Clarification on "Broker"

Hi,

In "Broker Options", the descriptions of created, startedoptions should change from "Fired when ..." into "Fire after ...". Please, clarify.

On the contrary the descriptions of stoppedoption should change from "Fired when ..." into "Fire before ...". Please, clarify.

What I see in "Broker lifecycle - Starting logic", first $broker.started is emitted (which means that broker has started) and after that, it calls any started handler in middlewares & broker options. I suspect that in case of any handler error the broker keeps on living.

On the contrary, in "Stopping logic", $broker.stopped is being emitted in the very end which means that broker is still alive when any stopped handler in middlewares & broker options is called! Hence, the semantic stopped in the handlers is not compatible with that in middleware and maybe in services!

IMHO, you should find a way to make very clear and remove any ambiguity of what is created, loaded, starts, and stops and when putting them on a time scale.

Tia

To help the Russian community to have 100% access to the site

Hello @icebob !
In the Russian community constantly complain about the inaccessibility of the site due to the blocked ip address 167.99.137.12 of netlify.com hosting which uses its international CDN network.
To help the Russian community to have 100% access to the site, I provided Russian CDN hosting based on the largest site in Russia, Selectel (it hosts the largest social network in Russia, vk.com) for accessibility of the site throughout Russia without any restrictions. This CDN will never fall into restrictions and blocking.
Please indicate for subdomain ru.moleculer.services CNAME f906b9f8-f416-4d38-8970-9682515101cf.selcdn.net so that I can give a mirror for the Russian community!

multi-language support

Hello, @icebob!
Help me with hexo, make an example with the support of another language, so that we can make a translation of the site and documentation into the main repository.
I have not previously worked with him and something I can not generate the correct site in working paths.

Translation to pt-BR

Hi, I could help translate to pt-BR. If you want, add it to the crowdin that I will help to maintain!

Inconsistency in broker.md

Hi,

Between Broker options table and Full options object, the following options

 ...
 bulkhead: {
     enabled: true,
     concurrency: 10,
     maxQueueSize: 100,
 },

 transit: {
     maxQueueSize: 50 * 1000
 }, 
 ...

appear only in the object.

Tia

Clarification on "Avoid deadlocks"

Hi,

In Avoid deadlocks note of Lifecycle.md it is referred:

... To avoid it, remove the concerned service from dependencies and use this.waitForServices method out of started handler instead.

"the concerned service" means any one of the two services. Correct?

I cannot understand what "out of started handler instead." means. Especially the "out of"! Please, make it clearer, if possible or give an example.

Tia

Search broken

Looks like the search is broken on the main web site :(

Feeling confused with env SERVICES

I think your mean about env SERVICES at Services loading logic, is to allow the developer to load exactly one or more services according to the value set for it. But in the real world, I feel like it's a group of services instead of services.
You can check my example https://stackblitz.com/edit/moleculer-project-demo-v6n8nd?file=services/a-group/test.service.js

config
image

Results:
image

Expected:
No services load

I'm submitting this because I think if you mean for it to actually load a group of services we should rename it SERVICESGROUP or if not, the site should be update to make it clear

serializers.md

Hi,

At Custom serializer sector the title of the table should be Use custom serializer instead of Use custom cacher.

Tia

Documentation - v0.14

Hi.. last time and expressed here a minor problem in the documentation.

I found another one.

Here it goes
Access the link tracing without context

Where it says
const span = this.broker.startSpan("initializing db", { tags: { dbHost: this.settings.dbHost } });

Should be:
const span = this.broker.tracer.startSpan("initializing db", { tags: { dbHost: this.settings.dbHost } });
Anyway just trying to help.
And I have to say.. You all have done a great job..
Moleculer is awesome!

Cheers!

ToDo's for v0.14

Sticky placeholder to keep track of things we need to update in the docs:

  • communication protocol changed (3 -> 4)

  • handling conflict nodeIDs

  • Breaking: validation broker options is removed. Use validator instead. If validator is defined or true, the validation is enabled. Otherwise, it is disabled.

  • ctx access in Strategies next method.

  • Shard strategy is added.

    const broker = new ServiceBroker({
    	registry: {
    		strategy: "Shard",
    		strategyOptions: {
    			shardKey: "name"
    		}
    	}
    });
  • The broker.use deprecated method is removed. Use middlewares: [] in the broker options instead.

  • hooks inside action definitions, as well.

    broker.createService({
        name: "greeter",
        hooks: {
            before: {
                "*"(ctx) {
                    broker.logger.info(chalk.cyan("Before all hook"));
                },
                hello(ctx) {
                    broker.logger.info(chalk.magenta("  Before hook"));
                }
            },
            after: {
                "*"(ctx, res) {
                    broker.logger.info(chalk.cyan("After all hook"));
                    return res;
                },
                hello(ctx, res) {
                    broker.logger.info(chalk.magenta("  After hook"));
                    return res;
                }
            },
        },
    
        actions: {
            hello: {
                hooks: {
                    before(ctx) {
                        broker.logger.info(chalk.yellow.bold("    Before action hook"));
                    },
                    after(ctx, res) {
                        broker.logger.info(chalk.yellow.bold("    After action hook"));
                        return res;
                    }
                },
    
                handler(ctx) {
                    broker.logger.info(chalk.green.bold("      Action handler"));
                    return `Hello ${ctx.params.name}`;
                }
            }
        }
    });    

    Output

    INFO  - Before all hook
    INFO  -   Before hook
    INFO  -     Before action hook
    INFO  -       Action handler
    INFO  -     After action hook
    INFO  -   After hook
    INFO  - After all hook
    
  • broker metadata option. It's transfered to other nodes.

  • new middleware hooks (registerLocalService, serviceCreating, transitPublish, transitSubscribe, transitMessageHandler, transporterSend, transporterReceive) #436

  • enhanced hot-reload middleware #408

  • new Middlewares:

    • Transmit.Encryption
    • Transmit.Compression
    • Debugging.TransitLogger
    • Debugging.ActionLogger
    • ...etc
  • Kafka transporter upgrade to support kafka-node@4

  • rename ctx.metrics -> ctx.tracing

  • new built-in tracing solution with exporters (Zipkin, Jaeger, Datadog)

  • new built-in metrics solution with reporters (Prometheus, Datadog, StatD)

  • extend internal services ($node)

    // moleculer.config.js
    module.exports = {
        nodeID: "node-1",
        logger: true,
        internalServices: {
            $node: {
                actions: {
                    // Call as `$node.hello`
                    hello(ctx) {
                        return `Hello Moleculer!`;
                    }
                }
            }
        }
    };
  • load middlewares by names

        const { Middlewares } = require("moleculer");
    
        // Extend with custom middlewares
        Middlewares.MyCustom = {
            created(broker) {
                broker.logger.info("My custom middleware is created!");
            }
        };
    
    
        const broker1 = new ServiceBroker({
            logger: true,
            middlewares: [
                // Load by middleware name
                "MyCustom"
            ]
        });    

Please note: middleware must be Object. If Function it will be called with broker. Previous backward compatibility is dropped.

  • global errorHandler in ServiceBroker errorHandler(err, info) {}

    • in info can be reachable actual service or context or action or event...
    • if the error handled, not printed to the console or throw further.
  • broker.hotReloadService has been removed.

Update docs tasks for 0.12 version

Please note, do all changes in next-12 branch and in the source/0.12/docs folder! Thanks.

1. Merging logic changed

  • docs/service.md: change algorithm of actions to "Extend with defaultsDeep."

2. Transporter options changed. No wrapper

  • docs/service.md: update code snippets. Remove nats, redis...etc extra level in transporter options

3. Default nodeID changed

  • docs/broker.md#Broker-options: update nodeID Default value to "Computer name + process PID"

4. New ServiceBroker options

  • docs/broker.md#Broker-options: add new options to the table. middlewares, created, started, stopped

5. Group parameter in broadcast

  • docs/broker.md#Broadcast-event: add broker.broadcast example with groups (like at emit)

6. Update Service Registry page

  • create a Strategies section in [docs/service-registry.md`
    • add some config example from here
    • add RoundRobin strategy with example
    • add Random strategy with example
    • add CpuUsage strategy with example

7. Starting logic is changed

  • add a "Start & Stop" section to docs/broker.md before "Middlewares" section. Write some sentences what happen at broker.start and broker.stop. I will expand it if something missing.

8. Metadata sent back

  • Add metadata section to docs/broker.md after "Call services/Retries" section. Write some sentences what happen at broker.start and broker.stop. I will expand it if something missing.

9. ES6 classes

  • create a new "ES6 class services" section on the bottom of docs/service.md. Copy the content from changelog.

10. Event group option

  • extend code snippet with an overwritten group example in docs/service.md#Events

11. New TCP transporter

  • create a new section for TCP transporter before NATS transporter in docs/transporters.md and copy content from changelog

12. New Kafka transporter

  • create a new section for TCP transporter ander AMQP transporter in docs/transporters.md and copy content from changelog

13. New NATS Streaming transporter

  • create a new section for TCP transporter under Kafka transporter in docs/transporters.md and copy content from changelog

14. Custom REPL commands

  • add new "Custom commands" section to the bottom of docs/moleculer-repl.md. Copy the content from the changelog

15. loadServices default params changed

  • update code snippet in docs/service.md#Load-multiple-services-from-a-folder. Change fileMask = "*.service.js" to **/*.service.js

16. New retriable errors

  • update "Retryable" value to true in "ServiceNotFoundError" and "ServiceNotAvailable" in docs/errors.md#Internal-error-classes

17. ctx.broadcast

  • add ctx.broadcast to table in docs/context.md

18. Clustering

  • Add "Built-in clustering section at the bottom of docs/runner.md. Copy content from changelog

19. Load env file

  • add ".env files" section on the bottom of docs/runner.md page. Add content from changelog.

20. Metrics options

  • Add a new "Context params" section on the top of docs/metrics.md page. Copy content from changelog
  • add some examples from here

21. Cache options

  • add a "Cache options" section under "Cache keys" section to "docs/cachers" page. Copy content from changelog
  • add "#" meta keys example to "Cache keys" section

22. Service dependencies

  • add "Dependencies" section below "Lifecycle events" section to docs/service.md file. Copy the content from changelog

23. Service metadata

  • add "Metadata" section below "Dependencies" section to docs/service.md file. Copy the content from changelog

24. Disabled balancer

  • add a "Disabled balancer" section to docs/transporters on the bottom of page. Leave empty with "TODO"

Selecting streaming mode when using autoAliases seems hard to find in documentation

Hello,

In order to select streaming mode when using autoAliases, one has to define the rest section of its action the following way:

actions: {
  actionName: {
    rest: {
      method: 'POST',
      path: '/some/action/path',
      type: 'stream',
    }
  }
}

The only example detailing this that I have found in the documention is available here:
https://moleculer.services/docs/0.14/moleculer-web.html#File-upload-aliases

In this example the type is set to multipart.
It was not clear, at least to myself, that this type could also be set to stream when defining a rest section.
Moreover, this example does not deal with auto aliases (I agree that this is just the section next to it but I did not relate both examples at first).

@icebob Is this on purpose (meaning we should not use the type field in a rest section) or is this the right way to go (in which case, the documentation could probably be improved)?

Serializer option

Hi,

On moleculer-cli.md#Start a broker and connect to a transporter page,
Options includes
--serializer Serializer [string] [default: null]
but it's not included at the output of $moleculer --help.

Tia

Invalid validator.type FastestValidator

Prerequisites

Please answer the following questions for yourself before submitting an issue.

  • I am running the latest version
  • I checked the documentation and found no answer
  • I checked to make sure that this issue has not already been filed
  • I'm reporting the issue to the correct repository

Current Behavior

moleculer.config.js accept validator.type="Fastest" instead of "FastestValidator" as documentation said

Expected Behavior

Correct documentation about "FastestValidator"

Failure Information

Steps to Reproduce

Please provide detailed steps for reproducing the issue.

  1. Edit moleculer.config.js, set
validator: {
  type: "FastestValidator",
}
  1. run "npm run dev"

Context

Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.

  • Moleculer version: 0.14.9
  • NodeJS version: v12.18.1
  • Operating System: MacOS 10.15.5

Failure Logs

[2020-08-12T12:30:38.616Z] FATAL XXX.local-82113/BROKER: Unable to create ServiceBroker. BrokerOptionsError: Invalid Validator type 'FastestValidator'.
    at Object.resolve (/XXX/node_modules/moleculer/src/validators/index.js:49:10)
    at new ServiceBroker (/XXX/node_modules/moleculer/src/service-broker.js:233:33)
    at MoleculerRunner.startBroker (/XXX/node_modules/moleculer/src/runner.js:450:17)
    at /XXX/node_modules/moleculer/src/runner.js:475:21 {
  code: 500,
  type: 'BROKER_OPTIONS_ERROR',
  data: { type: 'FastestValidator' },
  retryable: false
}
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] dev: `moleculer-runner --repl --hot services/**/*.service.js --envfile .env`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] dev script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /XXX/.npm/_logs/2020-08-12T12_30_38_628Z-debug.log

Joi validation from example does not work correctly

The problem occurs when you try to set a default value.
For example: Joi.object().keys({ foo: Joi.number().valid([0, 1]).default(0) })
Nothing will return.
I already found another way to do this it and created PR to fix docs, just make sure I'm move in the right direction :)
#75

Broker, Service and Middleware Semantic suggestion

Hi,

Please, next find my suggestion.

Broker

Option A Option B
broker.start() (reflexive) broker.start()
broker.stop() (reflexive) broker.stop()
broker.startREPL() broker.repl()
broker.getError() broker.error()
broker.getLogger() broker.logger()
broker.loadService() broker.load()
broker.loadServices() broker.mload()
broker.createService() broker.create()
broker.destroyService() broker.destroy()
broker.getLocalService() broker.local()
broker.waitForServices() broker.wait()
broker.callService() broker.call()
broker.callServices() broker.mcall()
broker.emitEvent() broker.emit()
broker.broadcastEvent() broker.broadcast()
broker.broadcastEventLocal() broker.broadcastLocal()
broker.pingNode() broker.ping()
afterCreate() (reflexive) created()
afterStart() (reflexive) started()
beforeStop() (reflexive) stopping()

Service

Option A Option B
aftercreated() (reflexive) created()
beforeBrokerStart() brokerStarting()
beforeBrokerStop() brokerStopping()

Middleware

Option A Option B
callService() call()
callServices() mcall()
emitEvent() emit()
broadcastEvent() broadcast()
broadcastEventLocal() broadcastLocal()
afterServiceCreate() serviceCreated()
beforeServiceStart() serviceStarting()
afterServiceStart() serviceStarted()
beforeServiceStop() serviceStopping()
afterServiceStop() serviceStopped()
afterBrokerCreate() brokerCreated()
beforeBrokerStart() brokerStarting()
afterBrokerStart() brokerStarted()
beforeBrokerStop() brokerStopping()
afterBrokerStop() brokerStopped()

Tia

this.actions.actionName()

Hi,

In "services.html#Properties-of-Service-instances" this.actions is an object property.

In "actions.html#Action-visibility" a this.actions.xy() method appears, which is not included above.

Tia

[Discussion] Documentation improvements

Hello guys,

We have plenty of great examples and documentation goes through each concept
A newcomer might start coding services very fast by going through the documentation.
As long as you get experienced you want to search for an API Reference documentation

If there is not any discussion about documentation, so let's start a discussion for improvements

I would like to start below

  • API Reference documentation
  • Getting Started tutorial
  • Maybe some minimal general micro service terms glossary

Also, we will need an established way to make these improvements.

  • How we are gonna contribute to the documentation?
  • Who will start it?
  • Do we have stable typescript definitions?

Clarification on "Lifecycle events"

Hi,

As I see, in "Middlewares.md" verbs in past tense (e.g. created, started, stopped) (instead of afterCreate, afterStart, and afterStop) are used to imply "After it was created, started, stopped" and ones in continuous tense (e.g. starting, stopping) (instead of beforeStart and beforeStop) to imply "Before starting, stopping".

In "Lifecycle events" section of "Service.md", it is referred that:

created() {
            // Fired when the service instance created (with `broker.loadService` or `broker.createService`)
        },

async started() {
            // Fired when broker starts this service (in `broker.start()`)
        }

async stopped() {
            // Fired when broker stops this service (in `broker.stop()`)
        }

"When", I think at first sight, induces ambiguity.

In created() it would be "// Fired after the service instance was created ..."

In started() and stopped() it would be "// Fired after broker has started/stopped this service...".

Please, clarify if started() and stopped() handlers are part of starting and stopping procedures of the service itself correspondingly. What about created() handler?

It is part of procedure when, in case there is an error in handler, the service will refuse to be created, start or stop and an error will arise.
It is not part of procedure when, in case there is an error in handler, the service will be created, start or stop normally and an error will arise.

In case any of them is part, then created(), started() and stopped() semantics induce ambiguity. In that case, they would be something like: onCreate, onStart, and onStop, OR duringCreate, duringStart, and duringStop.

Tia

caching missing: service.settings.$cache

I see this configuration missing in document for a long time

// some.service.js
{
  settings: {
    // this is default action cache value
    // will be applied when action.cache === undefined
    $cache: boolean
  }
}

Extend Jaeger sampler documentation.

Is your feature request related to a problem? Please describe.
There is no clear documentation on how to configure the Jaeger sampler. Currently sampling.options refers to https://www.jaegertracing.io/docs/1.14/sampling/#client-sampling-configuration which is describing Jaeger config outside of Moleculer scope.

When using configuration object to instantiate the tracer, the type of sampling can be selected via sampler.type and sampler.param properties. Jaeger libraries support the following samplers:

Constant (sampler.type=const) sampler always makes the same decision for all traces. It either samples all traces (sampler.param=1) or none of them (sampler.param=0).
Probabilistic (sampler.type=probabilistic) sampler makes a random sampling decision with the probability of sampling equal to the value of sampler.param property. For example, with sampler.param=0.1 approximately 1 in 10 traces will be sampled.
Rate Limiting (sampler.type=ratelimiting) sampler uses a leaky bucket rate limiter to ensure that traces are sampled with a certain constant rate. For example, when sampler.param=2.0 it will sample requests with the rate of 2 traces per second.
Remote (sampler.type=remote, which is also the default) sampler consults Jaeger agent for the appropriate sampling strategy to use in the current service. This allows controlling the sampling strategies in the services from a central configuration in Jaeger backend, or even dynamically (see Adaptive Sampling).

And here is what we have in our code:

getSampler(serviceName) {
  if (isFunction(this.opts.sampler)) return this.opts.sampler;

  if (this.opts.sampler.type == "RateLimiting")
    return new Jaeger.RateLimitingSampler(
      this.opts.sampler.options.maxTracesPerSecond,
      this.opts.sampler.options.initBalance
    );

  if (this.opts.sampler.type == "Probabilistic")
    return new Jaeger.ProbabilisticSampler(this.opts.sampler.options.samplingRate);

  if (this.opts.sampler.type == "GuaranteedThroughput")
    return new GuaranteedThroughputSampler(
      this.opts.sampler.options.lowerBound,
      this.opts.sampler.options.samplingRate
    );

  if (this.opts.sampler.type == "RemoteControlled")
    return new RemoteControlledSampler(serviceName, this.opts.sampler.options);

  return new Jaeger.ConstSampler(
    this.opts.sampler.options && this.opts.sampler.options.decision != null
      ? this.opts.sampler.options.decision
      : 1
  );
}

Describe the solution you'd like
Describe a full list of possible sample params in docs.

Describe alternatives you've considered

Additional context

Ask Netlify to switch shared IP for moleculer.services.

I am a lead engineer and architect at Morgan Stanley, the fourth largest investment bank in the world. I have for some time been working on a project that unifies many of our systems communicate with each other, using moleculer as the service bus.

From my understanding the site is hosted on netlify, and currently moleculer.services shared ip is 104.198.14.52. Unfortunately this IP has been blacklisted due hosting other sites with malicious content

https://www.virustotal.com/en/ip-address/104.198.14.52/information/

I will be presenting my proposal in the next month, but it will be hard as our firewall actively blocks moleculer.services due to the IP address being blacklisted. Would it be possible to ask netlify to move your instance to an IP that doesn't.. for the lack of a better word, suck?

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.