Code Monkey home page Code Monkey logo

mormot's Introduction

  Synopse mORMot 1 Framework

An Open Source Client-Server ORM/SOA framework
 (c) 2008-2024 Synopse Informatique
  https://synopse.info
  http://mormot.net

=========  
 WARNING
=========
 This repository is now in "frozen/maintenance" mode. 
 Only SQLite3 static binaries and important bug fixes will be included in the future.
-----------------------------------------------------------------------------------------------
 Please consider using https://github.com/synopse/mORMot2 for any new or maintainable project.
-----------------------------------------------------------------------------------------------


Contributors
  Alan Chate
  Alexander (sha)
  Alexander (volax)
  AlexPirate
  Alfred Glaenzer (alf)
  Andre Heider (dhewg)
  Antoine Simard (AntoineGS)
  Arnaud Bouchez
  ASiwon
  Aweste
  Bas Schouten
  BigStar
  BugsDigger
  Cheemeng
  CoMPi
  Damien (ddemars)
  Darian Miller
  Daniel Kuettner
  David Mead (MDW)
  Delphinium (louisyeow)
  DigDiver
  Dominikcz
  EgorovAlex
  Emanuele (lele9)
  Eric Grange
  Esmond
  Esteban Martin (EMartin)
  Eugene Ilyin
  Eva Freimann (EVaF)
  FeelAirSlow
  F-Vicente
  Goran Despalatovic (gigo)
  Jean-Baptiste Roussia (jbroussia)
  Joe (jokusoft)
  Johan Bontes
  Jordi Tudela
  Kevin Chen
  Lagodny
  Leon Oosthuizen
  Macc2010
  Maciej Izak (hnb)
  Marcos Douglas B. Santos (mdbs99)
  Mario Moretti
  Marius Maximus (mariuszekpl)
  Martin Eckes
  Martin Suer
  Mapes
  Matkov
  Maxim Masiutin
  Mazinsw
  MChaos
  Miab3
  Michael (EgonHugeist)
  Michalis Kamburelis 
  MilesYou
  Mingda
  Mr Yang (ysair)
  Nicolas Marchand (MC)
  Nortg
  Nzsolt
  Oleg Tretyakov
  Ondrej (reddwarf)
  Pavel Mashlyakovskii (mpv)
  Pierre le Riche
  RalfS
  Richard6688
  Rik (rvk)
  Sabbiolina
  Sanyin
  Sinisa (sinisav)
  Sllimr7139
  SSoftPro
  Stefan (itSDS)
  Svetozar Belic (transmogrifix)
  Transmogrifix
  Uian2000
  Vaclav
  Vadim Orel
  Willo vd Merwe
  Win2014
  Wloochacz
  Wolfgang Ehrhardt
  Yoanq
  Ysair
  Zed

[See below if you upgrade from 1.17 revision]

  
Synopse mORMot is an Open Source Client-Server ORM SOA MVC framework
for Delphi 6 up to the latest Delphi and FPC revisions, targeting Windows/Linux
for servers, and any platform for clients (including mobile or AJAX).

The main features of mORMot are therefore:

 - ORM/ODM: objects persistence on almost any database (SQL or NoSQL);
 - SOA: organize your business logic into REST services;
 - Clients: consume your data or services from any platform, via ORM/SOA APIs;
 - Web MVC: publish your ORM/SOA process as responsive Web Applications.

With local or remote access, via an auto-configuring Client-Server REST design.

Due to its modular design, switch from a Client-Server architecture over
HTTP, named pipes or GDI messages into a stand-alone application is just
a matter of mORMot classes initialization.
For instance, the very same executable can even be running stand-alone,
as a server, as a service, or a client, depending on some run-time parameters!

Emphasizing simplicity, speed and versatility, mORMot is a incredibly well
documented Open Source project easy enough to add basic ORM or Client-Server
features to simple applications for hobbyists, or let experienced users
develop scaling and strong service-based projects for their customers, with
the advantages of native code and easy-to-deploy solutions, reducing
deployment cost and increasing ROI.

It provides an Open Source self-sufficient set of units (even Delphi starter
edition is enough) for creating any application, from a stand-alone solution
up to the most complex Domain-Driven Design (DDD):

 - Presentation layer featuring MVC UI generation with i18n and reporting
 (with pdf export) for rich Delphi clients, MVC web clients (with logic-less
 Mustache templates) or rich AJAX clients (via native JSON/REST access);

 - Application layer implementing Service Oriented Architecture via
 interface-based services (like WCF) and Client-Server ORM (including 
 method-based services) - following a RESTful model using JSON over several
 communication protocols (e.g. HTTP/1.1);

 - Domain Model layer handling all the needed business logic in plain Delphi
 objects, including high-level managed types like dynamic arrays or records
 for Value Objects, dedicated classes for Entities or Aggregates, and variant
 storage with late-binding for dynamic documents;

 - Data persistence infrastructure layer with ORM operations on direct
 Oracle, MS SQL, OleDB, ODBC, ZEOS/ZDBC access or any TDataSet provider (e.g.
 FireDAC/AnyDAC, UniDAC, NexusDB, BDE...), with a powerful SQLite3 kernel,
 and optional SQL access if needed, with amazing performance and advanced
 features like Array DML, auto-generating SQL for SQLite3, Oracle, 
 Jet/MSAccess, MS SQL, Firebird, DB2, PostgreSQL, MySQL and NexusDB - and
 alternative high-speed MongoDB NoSQL database access for ODM persistence;

 - Cross-Cutting infrastructure layers for handling data filtering and
 validation, security (e.g. Windows authentication or any custom model),
 caching, logging and testing (framework uses test-driven approach and
 features interface stubbing and mocking).

With mORMot, ORM/ODM is not used only for data persistence of objects (like
in other implementations), but as part of a global n-Tier, Service Oriented
Architecture (SOA), ready to implement Domain-Driven solutions. This
framework is not an ORM on which a transmission layer has been added, like
almost everything existing in Delphi, C# or Java: this is a full Client-Server 
ORM/SOA from the ground up.
This really makes the difference.

