Git Product home page Git Product logo

guess-language.el's Introduction

https://melpa.org/packages/guess-language-badge.svg

guess-language: Emacs minor mode for robust automatic language detection

Emacs minor mode that detects the language of what you’re typing. Automatically switches the spell checker and typo-mode (if present).

Key features:

  • Detection algorithm is robust, efficient, and dead simple. Based on character trigrams.
  • Support for many languages. More can be easily added.
  • Stays out of your way. Set up once, then forget it exists.
  • Works with documents written in multiple languages.

News:

  • [2022-04-08 Fri] Added support for displaying current language as color emoji in the mode line (requires Emacs 28.1 or later). See updated format of guess-language-langcodes. Old configurations should still work but won’t show color flags.

What is guess-language?

I write a lot of text in multiple languages and was getting tired of constantly having to switch the dictionary of my spell-checker. In true Emacs spirit, I decided to dust off my grandpa’s parentheses and wrote some code to address this problem. The result is guess-language-mode, a minor mode for Emacs that guesses the language of the current paragraph and then changes the dictionary of ispell and the language settings of typo-mode (if present). It also reruns Flyspell on the current paragraph, but only on that paragraph because I want to leave paragraphs in other languages untouched. Language guessing is triggered when Flyspell detects an unknown word, but only if the paragraph has enough material to allow for robust detection of the language (~ 35 characters).

Currently, the following languages are supported: Arabic, Czech, Danish, Dutch, English, Esperanto, Finnish, French, German, Italian, Norwegian, Polish, Portuguese, Russian, Serbian (Cyrillic and Latin), Slovak, Slovenian, Spanish, Swedish, Vietnamese.

It is easy to add more languages and this repository includes the necessary language statistics for 47 additional languages. (These were copied from guess_language.py.) If we already have the required language data (see directory trigrams), all you need to do is to add an entry to the variable guess-language-langcodes. See here for the commit that added support for Serbian. See the code of typo-mode to determine the quoting style needed for the language that you’re adding. An overview of quoting styles across languages can be found on Wikipedia. PRs adding new languages are welcome.

Prerequisites

This mode assumes that Flyspell is activated and configured for all relevant languages, i.e., those listed in guess-language-languages. If typo-mode is present, guess-language also changes the language there. Typo-mode is not a dependency, though.

Installation

Guess-language-mode is available through MELPA.

Configuration

Language settings

(require 'guess-language)

;; Optionally:
(setq guess-language-languages '(en de))
(setq guess-language-min-paragraph-length 35)

guess-language-languages defines the candidate languages that should be considered. It is recommended to only include languages that are actually used because this improves performance. Languages are identified using ISO 639-1 codes (see table below).

guess-language-min-paragraph-length specifies the minimal length that a paragraph needs to have before guess-language-mode starts guessing. Based on some informal tests texts shorter than 30 characters are not enough to give good results. However, above 40 characters the algorithm performs well. Of course, these numbers depend on the target language (some are easier to detect than others) and on the (number of) candidate languages that are considered. (Open the files in the directory testdata and do M-x guess-language-mark-lines to see for yourself.)

For each language, there is a default Ispell dictionary that guess-language-mode tries to use. However, for some languages there are several dictionaries available and guess-language can’t know which one you’d like to use. For example, there are several different dictionaries for German and for English. If the dictionary that guess-language-mode uses by default is not present, you will get an error message like the following:

Error in post-command-hook (flyspell-post-command-hook): (error "Undefined dictionary: en")

In this case, use the variable guess-language-langcodes to tell guess-language-mode which dictionary should be used instead. For example, use the following definition if you want to use British English and Swiss German:

(setq guess-language-langcodes
  '((en . ("en_GB" "English" "🇬🇧" "English"))
    (de . ("de_CH" "German" "🇨🇭" "Swiss German"))))

The key is a symbol specifying the ISO 639-1 code of the language. The values is a list with four elements. The first is the name of the dictionary that should be used by the spell-checker (e.g., what you would enter when setting the language with ispell-change-dictionary). The second element is the name of the language setting that should be used with typo-mode. If a language is not supported by typo-mode, that value is nil. The third element is a string for displaying the current language in the mode line. This could be text or a Unicode flag symbol (displayed as color emoji starting from Emacs 28.1). The last element is the name of the language for display in the mini buffer.

For a list of all dictionaries available for spell-checking, use the following:

(mapcar 'car ispell-dictionary-alist)

Languages that are currently supported by guess-language-mode:

LanguageIDO 639-1 codeDefault Ispell dictionaryDefault typo-mode setting
Arabicarar
CzechcsczechCzech
Danishdadansk
Dutchnlnederlands
EnglishenenEnglish
EsperantoeoesperantoEnglish
FinnishfifinnishFinnish
FrenchfrfrancaisFrench
GermandedeGerman
ItalianititalianoItalian
Norwegiannbnorsk
Polishplpolish
Portugueseptportuguese
RussianrurussianRussian
Serbian (Cyrillic)srserbianGerman (most similar to Serbian)
Serbian (Latin)srsr-latGerman (most similar to Serbian)
Slovakskslovak
Slovenianslslovenian
Spanishesspanish
Swedishsvsvenska
Vietnameseviviet

Custom functions to be run when a new language is detected

While changing the spell-checker’s dictionary is the main purpose of guess-language, there are other things that a user might want to do when a new language is detected, for instance, a user might want to change the input method. Things like that can be easily achieved by adding custom functions to the hook guess-language-after-detection-functions. Functions on this hook take three arguments:

LANGthe language that was detected
BEGINNINGthe beginning of the region in which the new language was detected
ENDthe end of the region

Template:

(defun my-custom-function (lang beginning end)
  (do-something))

(add-hook 'guess-language-after-detection-functions #'my-custom-function)

Usage

Activate guess-language-mode in the buffer in which you want to use it. To activate it automatically in buffers containing text (as opposed to code), add guess-language mode to text-mode-hook:

(add-hook 'text-mode-hook (lambda () (guess-language-mode 1)))

Changing the voice used by the Festival text-to-speech system

The code snipped below illustrates how guess-language can be configured to automatically change the voice used by the text-to-speech engine Festival (install festival.el for this to work):

(defun guess-language-switch-festival-function (lang beginning end)
  "Switch the voice used by festival.

LANG is the ISO 639-1 code of the language (as a
symbol).  BEGINNING and END are the endpoints of the region in
which LANG was detected but these are ignored."
  (when (and (featurep 'festival)
             (festivalp))
    (pcase lang
      ('en (festival-voice-english-female))
      ('de (festival-voice-german-female)))))

(add-hook 'guess-language-after-detection-functions #'guess-language-switch-festival-function)

The pcase needs to be modified to use the voices that are installed on your system. Refer to the documentation of Festival for details.

Changing the language of Synosaurus

Synosaurus is an Emacs package providing access to a German or English thesaurus. Using the code below the language of the thesaurus is automatically changed to the language of the current paragraph. Refer to the documentation of Synosaurus for details.

(defun guess-language-switch-synosaurus (lang beginning end)
  "Switch the thesaurus language.

LANG is the ISO 639-1 code of the language (as a
symbol).  BEGINNING and END are the endpoints of the region in
which LANG was detected.  These are ignored."
  (when (featurep 'synosaurus)
    (pcase lang
      ('en (setq synosaurus-backend 'synosaurus-backend-wordnet))
      ('de (setq synosaurus-backend 'synosaurus-backend-openthesaurus)))))

(add-hook 'guess-language-after-detection-functions #'guess-language-switch-synosaurus)

Notes

  • Support for Latin Serbian is based on trigrams transliterated from Cyrillic Serbian. Since some Cyrillic trigrams transliterate to 4-grams in Latin, we truncated those but as a result have two duplicates, “e n” and “ra “. Not ideal but the results are probably still robust enough. Nonetheless, it would be good if someone could compute proper Latin trigrams one day.

guess-language.el's People

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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

guess-language.el's Issues

Redundant aspell processes after magit-commit

Emacs -Q:

(progn
  (setq package-archives '(("gnu" . "https://elpa.gnu.org/packages/")
                           ("nongnu" . "https://elpa.nongnu.org/nongnu/")))
  (package-install 'magit)
  (package-install 'guess-language)
  (package-activate-all)

  (setq guess-language-languages '(en sl))
  (setq-default ispell-dictionary "slovenian")
  (add-hook 'text-mode-hook 'flyspell-mode)
  (add-hook 'flyspell-mode-hook 'guess-language-mode))

Each M-x magit-commit-create will leave an extra aspell process.
(A bit more info can be found on
http://debbugs.gnu.org/cgi/bugreport.cgi?bug=48379 )

Dutch ?

The table of languages that are currently supported by guess-language-mode mentions:
Dutch nl de

Should that not be Dutch nl nl_NL?

Updating version for GNU ELPA archive required

Hello!

Verison 0.0.1 of package guess-language in GNU ELPA archive is very old and have critical bug: recipe do not contain files from trigrams/ directory.

When guess-language-mode is activated, Emacs show error message:

Error in post-command-hook (flyspell-post-command-hook): (file-missing "Opening input file" "File or folder does not exists" "/home/dunaevsky/.emacs.d/elpa/guess-language-0.0.1/trigrams/en")

Please, update recipe for GNU ELPA archive.

Adding a language

I wandered if there is possibility that you add short explanation about adding other languages. It just say now that it's "easy to add", but I have no idea how to do that.
I'm specifically interested in Serbian, but I believe this explanation could be made general and of value to users of many other languages.
Thanks for the great package!

validate-setq on guess-language-langcodes

Hi,

just upgraded guess-language from MELPA. I have this snippet in my init file:

(use-package guess-language         ; Automatically detect language for Flyspell
  :ensure t
  :defer t
  :init (add-hook 'text-mode-hook #'guess-language-mode)
  :config
  (validate-setq guess-language-langcodes '((en . ("en_GB" "English"))
                                            (it . ("it_IT" "Italian")))
                 guess-language-languages '(en it)
                 guess-language-min-paragraph-length 45)
  :diminish guess-language-mode)

I get this warning upon restarting Emacs:

Error (use-package): guess-language :config: Looking for `(alist :key-type symbol :value-type ...)' in `((en "en_GB" "English") (it "it_IT" "Italian"))' failed because:
Looking for `(repeat (cons symbol list))' in `((en "en_GB" "English") (it "it_IT" "Italian"))' failed because:
Looking for `(cons symbol list)' in `(en "en_GB" "English")' failed because:
Looking for `list' in `("en_GB" "English")' failed because:
  wrong number of elements

I am using validate-setq from @Malabarba's validate to be sure I am setting the right values everywhere in my init file.

Everything's working fine with regular setq, so this is might not be related to your package.

Trigrams searched in wrong directory?

Hi, this looks like it's exactly the thing I've been looking for, but I'm having trouble setting it up. I installed the package and added the following to my init file:

(use-package guess-language
  :ensure t
  :init
  (add-hook 'text-mode-hook #'guess-language-mode)
  :diminish guess-language-mode)

But when I open a text file, flyspell doesn't work (even though I get a message about it starting up). The *Messages* buffer contains a message such as the following:

Error in post-command-hook (flyspell-post-command-hook): (file-error "Opening input file" "No such file or directory" "/home/joost/src/criticmarkup-emacs/trigrams/en")

The directory in the error message is the one containing the file I just opened.

Am I doing something wrong or is this a bug somewhere?

Display emoji symbols in mini buffer to indicate language

Country flags are not appropriate for some languages in which case we might want to show some other fancy unicode character. Motivation: The current language is difficult to spot in busy mode lines.

As far as I understand, Emacs currently lacks the necessary support for combined glyphs like 🇩🇪 (1F1E9 and 1F1EA unified), but in the future this will likely be possible.

Edit: Combined glyphs and native display of color emoji are supported as of version 28.1.

Add guess-language-after-autoset-hook

I started using this package, and I'm very happy with it. The language detection mechanisms works very well. Thanks!

One feature that I'm missing though is to perform additional actions after the language detection mechanism has finished executing. Usually when I switch from English to Danish dictionary I also set the input method to danish-postfix, which allows me to use the English (US) keyboard layout, while still being able to write Danish letters that are not available on the English keyboard layout. Setting the input method can be done like this:

M-x set-input-method RET danish-postfix RET

Now when I type "oe", Emacs changes it to "ø", "aa" becomes "å" and so on. The important thing, however, is that the keyboard layout remains the same.

Right now I have to change the input method manually every time guess-language switches dictionary. It would be better if guess-language could help me change the input method too. I tried to look for a hook that would allow me to run additional code when the dictionary changes (some ispell hook), but I couldn't really find a clever way to do this. Since other users of guess-language might want to perform a similar task I thought that adding a guess-language-after-autoset-hook would be a good idea (perhaps you can think of a better name)? The hook is intended to be run immediately before guess-language-autoset exits. What do you think?

Comparing this package with similar ones

I was looking for a package that would enable me to automatically switch the dictionary of my spell-checker. In addition to this package, I also found auto-dictionary-mode.

I think it would be helpful to add a small section in the README to explain the most important differences between this package and similar ones. It seems to me like this package and auto-dictionary-mode are trying to achieve the same goal. I'm interested in knowing what I gain by using this package in particular (rather than auto-dictionary-mode). Although auto-dictionary-mode does not seem to be actively maintained, it is quite popular (based on its number of downloads). Also, can you say anything about the performance of these two packages?

Thanks in advance.

Cursor jumps when text is analysed

I've noticed that the cursor jumps around while text is being analysed by guess-language. Although this is barely noticeable for small paragraphs, it becomes easier to see for larger ones. I've managed to produce this issue using a rather small Emacs configuration, which I store in ~/Desktop/tmp/init.el:

;; ~/Desktop/tmp/init.el
(package-initialize)

(autoload 'flyspell-mode "flyspell" t)
(setq ispell-dictionary "british")
(setq ispell-current-dictionary "british")
(add-hook 'text-mode-hook 'flyspell-mode)

(require 'guess-language)
(setq guess-language-languages '(en da))
(setq guess-language-min-paragraph-length 35)
(add-hook 'text-mode-hook (lambda () (guess-language-mode 1)))

Now, open an empty file (e.g. ~/Desktop/tmp/Demo.txt) in Emacs:

emacs -Q -l ~/Desktop/tmp/init.el ~/Desktop/tmp/Demo.txt

Initially, Emacs uses the british dictionary.

First, I start typing a Danish sentence. Eventually the number of characters becomes 35, which triggers the guess-language analysis. While the analysis is being performed, the cursors jumps between the "misspelled" words. Based on this analysis guess-language correctly switches the dictionary to danish.

Another way to make the cursor jump is by pasting a large chunk of text that contains several "misspelled" words (according to the current dictionary). For example by deleting the danish sentence, and pasting a large chunk of "Lorem Ipsum": since none of these words are included in the Danish dictionary this causes the cursor to jump a lot.

Below is a GIF that illustrates the scenario explained above:

optimised

I had to reduce the quality of the GIF - otherwise Github would not allow me to upload it. Let me know if the quality of the GIF is a problem.

System info:
GNU Emacs 26.0.50.2 (x86_64-pc-linux-gnu, GTK+ Version 3.18.9) of 2017-02-01
guess-language 20170204.311

Very slow in Org buffers

Hi,

I've been experiencing a terrible slow-down in Org buffers recently, especially when inside tables, but also just moving the cursor around partially collapsed headings. A quick profiling showed that guess-language is the culprit, especially the call to how-many in guess-language-region:

- flyspell-post-command-hook                                     2958  89%
 - flyspell-word                                                 2958  89%
  - flyspell-highlight-duplicate-region                          2940  88%
   - run-hook-with-args-until-success                            2940  88%
    - guess-language-function                                    2940  88%
     - guess-language                                            2940  88%
      - guess-language-region                                    2883  87%
         how-many                                                2883  87%
      + backward-paragraph                                         49   1%
      + forward-paragraph                                           8   0%
  + org-mode-flyspell-verify                                       18   0%
+ command-execute                                                 323   9%
+ yas--post-command-handler                                        14   0%
+ redisplay_internal (C function)                                   9   0%
+ timer-event-handler                                               3   0%
+ ...                                                               0   0%

It seems that the longer the Org file, the bigger the slow down. I'm guessing that this may be caused by the fact that backward-paragraph in an Org buffer may travel very far back: in one particular Org file of mine, it moves almost all the way to the beginning of the buffer.

I tried the obvious thing, i.e., use org-backward-paragraph and org-forward-paragraph in guess-language-paragraph if major-mode is org-mode, but that didn't seem to have much of an effect. Perhaps you know of a better way to deal with the issue?

Advantage from using local variables ?

Maybe add 'advantage of using local variables' in readme ?

e.g

;; Local Variables:
;; ispell-check-comments: exclusive
;; ispell-local-dictionary: "en"
%%% Local Variables:
%%% ispell-local-dictionary: "british"
%%% End:

org-mode - "Wrong type argument: number-or-marker-p, nil"

Hi there,

I've been experiencing some problems using guess-language and org-mode.

M-x guess-language in an org-file anywhere on the second line of the example below causes the error:

Wrong type argument: number-or-marker-p, nil.

  - First item. I'm just writing something longer so that the minimum
    number of characters is reached.

This problem also shows up (not always) when fly-spelling the whole buffer (M-x flyspell-buffer) stopping the verification before it reaches the end of the file.

My guess this error can be somewhat related to the (last part) of issue #17 (comment) and also commit 65dccb1 which deals with paragraph navigation in org-mode files.

Using:
Emacs 26.1
Org mode 9.1.14
guess-language head from git repository.

Debugger output:

Debugger entered--Lisp error: (wrong-type-argument number-or-marker-p nil)
  org-list-struct()
  guess-language-forward-paragraph()
  guess-language()
  funcall-interactively(guess-language)
  call-interactively(guess-language record nil)
  command-execute(guess-language record)
  helm-M-x(nil "guess-language")
  funcall-interactively(helm-M-x nil "guess-language")
  call-interactively(helm-M-x nil nil)
  command-execute(helm-M-x)

Please let me know if you need further info to pinpoint the error.

Possiblity to ignore certain lines

Some modes post content in the buffer that is read-only and not related to the actual content that the user writes.

For example in have or ERC/Circe the messages sent by other users or for Mastodon the same and the keybinds shown.

flyspell-large-region: Wrong type argument: stringp, nil

M-x flyspell-buffer fails with error flyspell-large-region: Wrong type argument: stringp, nil when guess-language-mode` is enabled. The major mode does not seem to be a factor to reproduce the error (it breaks in fundamental, text and org modes).

Steps to reproduce:

  • Download the latest guess-language version from git (currently bc6fe11) and place it in /tmp
$ cd /tmp/
$ git clone [email protected]:tmalsburg/guess-language.el.git
  • Start emacs with emacs -q
  • Run the following snippet to initialize guess-language (M-x eval-buffer in the scratch buffer):
(add-to-list 'load-path "/tmp/guess-language.el")
(load "guess-language")
     
(setq guess-language-languages '(en fr pt))
(setq guess-language-min-paragraph-length 35)
(setq guess-language-langcodes
      '((en . ("en_US" "English"))
        (fr . ("fr_FR" "French"))
        (pt . ("pt_BR" "Portuguese"))
        ))
  • Create a new buffer and paste the following text:
The following lines must be in a language different from the language of the first line to cause the bug.
The number of lines below seems to be the minimum necessary to make the bug manifest itself in my system.

Uma linha longa o suficiente para que o problema se manifeste.
Uma linha longa o suficiente para que o problema se manifeste.
Uma linha longa o suficiente para que o problema se manifeste.
Uma linha longa o suficiente para que o problema se manifeste.
Uma linha longa o suficiente para que o problema se manifeste.
Uma linha longa o suficiente para que o problema se manifeste.
Uma linha longa o suficiente para que o problema se manifeste.
Uma linha longa o suficiente para que o problema se manifeste.
Uma linha longa o suficiente para que o problema se manifeste.
Uma linha longa o suficiente para que o problema se manifeste.
Uma linha longa o suficiente para que o problema se manifeste.
Uma linha longa o suficiente para que o problema se manifeste.
Uma linha longa o suficiente para que o problema se manifeste.
Uma linha longa o suficiente para que o problema se manifeste.
Uma linha longa o suficiente para que o problema se manifeste.
Uma linha longa o suficiente para que o problema se manifeste.
  • Run M-x flyspell-buffer - Everything works as expected
  • Enable guess-language-mode M-x guess-language-mode
  • Run M-x flyspell-buffer - Flyspell terminates with the following error before the end of the spell checking: flyspell-large-region: Wrong type argument: stringp, nil

Full output of the messages buffer:

For information about GNU Emacs and the GNU system, type C-h C-a.
Mark set
Loading /tmp/guess-language.el/guess-language.el (source)...done
You can run the command ‘eval-buffer’ with M-x ev-b RET
Loading /tmp/guess-language.el/guess-language.el (source)...done
(New file)
Mark set
Starting new Ispell process /usr/bin/aspell with default dictionary...
Checking region...
Spell Checking...100% [manifeste]
Spell Checking completed.
You can run the command ‘flyspell-buffer’ with M-x fl-bu RET
Spell Checking completed.
Guess-Language mode enabled in current buffer
You can run the command ‘guess-language-mode’ with M-x gue-mo RET
Guess-Language mode enabled in current buffer
Checking region...
Ispell process killed
Local Ispell dictionary set to pt_BR
Starting new Ispell process /usr/bin/aspell with pt_BR dictionary...
Detected language: Portuguese
flyspell-large-region: Wrong type argument: stringp, nil

Debugger output:

Debugger entered--Lisp error: (wrong-type-argument stringp nil)
  flyspell-external-point-words()
  flyspell-large-region(1 1221)
  flyspell-region(1 1221)
  flyspell-buffer()
  funcall-interactively(flyspell-buffer)
  call-interactively(flyspell-buffer record nil)
  command-execute(flyspell-buffer record)
  execute-extended-command(nil "flyspell-buffer" "flyspell-bu")
  funcall-interactively(execute-extended-command nil "flyspell-buffer" "flyspell-bu")
  call-interactively(execute-extended-command nil nil)
  command-execute(execute-extended-command)

Emacs 26.1
guess-language from git (bc6fe11)

run-at-time

I was wondering what the rationale is behind the run-at-time at https://github.com/tmalsburg/guess-language.el/blob/master/guess-language.el#L247 ? I'm getting a lot of "Blocking call to accept-process-output with quit inhibited" as a result of this. This isn't so bad, but Emacs would also occasionally hang because two of those run-at-time at the same time seem to cause problems (?)

Just calling the body of that function locally seems to work, but I didn't extensively test it.

"advice" dependency not found

After some recent changes (d2a1330) guess-language depends on advice 0.1 package which is not on melpa, and consequently guess-language fails to build.

guess-language fail to start

When opening a text file, I get the following error

Error in post-command-hook (flyspell-post-command-hook): (wrong-type-argument symbolp (quote typo-mode))

Looking in the code I found a call (bound-and-true-p 'typo-mode) in the function guess-language-switch-typo-mode-function. Given that bound-and-true-p takes a symbol as argument this is obviously an error.

Removing the quote solves the problem for me

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.