The business logic of your applications will be easily exposed as Services,
and will be accessible from light clients (written in Delphi or any other
mean, including AJAX).
The SpiderMonkey JavaScript engine has been integrated on the server side
and can be used to define business rules or any process (including MVC web
rendering) - just like node.js, but with a multi-threaded core, and the
full power of our optimized Delphi libraries at hand.

The framework Core is non-visual: you will get everything you need in a
consistent set of classes to be used from code. In order to let you focus
on your business, using mORMot's KISS/DRY/SOC/YAGNI/TDD and Convention Over
Configuration patterns. But you have also some UI units available (including
screen auto-generation, reporting and ribbon GUI), and you can use it from
any RAD, web, or AJAX clients (via JavaScript or Smart Mobile Studio).

No dependency is needed on the client side (no DB driver, or third-party
runtime): it is able to connect via standard HTTP, even through a corporate
proxy or a VPN. Rich Delphi clients can be deployed just by copying and running
a stand-alone small executable, with no installation process. Stream can be
encrypted via HTTS or with proven SHA/AES-256. Endpoints are configured
automatically for each published interface on both server and client sides,
and creating a load-balancing proxy is a matter of one method call.
Speed and scalability has been implemented from the ground up: a genuine
optimized multi-threaded core let a single server handle more than 50,000
concurrent clients, faster than DataSnap, WCF or node.js, and our rich SOA
design is able to implement both vertical and horizontal scalable hosting,
using recognized enterprise-level SQL or NoSQL databases for storage.

Even if mORMot will be more easily used in a project designed from scratch,
it fits very well the purpose of evolving any existing Delphi project, or
creating the server side part of an AJAX application.

Licensed under a disjunctive tri-license giving you the choice of one of
the three following sets of free software/open source licensing terms:
 - Mozilla Public License, version 1.1 or later;
 - GNU General Public License, version 2.0 or later;
 - GNU Lesser General Public License, version 2.1 or later.
This allows the use of our code in as wide a variety of software projects
as possible, while still maintaining copy-left on code we wrote.

Main project page:
http://mORMot.net

Documentation:
https://synopse.info/files/html/Synopse%20mORMot%20Framework%20SAD%201.18.html

Installation:
https://synopse.info/files/html/Synopse%20mORMot%20Framework%20SAD%201.18.html#TITL_113

FAQ:
https://synopse.info/files/html/Synopse%20mORMot%20Framework%20SAD%201.18.html#TITL_123

How to get the source:
https://synopse.info/fossil/wiki?name=Get+the+source

A forum is dedicated to support:
https://synopse.info

A blog is available:
http://blog.synopse.info

Issues and feature requests can be posted (take a look at the forums
and latest unstable version first!):
https://synopse.info/fossil/reportlist

You can also monitor/fork our projects on GitHub:
https://github.com/synopse/mORMot

You may also install it as a Delphinus package: Delphinus-Support

Don't forget to download the documentation (available online or as pdf files,
created by our SynProject tool).
In particular, you should take a look at all general introduction chapters
of the SAD document. It will cover all key-concepts and code modelling
used by the framework.
A developer guide is included in this SAD document, in its 2nd part. You'll
get good practice guidance, presentation of the ORM/SOA approach and other
underlying concepts.

Feel free to contribute by posting enhancements and patches to this
quickly evolving project.
  
Enjoy!


Some units (e.g. SynPdf, SynGdiPlus, SynBigTable, SynCommons, SynCrypto, 
SynDB*, SynSQLite3, SynMongoDB, SynMustache, SynSM, mORMotReport) are used 
by mORMot, but do not require the whole framework to be linked.
That is, you can use e.g. only  PDF generation, SynDB fast database
access, a static-linked SQLite3 engine, direct MongoDB access, Mustache
templates, SpiderMonkey JavaSCript engine, code-generated reports, or 
the TDocVariant, TDynArray, TSynLog classes of SynCommons, without using
the main mORMot units and features (ORM, Client-Server, services, UI).

Some of those units can even be compiled with Delphi 5 (e.g. SynPdf, SynDB).


Quick Steps when upgrading from a previous 1.17 revision:

1) Note that some units where renamed, and some breaking changes introduced
   by some enhanced features, therefore a direct update is not possible

2) Erase or rename your whole previous #\Lib directory

3) Download latest 1.18 revision files as stated just above
  
4) Change your references to mORMot units:
 - Add in your uses clause SynLog.pas and/or SynTests.pas if needed;
 - Rename in your uses clause any SQLite3Commons reference into mORmot;
 - Rename in your uses clause any SQLite3 reference into mORMotSQLite3;
 - Rename in your uses clause any other SQlite3* reference into mORMot*;
 - Add in one uses clause a link to SynSQLite3Static (for Win32).
 
5) Consult the units headers about 1.18 for breaking changes, mainly:
 - TSQLRecord.ID: TID primary key, TIDDynArray, and TRecordReference are now Int64;
 - Renamed Iso8601 low-level structure as TTimeLogBits;
 - TJSONSerializerCustomReader/Writer callbacks changed;
 - TSQLRestServerCallBackParams replaced by TSQLRestServerURIContext class;
 - TSQLRestServerStatic* classes renamed as TSQLRestStorage*;
 - rmJSON* enums replaced by TSQLRestRoutingREST/JSON_RPC classes;
 - Changed '¤' into '~' character for mORMoti18n language files.

mormot's People

Contributors

achechulin avatar algalg avatar asiwon avatar bi0t1n avatar danielkuettner avatar darianmiller avatar dependabot[bot] avatar devaex avatar dhewg avatar edwinyzh avatar eugeneilyin avatar f-vicente avatar leo-herrera avatar longdirtyanimalf avatar maciej-izak avatar mdbs99 avatar nortg avatar pavelmash avatar proholz avatar sakura1977 avatar ssoftpro avatar synopse avatar tcs-ulli avatar tim-lebedkov avatar wojtek-io avatar wxinix avatar yn0ga avatar yonojoy avatar ysair avatar zedxxx 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  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  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

mormot's Issues

Aplicativo fecha após erro não identificado no Windows 10 Pro versão 18363.900

Nossa empresa, Sysmo Sistemas, possui um aplicativo de frente de caixa o qual está se fechando após um processo de verificação de integridade da base de dados SQLite em alguns computadores com Windows 10 Pro versão 18363.900.

Código em Deplhi 6:

uses
  mORMot;

[...]

function TRgnSQLiteMaintenance.VerifyDatabaseIntegrity(AServerDatabase: TSQLRestServerDB): Boolean;
var
  oSQLTableJSON: TSQLTableJSON;
begin 
  try
    oSQLTableJSON := AServerDatabase.ExecuteList([], 'PRAGMA integrity_check');
    try
      Result := (oSQLTableJSON <> nil);

      if (Result) then
        Result := (LowerCase(String(oSQLTableJSON.GetS(1,0))) = 'ok');
    finally
      if (oSQLTableJSON <> nil) then
        FreeAndNil(oSQLTableJSON);
    end;
  except
    on E: Exception do
    begin
      Result := False;
      {$IFDEF VER140}
      if (Assigned(LogarErroGeral)) then
        LogarErroGeral('', 'TRgnSQLiteMaintenance.VerifyDatabaseIntegrity: Exception [' + E.Message + ']');
      {$ENDIF}
    end;
  end;
end;

Pelo que foi possível identificar pelos logs a aplicação se fechou quando executou o comando oSQLTableJSON.GetS(1,0).

Suspeitamos que ocorre alguma exceção no processo, mas não é gerada nehuma mensagem de erro e simplesmente fecha a aplicação.

Identificamos em alguns clientes com Windows 10 onde se caso dê alguma exceção no código e o mesmo não é tratado com try except a aplicação é fechada sem apresentar mensagem de erro.
Porém neste caso mesmo com o try except o erro persiste.

Não conseguimos simular internamente, somente em cliente.

Identificamos que em outros computadores com a mesma configuração e versão do Windows não acontece o problema.

Já foram adicionadas permissões de usuário para Controle total e colocado SSD, porém não obteve-se sucesso.

O erro registrado nos eventos do Windows foi:

Nome do Log:   Application
Fonte:         Application Error
Data:          11/06/2020 20:01:34
Identificação do Evento:1000
Categoria da Tarefa:(100)
Nível:         Erro
Palavras-chave:Clássico
Usuário:       N/D
Computador:    caixa01lj5
Descrição:
Nome do aplicativo com falha: pdv10.exe, versão: 3.9.20.3, carimbo de data/hora: 0x2a425e19
Nome do módulo com falha: unknown, versão: 0.0.0.0, carimbo de data/hora: 0x00000000
Código de exceção: 0xc0000005
Deslocamento da falha: 0x00000000
ID do processo com falha: 0xbe0
Hora de início do aplicativo com falha: 0x01d6402ff3dcb7b8
Caminho do aplicativo com falha: c:\pdv\pdv10.exe
Caminho do módulo com falha: unknown
ID do Relatório: 04ede662-fca9-47c6-bcc4-8882091f9ebe
Nome completo do pacote com falha: 
ID do aplicativo relativo ao pacote com falha: 
XML de Evento:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
  <System>
    <Provider Name="Application Error" />
    <EventID Qualifiers="0">1000</EventID>
    <Level>2</Level>
    <Task>100</Task>
    <Keywords>0x80000000000000</Keywords>
    <TimeCreated SystemTime="2020-06-11T23:01:34.725905000Z" />
    <EventRecordID>7199</EventRecordID>
    <Channel>Application</Channel>
    <Computer>caixa01lj5</Computer>
    <Security />
  </System>
  <EventData>
    <Data>pdv10.exe</Data>
    <Data>3.9.20.3</Data>
    <Data>2a425e19</Data>
    <Data>unknown</Data>
    <Data>0.0.0.0</Data>
    <Data>00000000</Data>
    <Data>c0000005</Data>
    <Data>00000000</Data>
    <Data>be0</Data>
    <Data>01d6402ff3dcb7b8</Data>
    <Data>c:\pdv\pdv10.exe</Data>
    <Data>unknown</Data>
    <Data>04ede662-fca9-47c6-bcc4-8882091f9ebe</Data>
    <Data>
    </Data>
    <Data>
    </Data>
  </EventData>
</Event>

Retrieve gets multiple records

According to the code (shortened for brevity):

   /// get a member from a SQL statement
    // [...]
    // - Execute 'SELECT * FROM TableName WHERE SQLWhere LIMIT 1' SQL Statememt
    // [...]
    function Retrieve(const SQLWhere: RawUTF8; Value: TSQLRecord;
      const aCustomFieldsCSV: RawUTF8=''): boolean; overload; virtual;

In the log files, I observe no "limit" clause. The method still works fine (I get the first record) but I worry a little bit about performance (there may be thousands of matching records).

20201212 15325432 SQL   	mORMotSQLite3.TSQLRestServerDB(0540a4a0) 203us returned 4 rows as 479 B SELECT ID,Sucursal,Terminal,Fecha,Folio,Total,Disponible,TrackId FROM StorageBoleta WHERE Disponible is NULL and Sucursal is NULL and Terminal is NULL

Is this by design?

Documentation example mistake ? 4.3.1. TList-like properties

Going through the documentation it seems that the examples at 4.3.1. TList-like properties has a mistake:

for i := GroupA.Count-1 downto 0 do
    if i and 3=0 then ///!!!!<<<< here it seems that it shoudl be "GroupA[3] = 0" or something similar
      GroupA.Delete(i); // delete integer at index i

I have modified/corrected some code but I can't share my work...

Hello, I have modified some units for Alexendria compatiblity and critical section approch bug.
Here my modification.

  • SynCrtSock : i have only move sone part of code to gain access to WinHttp.
  • SynCommons : use an Integer instead of boolean for fLocked and correct approch to TSynLocker.TryLock !!!
  • Synopse.inc : add support of Delphi 11.

mORMot.zip
.

No interpretation for error messages in SynCrtSock.SysErrorMessagePerModule on my machines

Hello,

My system is in french language and when a winhttp.dll error is raised in SynCrtSock, I only have the error code but no textual explanation.

May I suggest a slight modification in SynCrtSock ?
The function SysErrorMessagePerModule, could be modified to fall back to the default behaviour (cf. https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-formatmessage) if english langage is not available.
Moreover, it may also be useful to use the FORMAT_MESSAGE_IGNORE_INSERTS flag (cf. https://devblogs.microsoft.com/oldnewthing/20071128-00/?p=24353).

  tmpLen := FormatMessage(
    FORMAT_MESSAGE_FROM_HMODULE or FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_IGNORE_INSERTS,
    pointer(GetModuleHandle(ModuleName)),Code,ENGLISH_LANGID,@err,0,nil);
  // if string is empty, it may be because english is not found
  if (tmpLen = 0) then
     tmpLen := FormatMessage(
       FORMAT_MESSAGE_FROM_HMODULE or FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_IGNORE_INSERTS,
       pointer(GetModuleHandle(ModuleName)),Code,0,@err,0,nil);

Thank you !

Use fully qualified namespaces

At least on the Delphi side this is more and more considered best practice - and it is a pain to update these manually every time we update mORMot - hopefully this is the norm in mORMot2 - with all the other great "cleanups" :)

Thanks

Correct criticalsection managment and move some declaration to handle HttpAPI in Windows.

OK, I'me aware to use Git/TortoiseGit so I send an issue.

There is a problem in criticalsection mamagment so I change SynCommons.pas :

  • Replace fLocked to Integer frm boolean (to manage nested calls)
  • Correct function TSynLocker.TryLock function to NOT CHECK fLocked !

And I have move declaration and procedure to handle correctly SSL certificate (I create separate unit to do this) in SynCrtSock.pas

mORMot.zip

Update SynDB unit ( TQuery FPC compatibility )

I use Lazarus 2.0.10 with FPC 3.2.0.
While using mORMot with TQuery, I constat that the function

TQuery.FieldByName('ffield').AsString;
TQuery.FieldByName('ffield').AsWideString;

returns bad when it encounters accent characters ( é, à, è, ... ).
So I have bypassed this problem with the following modifications in the code in SynDB.pas :

function TQueryValue.GetAsWideString: SynUnicode;
begin
  CheckValue;
  with TVarData(fValue) do
  case VType of
    varNull:     result := '';
    varInt64:    result := UTF8ToSynUnicode(Int64ToUtf8(VInt64));
    {$ifdef fpc}
    varString:   result := WideString(RawUTF8(VAny));//UTF8ToSynUnicode(RawUTF8(VAny));
    {$else}
    varString:   result := UTF8ToSynUnicode(RawUTF8(VAny));
    {$endif}
    {$ifdef HASVARUSTRING}
    varUString:  result := UnicodeString(VAny);
    {$endif}
  else Result := SynUnicode(fValue);
  end;
end;  

and :

function TQueryValue.GetString: string;
begin
  CheckValue;
  with TVarData(fValue) do
  case VType of
    varNull:     result := '';
    varInteger:  result := IntToString(VInteger);
    varInt64:    result := IntToString(VInt64);
    varCurrency: result := Curr64ToString(VInt64);
    varDouble:   result := DoubleToString(VDouble);
    varDate:     result := Ansi7ToString(DateTimeToIso8601Text(VDate,' '));
    {$ifdef FPC}
    varString:   result := String(RawUTF8(VAny)); //UTF8ToString(RawUTF8(VAny));
    {$else}
    varString:   result := UTF8ToString(RawUTF8(VAny));
    {$endif}
    {$ifdef HASVARUSTRING}
    varUString:  result := string(UnicodeString(VAny));
    {$endif HASVARUSTRING}
    varOleStr:   result := string(WideString(VAny));
    else result := fValue;
  end;
end;       

So If you find that my corrections are correct, It will be geat to incorporaate them.
Thanks.

PS: github is not formatting code correctelly.

Endless recursive calls in SynCommons::FileSize

Converting the SQLite3/Samples/12 - SynDB Explorer/DBSynLZ.dpr to Lazarus and building it segfaults due to a endless recursive loop here:

function FileSize(F: THandle): Int64;
var res: Int64Rec absolute result;
begin
  result := 0;
  if PtrInt(F)>0 then
    res.Lo := FileSize(F); { *Converted from GetFileSize* } // from WinAPI or SynKylix/SynFPCLinux
end; 

Changing this line seem to fix the problem:

res.Lo := FileSize(F); { *Converted from GetFileSize* } // from WinAPI or SynKylix/SynFPCLinux

by:

res.Lo := GetFileSize(F, nil); { *Converted from GetFileSize* } // from WinAPI or SynKylix/SynFPCLinux

syncommons.pos is 5x slower than system.pos

Hi, I remembered Mormot had a faster Pos function. I was doing really a lot of Pos in some code while bruteforcing some compression code. Changing system.pos for syncommons.pos make it 5x slower. Both string and substring to search are declared as ansistrings.
Is this normal?

Problem in SynCrtSock.TWinHTTP.InternalSendRequest if the server asks for a client certificate

Hello,

I have a test server where https port is set to ask for a client certificate (it can be done via command line : netsh http add sslcert ipport=0.0.0.0:443 certhash=XXhashXX appid={XXappidXX} clientcertnegotiation=enable).

When I send an https request with THttpRequest.Request, I should have a 12044 error (ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED), but I have an error 12019 (ERROR_INTERNET_INCORRECT_HANDLE_STATE).
I think there is a problem with the conditions in procedure TWinHTTP.InternalSendRequest. I propose the following modification :

  L := length(aData);
  if not _SendRequest(L) or
     not WinHttpAPI.ReceiveResponse(fRequest,nil) then begin
    **if fHTTPS and IgnoreSSLCertificateErrors and (GetLastError=ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED) then begin**
      if not WinHttpAPI.SetOption(fRequest,WINHTTP_OPTION_SECURITY_FLAGS,
         @SECURITY_FLAT_IGNORE_CERTIFICATES,SizeOf(SECURITY_FLAT_IGNORE_CERTIFICATES)) then
        RaiseLastModuleError(winhttpdll,EWinHTTP);
      if not WinHttpAPI.SetOption(fRequest,WINHTTP_OPTION_CLIENT_CERT_CONTEXT,
         pointer(WINHTTP_NO_CLIENT_CERT_CONTEXT),0) then
        RaiseLastModuleError(winhttpdll,EWinHTTP);
      if not _SendRequest(L) or
         not WinHttpAPI.ReceiveResponse(fRequest,nil) then
        RaiseLastModuleError(winhttpdll,EWinHTTP);
    **end else
       RaiseLastModuleError(winhttpdll,EWinHTTP);**
  end;

Thank you !

function _PdfDateToDateTime in SynPdf.pas : Raise missing

in method :

function _PdfDateToDateTime(const AText: TPdfDate): TDateTime;
var Y,M,D, H,MI,SS: cardinal;
begin
if Length(AText)<16 then
EConvertError.CreateRes(@SDateEncodeError);
Y := ord(AText[3])*1000+ord(AText[4])*100+ord(AText[5])*10+ord(AText[6])
-(48+480+4800+48000);
M := ord(AText[7])*10+ord(AText[8])-(48+480);
D := ord(AText[9])*10+ord(AText[10])-(48+480);
result := EncodeDate(Y,M,D);
H := ord(AText[11])*10+ord(AText[12])-(48+480);
MI := ord(AText[13])*10+ord(AText[14])-(48+480);
SS := ord(AText[15])*10+ord(AText[16])-(48+480);
if (H<24) and (MI<60) and (SS<60) then // inlined EncodeTime()
result := result + (H * (MinsPerHour * SecsPerMin * MSecsPerSec) +
MI * (SecsPerMin * MSecsPerSec) + SS * MSecsPerSec) / MSecsPerDay else
EConvertError.CreateRes(@SDateEncodeError);
end;

Raise is missing .

correct code:

function _PdfDateToDateTime(const AText: TPdfDate): TDateTime;
var Y,M,D, H,MI,SS: cardinal;
begin
if Length(AText)<16 then
raise EConvertError.CreateRes(@SDateEncodeError);
Y := ord(AText[3])*1000+ord(AText[4])*100+ord(AText[5])*10+ord(AText[6])
-(48+480+4800+48000);
M := ord(AText[7])*10+ord(AText[8])-(48+480);
D := ord(AText[9])*10+ord(AText[10])-(48+480);
result := EncodeDate(Y,M,D);
H := ord(AText[11])*10+ord(AText[12])-(48+480);
MI := ord(AText[13])*10+ord(AText[14])-(48+480);
SS := ord(AText[15])*10+ord(AText[16])-(48+480);
if (H<24) and (MI<60) and (SS<60) then // inlined EncodeTime()
result := result + (H * (MinsPerHour * SecsPerMin * MSecsPerSec) +
MI * (SecsPerMin * MSecsPerSec) + SS * MSecsPerSec) / MSecsPerDay else
raise EConvertError.CreateRes(@SDateEncodeError);
end;

Infinite loop in SynZip UnCompress (Stream, Mem or ZipString)

Those functions currently contain an infinite loop for some special cases of compressed stream corruption, they have a repeat...until loop which looks like

    repeat
      code := Check(inflate(strm, Z_FINISH),[Z_OK,Z_STREAM_END,Z_BUF_ERROR],'UnCompressStream');
      FlushBuf;
    until code=Z_STREAM_END;

And Check() is thus set to accept Z_BUF_ERROR while the until test does not cover for the case when FlushBuf will not handle it.

To reproduce run the following code on the deflate.bomb file that is inside the attached zip. The issue occurs on both Win32 and Win64.

var
   f : TFileStream;
   buf : TBytes;
   outBuf : ZipString;
begin
   f := TFileStream.Create('c:\temp\deflate.bomb', fmOpenRead);
   SetLength(buf, f.Size);
   f.Read(buf[0], f.Size);
   UnCompressZipString(Pointer(buf), f.Size, outBuf, nil, False, 64*1024);  // never ends
end.

deflate.bomb.zip

CreateMissingTables

After updating to the 07/07/2020 version, an error occurs in the ".CreateMissingTables" method when creating tables with non-lowercase names.
Example:
testtest OK
testTest Error

THttpApiWebSocketConnection.PrivateData Property value cannot be set.

procedure TForm1.OnDisconnect(const Conn: THttpApiWebSocketConnection;
  aStatus: WEB_SOCKET_CLOSE_STATUS; aBuffer: Pointer; aBufferSize: Cardinal);
begin
  if Assigned(Conn.PrivateData) then
  begin
    //Conn.PrivateData  :=  nil;  //compile error: E2064 Left side cannot be assigned to
    PHttpApiWebSocketConnection(@Conn).PrivateData  :=  nil;
  end;
  TSynLog.Add.Log(sllInfo, '% - disconnect', [Conn.Index]);
end;

Can I change it to

THttpApiWebSocketConnection = record
...
property PrivateData: pointer read fPrivateData write fPrivateData; // write SetPrivateData?

AV exception raised when SQL user login failed. SynDB

I tried the code:
aConProp:=TSQLDBZEOSConnectionProperties.Create(
TSQLDBZEOSConnectionProperties.URI('OleDB[mssql]', '', ''),
Format(csConStr,[aSQLServer,aDatabase]),aLogin,aPWD);
try
aStmt:=aConProp.NewThreadSafeStatementPrepared(csSQL,True,True);
aStmt.Bind([aUserID]);
aStmt.ExecutePrepared;
if aStmt.Step then
aName:=aStmt.ColumnString(0);
except
On E: Exception do begin
TSynLog.Add.Log(sllServer,'Connect failed :% ',[E.Message]);
raise
end;
end;

It shows AV message instead of "OLEDB Error 80040E4D: SQLState: Login failed for user..." when user login denied.

I noticed when login denied the Stmt instance will be nil but still be referenced in exception block.

I revised TryPrepare procedure exception block like below and then works fine. Hope this can help.

procedure TryPrepare(doraise: boolean);
var Stmt: TSQLDBStatement;
begin
....
except
on E: Exception do begin
StringToUTF8(E.Message,fErrorMessage);
fErrorException := PPointer(E)^;
if assigned(Stmt) then begin
{$ifndef SYNDB_SILENCE}
with SynDBLog.Add do
if [sllSQL,sllDB,sllException,sllError]*Family.Level<>[] then
LogLines(sllSQL,pointer(Stmt.SQLWithInlinedParams),self,'--');
{$endif}
Stmt.Free;
end else
with SynDBLog.Add do
if [sllSQL,sllDB,sllException,sllError]*Family.Level<>[] then
LogLines(sllSQL,pointer(fErrorMessage),self,'--');
result := nil;
if doraise then
raise;
end;

Revert the pull request 46

The change in pull request 46 seems to be invalid: synopse/SynPDF#46

Here is the code I used to test this.

The output was:
MS Sans Serif 2
Microsoft Sans Serif 2
Courier New 1
Courier 1

This means that "(ALogFont.lfPitchAndFamily and 3) = FIXED_PITCH" would evaluate for the parameter AIsFixedWidth to

MS Sans Serif 2 => False
Microsoft Sans Serif 2 => False
Courier New 1 => True
Courier 1 => True

This is correct.

@maykon-t can you test on your computer?

// JCL_DEBUG_EXPERT_GENERATEJDBG OFF
program TestFonts;

{$APPTYPE CONSOLE}

{$R *.res}

uses
    System.SysUtils, Windows;

function EnumFontsProc(var LogFont: TLogFont; var TextMetric: TTextMetric;
    FontType: Integer; Data: Pointer): Integer; stdcall;
begin
    WriteLn(string(LogFont.lfFaceName), ' ', LogFont.lfPitchAndFamily and 3);

    Result := 1;
end;

var
    DC: HDC;
    F: LOGFONTW;
begin
    DC := GetDC(0);
    try
        FillChar(F, sizeof(F), 0);
        F.lfCharset := DEFAULT_CHARSET;
        EnumFontFamiliesEx(DC, F, @EnumFontsProc, 0, 0);
    finally
        ReleaseDC(0, DC);
    end;
    ReadLn;
end.

Delphi 2007: not defined USHORT

SynCrtSock.pas - not defined USHORT for old delphi

Fix:
PackageNameLength: {+}{$if declared(USHORT)}USHORT{$else}Word{$ifend}{+.};

Socket based server don't handle compressed chunked encoding

In case client transfer body in compressed chunked format:

Transfer-Encoding: gzip, chunked

THttpSocket.GetHeader don't recognize neither this is chunked encoding nor chunks is compressed

We can delay this issue since for a while I have not met such requests in the real life..

The last ')' is missed.

When did something like this:
TSQLSampleRecord.AutoFree(Rec, Database, '(ID in (1,2) or ID in (3,4))', []);
the sql clause became: 'select ID,Time,Name,Question from SampleRecord where (ID in (1,2) or ID in (3,4)'. I fixed it like this (SynTable.pas, GetWhereExpression):

'n','N': begin
Where.Operator := opIn;
P := GotoNextNotSpace(P+2);
if P^<>'(' then
exit; // incorrect SQL statement
B := P; // get the IN() clause as JSON
inc(P);
while (P^<>')') or (P[1]=':') do // handle :(...): within the clause
if P^=#0 then
exit else
inc(P);
inc(P);
SetString(Where.Value,PAnsiChar(B),P-B);
Where.ValueSQL := B;
Where.ValueSQLLen := P-B;
result := GetWhereValues(Where);
P := GotoNextNotSpace(P);
if (P^=')') and (Where.FunctionName='') then begin
B := P;
repeat
inc(P);
until not (P^ in [#1..' ',')']);
while P[-1]=' ' do dec(P); // trim right space
SetString(Where.ParenthesisAfter,B,P-B);
P := GotoNextNotSpace(P);
end;

exit;
end;

JSONReformat output is not correct

The output of this JSON format with some special characters is incorrect and truncated, but it can be correctly formatted in vscode. This should be a correct JSON:

{"id":{"$oid":"5f51f7fc1a313f6ce3535b77"},"@timestamp" :"2020-09-03T03:16:17.137Z","log" : {"offset" :543391,"file" : {"path" :"C:\Program Files\rempl\Logs\Remediation.011.etl"}},"message" :"CV'#0#2'SetDisableUXWUAccess'#0#1'DoNotConnectToWindowsUpdate'#0#1'NoAutoUpdate'#0#1'AuOptions'#0#1'isRegisteredWithMU'#0#7'isRegisteredWithWU'#0#7'isRegisteredWithWS'#0#7'isRegisteredWithDCAT'#0#7'isRegisteredWithOther'#0#7'2'#0'0'#0'1'#0'8'#0'.'#0'3'#0'C'#0#0#0'�'#2#0#0#0#0#0#0'mnM5lRlFzUSYZhmx.0'#0'K'#0'E'#0'Y'#0''#0'N'#0'O'#0'T'#0''#0'F'#0'O'#0'U'#0'N'#0'D'#0#0#0'K'#0'E'#0'Y'#0''#0'N'#0'O'#0'T'#0''#0'F'#0'O'#0'U'#0'N'#0'D'#0#0#0'K'#0'E'#0'Y'#0''#0'N'#0'O'#0'T'#0''#0'F'#0'O'#0'U'#0'N'#0'D'#0#0#0'K'#0'E'#0'Y'#0''#0'N'#0'O'#0'T'#0'_'#0'F'#0'O'#0'U'#0'N'#0'D'#0#0#0#0#0#0#0#1#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0'eY'#7#$13'�'#1#0#0#0'��'#1#0'��'#1#0'F�'#3'�'#1#0#0#0#$1C'9&tBsKB�C��8m^��7'#0#$B#1#0#0#0#1#0#0#0#0'�'#0#0#4#0#0#0#3#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'@'#0#$C#0#1#0'3'#0'3'#0'Microsoft.Windows.Remediation'#0#$13#0#1#$1A'sPO蠅�G�����'#4'v�'#0#0#0#0#0'�'#3#$B#0#0#0'�'#3'�'#3'","input" : {"type" :"log"},"agent" : {"name" :"XLY-LIURONG","type" :"filebeat","version" :"7.9.0","hostname" :"XLY-LIURONG","ephemeral_id" :"e3a78cca-67a7-4b7f-a7fd-bee382589b49","id" :"f39d3911-acef-44f7-bfff-08c9bd2e2ef8"},"ecs" : {"version" :"1.5.0"},"host" : {"os" : {"platform" :"windows","version" :"10.0","family" :"windows","name" :"Windows 10 Education","kernel" :"10.0.17134.1667 (WinBuild.160101.0800)","build" :"17134.1667"},"id" :"b2789ed2-a7cd-49e9-8a58-4229c1e43034","ip" : ["fe80::2094:8e7e:e734:8fb9","192.168.0.52","fe80::69e5:ad7c:10c1:586a","169.254.88.106","fe80::d5e7:eedf:d448:d6f5","192.168.202.1","fe80::15d5:993:d2d2:54d3","192.168.40.1"],"name" :"XLY-LIURONG","mac" : ["34:97:f6:29:8e:76","0a:00:27:00:00:13","00:50:56:c0:00:01","00:50:56:c0:00:08"],"hostname" :"XLY-LIURONG","architecture" :"x86_64"}}

mORMot master, Delphi 10.2.3, Win 10 LTSC 2019
I'm sorry,I can't reproduce this problem. It seems to only appear in my program. When I copy the JSON into a file and read it from the file, it is properly formatted!

beforeFormat
afterReformat

Fatal Error (Exception External:?) after second exception in Interfaced based Services

Scenario:
Windows 10, 64 bit Lazarus 2.2.2, 64 bit Freepascal 3.2.2
Sample 14 - Interfaced based services

In Project14ServerHttp.dpr
Change the method 'Add' by inserting an exception:
function TServiceCalculator.Add(n1, n2: integer): integer;
begin
result := n1+n2;
raise Exception.Create('Test'); // <<< insert this exception
end;

In browser type:
http://localhost:8888/root/calculator/add?n1=1&n2=2
The first execution is ok, the exception is showed correctly
but execute again... the server goes down with the message... >>> Fatal error, External Exception: ?

BatchSend mistakenly strips off millisecond part of TDateTimeMS

TDateTimeMS type is supposed to have a millisecond part, when adding to an external database (e.g., PostgreSQL).

It works as expected if the record is added individually using the Add method.

Howerver, when BatchAdd, mORMot will mistakenly strip off the millisecond part of TDateTimeMS field inside method TSQLDBStatementWithParams.BindArray , Line 7891-7896, of SynDB.pas:

if (ParamType=ftDate) and (ChangeFirstChar<>'T') then
    for i := 0 to ValuesCount-1 do // fix e.g. for PostgreSQL
      if (p^.VArray[i]<>'') and (p^.VArray[i][1]='''') then begin
        v.From(PUTF8Char(pointer(p^.VArray[i]))+1,length(p^.VArray[i])-2);
        p^.VArray[i] := v.FullText({expanded=}true,ChangeFirstChar,'''');
      end;

I also checked the mORMot-generated SQL query sent to the database engine., which confirmed the above issue.

Can you please double check? Thanks.

Lack of explanation in case of WinHttp security error in SynCrtSock

Hello,

If I use SyCrtSock's THttpRequest.Request to make an https request to an url with a machine name only, without the domain information, there is obviously a security error because the CN is invalid.
But the error message contains only the error code and is thus hard to understand : "WinHTTP security error. Status 65536, statusInfo: 16".
Could the procedure WinHTTPSecurityErrorCallback be enhanced to give more explanation, for example :

procedure WinHTTPSecurityErrorCallback(hInternet: HINTERNET; dwContext: PDWORD;
  dwInternetStatus: DWORD; lpvStatusInformation: pointer; dwStatusInformationLength: DWORD); stdcall;
var
   err : String;
   code : DWORD;
begin
  code := pdword(lpvStatusInformation)^;
  err := '';
  if code and $00000001 > 0 then err := err + 'WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED | ';
  if code and $00000002 > 0 then err := err + 'WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT | ';
  if code and $00000004 > 0 then err := err + 'WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED | ';
  if code and $00000008 > 0 then err := err + 'WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA | ';
  if code and $00000010 > 0 then err := err + 'WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID | ';
  if code and $00000020 > 0 then err := err + 'WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID | ';
  if code and $00000040 > 0 then err := err + 'WINHTTP_CALLBACK_STATUS_FLAG_CERT_WRONG_USAGE | ';
  if code and $80000000 > 0 then err := err + 'WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR | ';
  if err <> '' then err := ': ' + Copy(err, 1, Length(err) - 3);
  // in case lpvStatusInformation^=-2147483648 this is attempt to connect to
  // non-https socket wrong port - perhaps must be 443?
  raise EWinHTTP.CreateFmt('WinHTTP security error. Status %d, statusInfo: %d (%s)',
    [dwInternetStatus, code, '$' + IntToHex(code, 8) + err]);
end;

Thank you !

PasZip.pas wrongly decompress a .zip as empty files

I'm using Delphi 7 and with the following function the attached zip is decompressed as two 0-bytes files (all other zip decompressors correctly decompress them as two non-empty files):

function UnzipFile(sSrcPathName: string; sDestPath: string): boolean;
var zip: TZipRead;
iCont: integer;
begin
result:= false;

zip:= TZipRead.Create(sSrcPathName, 0, 0, {ShowMessageBoxOnError=} true);
try
    for iCont:= 0 to zip.Count-1 do
        if not zip.UnZipFile(iCont, sDestPath, {ForceWriteFlush=} true) then
            exit;
finally
    zip.Free;
end;

result:= true;

end;

Test.zip

Memory Leak on RemoteDB

Hi,
While trying to connect to Shutdown RemoteDB server an exception is raised ( witch is normal ) but with memory leak while closing the application.
Try to execute this little application.

I use lazarus-2.0.12 fpc-3.2.2

testExcepCnt.zip

Feature request: Update zlib static libraries for faster decompression

When using with FPC+Win64 SynZip.pas will link static\x86_64-win64sse*.o static libraries, providing access to the accelerated CloudFlare zlib. Can I suggest that the static libraries included with this repository are updated to the latest version of CloudFlare. A recently merged pull request has made the CloudFlare zlib ~33% faster at decompressing files.

How to install mORMot in lazarus-2.0.6-fpc-3.0.4-win64?

Compile package mormot_base 1.18: Exit code 1, Errors: 8, Warnings: 3
SynCommons.pas(7332,23) Warning: Some fields coming after "" were not initialized
SynCommons.pas(13807,42) Warning: Some fields coming after "VType" were not initialized
SynCommons.pas(15370,56) Warning: Some fields coming after "VOptions" were not initialized
SynFPCTypInfo.pas(91,31) Error: Identifier not found "PInterfaceData"
SynFPCTypInfo.pas(91,45) Error: Error in type definition
SynFPCTypInfo.pas(92,32) Error: Identifier not found "PVmtMethodParam"
SynFPCTypInfo.pas(92,47) Error: Error in type definition
SynFPCTypInfo.pas(93,33) Error: Identifier not found "PIntfMethodTable"
SynFPCTypInfo.pas(93,49) Error: Error in type definition
SynFPCTypInfo.pas(94,33) Error: Identifier not found "PIntfMethodEntry"
SynFPCTypInfo.pas(94,49) Error: Error in type definition

Bufferoverread for THttpServerRequest.FullUrl

Hey,
i used the THttpApiServer from current master branch, and attached a OnRequest handler.
I had to notice that a bufferoverread happens for the FullUrl from THttpServerRequest. This is only the case for THttpServerRequest.FullUrl, THttpServerRequest.Url is correct.

image

Since the nullterminator is correct there, i current work around that by using Split([#0])[0]

Declaration of "ConvertToEmfPlus" is not 64 bit safe

SysGdiPlus.pas; line 628ff:

fConvertToEmfPlus: function(graphics, image: THandle; var flag: BOOL;
emftype: TEmfType; description: PWideChar; var out_metafile: integer): TGdipStatus; stdcall;

The out_metafile type must be THandle (or NativeUInt) to be 64 bit save. The current declaration leads to access violations in 64 bit applications. Also the declarion for "EmfPlusImg" in function TGDIPlusFull.ConvertToEmfPlus must be changed to THandle.

64 bit Mustache SynCommons compiler error

this declaration generated error:

  THeapMemoryStream = class(TMemoryStream)
  protected
    function Realloc(var NewCapacity: longint): Pointer; override;
  end;

[dcc64 Error] SynCommons.pas(13427): E2037 Declaration of 'Realloc' differs from previous declaration
longint vs NativeInt. It should be declared as:

THeapMemoryStream = class(TMemoryStream)
protected
  function Realloc(var NewCapacity: NativeInt): Pointer; override;
end;

SynDBUniDAC.pas has errors

  1. The interface USES section should include SynTable and SynOleDB - these two are missing.
  2. Line 287 missing the ; statement terminator
    meta.Restrictions.Values['TABLE_SCHEMA'] := UTF8ToString(UpperCase(Owner))

It won't compile without the above fix.

why cannot run the same SQLite on Linux at the same time

I use Delphi program to open SQLite database with TSQLRestServerDB. Lockingmode: = lmnormal. The compiler runs on Linux. When the second program is opened, an error is reported: esqlite3exception {"errorcode": 26, "sqlite3errorcode": "secnotadb", "message": "error sqlite_notadb (26) [dbopen] using 3.34.1 with ADB = nil"}.

But it is possible to run on windows.

What is the matter? How should it be solved?

Missing types from generated wrapper

With latest versions, I face some issues when generating code wrappers to access my SOA interfaces.

Some types are missing from methods' signature.

e.g.

function ValidateUserLogin(const inUserName, inUserPassword: String; out outUserInfo: TMyUserInfo): Boolean;

is wrapped as

function ValidateUserLogin(const inUserName, inUserPassword: String; out outUserInfo: ): Boolean;

After narrowing the issue with git bisect, it seems I found the culprit.

in SQLite3/mORMotWrappers.pas, inside TWrapperContext.ContextFromInfo(), around line 948

trimcopy(typName,i+1,maxInt,typName);

the same string is passed as const & out parameter and gets cleared when entering trimcopy.

FYI I'm using delphi 10.1

all the best
Sylvain

Strange behaviour

Hello.
I have the following problem.I compile and run mormot http server on port X using delphi 10.4.1.
When I start accidentally 2 http servers on the same port, mormot allows me to do that.
The exception is raised, but it somehow is ignored.
Is it an intended behaviour? Can I somehow check in my code, that mormot http server was started succefully?

Thank You.

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.