Jump to content

lynkfs

Moderators
  • Content Count

    743
  • Joined

  • Last visited

  • Days Won

    146

Reputation Activity

  1. Like
    lynkfs got a reaction from Czar in Quantum computing with Smart   
    Is it possible to do a bit of quantum computing using SMS ?
    The answer looks to be yes, using IBM's quantum computer resources which are partly made available for developers
    Basics first : IBM has released it's SDK to program these quantum computers using a visual composer, Python, a proprietary assembler QASM format and some run and execute utilities.
    There is however a second way of using its quantum resources, using the entry-points of is Q-experience REST server. Most if not all of the visual composer functions can be done by ajax-calls !
    To demonstrate : the first thing is to acquire an api-token. 
    (Create an account on https://quantumexperience.ng.bluemix.net/qx/experience. Log in and navigate to the Composer. Username > My Account, and then Advanced on the upper right. Then generate API Token. Api Tokens are personal and are not supposed to be shared.)
    The next thing is to generate a session token (access token). This can be done in code.
    This screenshot
     
    shows a couple of these REST server calls and its results :
    The first button (get access) generates a session token The second button queries which quantum computers are available, how many qubits can be used, if it is online and what type of system it is. Current results show 3 quantum systems - 2 real ones and 1 simulator The third button (current Temp) gives some processor info of the selected system. In this case the current temperature in Kelvin : the Melbourne processor is cooled to just above the absolute minimum. Next : the next button to implement will be to submit some code to one of the available processors for processing. Below is the project code for these REST calls
    unit Form1; interface uses    System.Types,   System.Types.Convert,   System.Objects,   System.Time,   SmartCL.System,   SmartCL.Time,   SmartCL.Graphics,   SmartCL.Components,   SmartCL.FileUtils,   SmartCL.Forms,   SmartCL.Fonts,   SmartCL.Theme,   SmartCL.Borders,   SmartCL.Application, SmartCL.Net.Http, ECMA.Json, SmartCL.Controls.Button,   SmartCL.Controls.Label, HTMLTableElement, SmartCL.Controls.ScrollBox,   SmartCL.Controls.Panel, SmartCL.Controls.ComboBox; type   TForm1 = class(TW3Form)     procedure W3Button3Click(Sender: TObject);     procedure W3Button2Click(Sender: TObject);     procedure W3Button1Click(Sender: TObject);   private     {$I 'Form1:intf'}   protected     procedure InitializeForm; override;     procedure InitializeObject; override;     procedure Resize; override;     DBRows : integer := 0;     FHttp : TW3HttpRequest;     smscursor: variant;     procedure GetAccessToken(Sender: TW3HttpRequest);     procedure ListAvailableSystems(Sender: TW3HttpRequest);     procedure GetTempKelvin(Sender: TW3HttpRequest);     AccessToken : string;   end; implementation { TForm1 } procedure TForm1.InitializeForm; begin   inherited;   // this is a good place to initialize components end; procedure TForm1.InitializeObject; begin   inherited;   {$I 'Form1:impl'} end; { Button1 } procedure TForm1.W3Button1Click(Sender: TObject); begin //Get Access Token   var FHttp := TW3HttpRequest.Create;   FHttp.OnDataReady := GetAccessToken;   FHttp.open("POST",'https://quantumexperience.ng.bluemix.net/api/users/loginWithToken');   FHttp.RequestHeaders.Add("Content-type","application/json");   var api : variant := new JObject;   api.apiToken := TString.encodeURIComponent('a59d26ebf........1d6d6d4a28c430b5336aba');   FHttp.send(json.stringify(api)); end; procedure TForm1.GetAccessToken(Sender: TW3HttpRequest); begin   smscursor := JSON.parse(Sender.ResponseText);   AccessToken := smscursor.id;   W3Label1.Caption:= 'Access Token : ' + AccessToken; end; { Button2 } procedure TForm1.W3Button2Click(Sender: TObject); begin //List available Q systems   var FHttp := TW3HttpRequest.Create;   FHttp.OnDataReady := ListAvailableSystems;   FHttp.open("GET",'https://quantumexperience.ng.bluemix.net/api/Backends?access_token=' + AccessToken);   FHttp.RequestHeaders.Add("Content-type","application/json");   FHttp.send; end; procedure TForm1.ListAvailableSystems(Sender: TW3HttpRequest); begin   var W3TableElement1 : TW3TableElement := TW3TableElement.Create(W3Panel1); //add 5 columns to the grid   W3TableElement1.AddColumn('Name',200);      //title, width   W3TableElement1.AddColumn('Description',200);   W3TableElement1.AddColumn('Qubits',50);   W3TableElement1.AddColumn('System type',150);   W3TableElement1.AddColumn('Status',50);   smscursor := JSON.parse(Sender.ResponseText);   W3ComboBox1.Clear;   for var i := 0 to smscursor.length -1 do begin     W3TableElement1.AddCell(i+1,1,smscursor[i].name);     W3TableElement1.AddCell(i+1,2,smscursor[i].description);     W3TableElement1.AddCell(i+1,3,smscursor[i].nQubits);     if smscursor[i].simulator = true       then W3TableElement1.AddCell(i+1,4,'quantum simulator')       else W3TableElement1.AddCell(i+1,4,'quantum system');     W3TableElement1.AddCell(i+1,5,smscursor[i].status);     W3ComboBox1.add(smscursor[i].name);   end;   W3Panel1.NativeScrolling := true;   W3ComboBox1.OnChanged := procedure (Sender: TObject)   begin     writeln(W3ComboBox1.Items[W3ComboBox1.SelectedIndex]);   end; end; { Button3 } procedure TForm1.W3Button3Click(Sender: TObject); begin //Get Temp   var FHttp := TW3HttpRequest.Create;   FHttp.OnDataReady := GetTempKelvin;   //'https://quantumexperience.ng.bluemix.net/api/Backends/NAME/parameters?access_token=ACCESS-TOKEN';   FHttp.open("GET",'https://quantumexperience.ng.bluemix.net/api/Backends/' +                    W3ComboBox1.Items[W3ComboBox1.SelectedIndex] +                    '/parameters?access_token=' +                    AccessToken);   FHttp.RequestHeaders.Add("Content-type","application/json");   FHttp.send; end; procedure TForm1.GetTempKelvin(Sender: TW3HttpRequest); begin   If Sender.ResponseText = '{}' then   begin     W3Label3.Caption := 'Simulators are not cooled to (close to) absolute minimum';   end else   begin     smscursor := JSON.parse(Sender.ResponseText);     if smscursor.fridgeParameters.Temperature.value = ''       then W3Label3.Caption := 'Processor does not support Temp reading'       else W3Label3.Caption:= 'Current Temp : ' + smscursor.fridgeParameters.Temperature.value + ' Kelvin';   end; end; procedure TForm1.Resize; begin   inherited; end;   initialization   Forms.RegisterForm({$I %FILE%}, TForm1); end.  
    In the end hopefully it will be possible to recreate the classic Battleships game using quantum computing, as described here
     
     
     
  2. Like
    lynkfs got a reaction from jarto in table grid   
    the simplest of grids, based on the html <table> element

    usage
      var W3TableElement1 : TW3TableElement := TW3TableElement.Create(W3Panel1); //add 4 columns to the grid   W3TableElement1.AddColumn('Name',200);      //title, width   W3TableElement1.AddColumn('Description',200);   W3TableElement1.AddColumn('Type',150);   W3TableElement1.AddColumn('Status',50);   for var i := 0 to 2 do begin     W3TableElement1.AddCell(i+1,1,'Name-'+inttostr(i)); //row,column,text     W3TableElement1.AddCell(i+1,2,'Desc-'+inttostr(i));     W3TableElement1.AddCell(i+1,3,'Type-'+inttostr(i));     W3TableElement1.AddCell(i+1,4,'Stat-'+inttostr(i));   end; W3Panel1.NativeScrolling := true;  
    component
    unit HTMLTableElement; interface uses   SmartCL.System, System.Types, SmartCL.Components; type   TW3TableElement = class(TW3CustomControl)   protected     function  MakeElementTagObj : THandle; override;     TableRow    : Variant;   public     procedure AddColumn(title: string; colwidth: integer);     procedure AddCell(row, column: integer; cell: String);     ColumnCount : integer := 0;     RowCount    : integer := 0;   end; implementation { TW3TableElement } function TW3TableElement.MakeElementTagObj : THandle; begin   Result := w3_createHtmlElement('table'); end; procedure TW3TableElement.AddColumn(title: string; colwidth: integer); begin //   Inc(ColumnCount); //when inserting the first column, do a rowInsert for the column titles   If ColumnCount = 1 then begin     TableRow := handle.insertRow(0);     Inc(RowCount);   end;   // Insert a cell in the row at index [column]   var newCell = TableRow.insertCell(columnCount-1);   newCell.setAttribute('bgColor','lightgrey');   newCell.setAttribute('width',inttostr(colwidth)+'px');   // Append a text node to the cell   var newText = browserapi.document.createTextNode(title);   newCell.appendChild(newText); end; procedure TW3TableElement.AddCell(row, column: integer; cell: String); begin // //when inserting the first cell in a row, do a rowInsert   If Column = 1 then begin     TableRow := handle.insertRow(RowCount);     Inc(RowCount);   end;   // Insert a cell in the row at index [column]   var newCell = TableRow.insertCell(column-1);   // Append a text node to the cell   var newText = browserapi.document.createTextNode(cell);   newCell.appendChild(newText); end; end.  
    note : this is an upgraded unit as referred to in this post - method 1
     
  3. Like
    lynkfs got a reaction from jarto in Send an email ?   
    a "smarted" up example of sending gmails using the gmail client library (replaces html file of option 2a previous post)  
    a form with 3 buttons (button1 : log in / button2: log out / button3 : send gmail)
    .... var document external 'document': variant; var console  external 'console':  variant; var gapi     external 'gapi':     variant; implementation { TForm1 } procedure TForm1.InitializeForm; begin   inherited;   // this is a good place to initialize components   var Script := document.createElement('script');   Script.src := 'https://apis.google.com/js/api.js';   Script.setAttribute('async','');   Script.setAttribute('defer','');   document.head.appendChild(Script);   Script.onload := procedure   begin     // Load the API client and auth2 library     gapi.load('client:auth2', procedure     begin       gapi.client.init(class         apiKey = '********2qOeiRlg2humU4YifLyNqt2TrWR2kGk';         discoveryDocs = ["https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest"];         clientId = '********7354-7kp9br0phbsdfkcsilu660u7uq9p6tqs.apps.googleusercontent.com';         scope = 'https://www.googleapis.com/auth/gmail.send';       end);     end);   end; end; procedure TForm1.W3Button1Click(Sender: TObject); //log in begin   gapi.auth2.getAuthInstance().signIn(); end; procedure TForm1.W3Button2Click(Sender: TObject); //log out begin   gapi.auth2.getAuthInstance().signOut(); end; procedure TForm1.W3Button3Click(Sender: TObject); // send gmail begin //   asm     const message =     "From: from@gmail.com\r\n" +     "To: to@hotmail.com\r\n" +     "Subject: Subject of your email\r\n\r\n" +     "with body of text here, separated by a blank line";     // The body needs to be base64url encoded.     const encodedMessage = btoa(message);     //replace all + with -, replace all / with _, and remove the trailing = to make it URL-safe     //const reallyEncodedMessage = encodedMessage.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')     //problem : Smart compiler can't handle \ characters     gapi.client.gmail.users.messages.send({       userId: 'me',       resource: {         raw: encodedMessage      //should be : reallyEncodedMessage       }     }).then(function () { console.log("done")});   end; // end;
     
     
  4. Like
    lynkfs got a reaction from jarto in NodeJS file utils and native app   
    yes to a node server with a back-end mysql db, no to a node server accessing the native file system
    I have these links on my system :
    node socket server with mysql db https://forums.smartmobilestudio.com/topic/4652-node-ground-zero/?tab=comments#comment-23125 file enumeration https://jonlennartaasenden.wordpress.com/?s=node.js  
    I've done some conversions using nativefier, works ok
    I'm racking my brains what the name is of this other native library I've used once, but it eludes me at present
     
     
  5. Like
    lynkfs reacted to DavidRM in NodeJS file utils and native app   
    Here's my example:
    Files := TW3NodeStorageDevice.Create(nil); Files.Mount(nil, procedure (Sender: TW3StorageDevice; Success: boolean) begin if Success then Writeln(PBNRS_FILE_SYSTEM_MOUNTED) else Writeln(Format(PBNRS_ERROR_MOUNTING_FILE_SYSTEM, [Files.LastError])); end ); And reading a file:
    Files.Load(PBNConfig.HelpFile, procedure (Sender: TW3StorageDevice; Filename: string; Data: TStream; Success: boolean) begin if Success then begin ... end else ... end  
  6. Thanks
    lynkfs got a reaction from IgorSavkic in NodeJS file utils and native app   
    yes to a node server with a back-end mysql db, no to a node server accessing the native file system
    I have these links on my system :
    node socket server with mysql db https://forums.smartmobilestudio.com/topic/4652-node-ground-zero/?tab=comments#comment-23125 file enumeration https://jonlennartaasenden.wordpress.com/?s=node.js  
    I've done some conversions using nativefier, works ok
    I'm racking my brains what the name is of this other native library I've used once, but it eludes me at present
     
     
  7. Like
    lynkfs got a reaction from IElite in Send an email ?   
    a "smarted" up example of sending gmails using the gmail client library (replaces html file of option 2a previous post)  
    a form with 3 buttons (button1 : log in / button2: log out / button3 : send gmail)
    .... var document external 'document': variant; var console  external 'console':  variant; var gapi     external 'gapi':     variant; implementation { TForm1 } procedure TForm1.InitializeForm; begin   inherited;   // this is a good place to initialize components   var Script := document.createElement('script');   Script.src := 'https://apis.google.com/js/api.js';   Script.setAttribute('async','');   Script.setAttribute('defer','');   document.head.appendChild(Script);   Script.onload := procedure   begin     // Load the API client and auth2 library     gapi.load('client:auth2', procedure     begin       gapi.client.init(class         apiKey = '********2qOeiRlg2humU4YifLyNqt2TrWR2kGk';         discoveryDocs = ["https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest"];         clientId = '********7354-7kp9br0phbsdfkcsilu660u7uq9p6tqs.apps.googleusercontent.com';         scope = 'https://www.googleapis.com/auth/gmail.send';       end);     end);   end; end; procedure TForm1.W3Button1Click(Sender: TObject); //log in begin   gapi.auth2.getAuthInstance().signIn(); end; procedure TForm1.W3Button2Click(Sender: TObject); //log out begin   gapi.auth2.getAuthInstance().signOut(); end; procedure TForm1.W3Button3Click(Sender: TObject); // send gmail begin //   asm     const message =     "From: from@gmail.com\r\n" +     "To: to@hotmail.com\r\n" +     "Subject: Subject of your email\r\n\r\n" +     "with body of text here, separated by a blank line";     // The body needs to be base64url encoded.     const encodedMessage = btoa(message);     //replace all + with -, replace all / with _, and remove the trailing = to make it URL-safe     //const reallyEncodedMessage = encodedMessage.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')     //problem : Smart compiler can't handle \ characters     gapi.client.gmail.users.messages.send({       userId: 'me',       resource: {         raw: encodedMessage      //should be : reallyEncodedMessage       }     }).then(function () { console.log("done")});   end; // end;
     
     
  8. Like
    lynkfs reacted to jarto in Working with Emoji data   
    Phew, that took some digging, but I found a solution:
    function ConvertFromUCS16(Value: String): String; begin //Make sure any " are escaped for var i:=Length(Value) downto 1 do if (Value[i]='"') and ((i=1) or (Value[i-1]<>'\')) then Insert('\',Value,i); result:=TString.DecodeURIComponent(JSON.parse('"'+Value+'"')); end; Solution from: https://stackoverflow.com/questions/7885096/how-do-i-decode-a-string-with-escaped-unicode
    Edit: Whoops, fixed a bug in the escaping
    Edit2: Add System.JSON to uses clause.
  9. Thanks
    lynkfs got a reaction from IgorSavkic in serviceWorkers (fetch)   
    Technically the cacheStorage api is not that hard, but choosing and implementing the different scenario's (cache-first-then-network, network-first-then-cache etc etc) becomes a bit tedious. And then there is the old browser caching mechanism too, which doesn't go away - two different caching mechanisms to take care of.
    There is a caching cookbook below (and some other links I collected for myself)
    difference between webworkers and service workers   https://www.quora.com/Whats-the-difference-between-service-workers-and-web-workers-in-JavaScript   https://stackoverflow.com/questions/38632723/what-can-service-workers-do-that-web-workers-cannot using serviceWorkers   https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers   https://itnext.io/service-workers-your-first-step-towards-progressive-web-apps-pwa-e4e11d1a2e85   https://developers.google.com/web/fundamentals/primers/service-workers/ inline webworker file   https://forums.smartmobilestudio.com/topic/4662-compiled-procedures/?tab=comments#comment-23272 URL.createObjectURL not for serviceWorkers   https://www.chromestatus.com/feature/5685092332601344   https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL   https://github.com/w3c/ServiceWorker/issues/688 Failed to register a ServiceWorker: The URL protocol of the script ('blob:http%3A//127.0.0.1%3A8090/ac72036e-ed81-49d7-9202-f0323e2018fe') is not supported. workertest : test your browser   https://html5workertest.com/ cookbook   https://serviceworke.rs/ google https://developers.google.com/web/fundamentals/codelabs/your-first-pwapp/ (problems : yahoos weather service is deprecated as per jan 2019 - converting it to OpenWeatherMap sourcecode insists unnecessarily on installing everything in server root - changed urls of resources to relative)  
  10. Like
    lynkfs reacted to DavidRM in ecma.promise   
    I've been using @warleyalex's promises for my projects. They work great. -David
  11. Like
    lynkfs got a reaction from IgorSavkic in serviceWorkers (fetch)   
    WebWorkers are a way of off-loading tasks from the main browser into a separate thread. ServiceWorkers sit between the browser and the network and extend these capabilities by a couple of powerful features :
    offline detection and interception possibilities of network requests (fetch api) resource caching under program control (new cacheStorage api) background syncing saving browser apps as icons on the homescreen serving push notifications ServiceWorkers are integral to Progressive Web Apps
    Architecturally a serviceWorker is just a separate js file, which means that 2 Smart projects are needed (one for the main program, one for the serviceWorker). For normal webWorkers there is a workaround in that it is possible to generate an in-memory js-file using the blob: protocol (see forum post here), so the webWorker can be generated from the main program. For serviceWorkers this approach should work as well, however all modern browsers have closed this avenue (see here, here and here). Not sure if this is temporary or permanent.
    ServiceWorkers are created in the main program, a bit differently then normal. No 'new' object constructor but instead a call to a registration function, returning a promise.
    var navigator external 'navigator': variant;   if navigator.serviceWorker then   begin     navigator.serviceWorker.register('sw-v1.js')       .then(procedure(registration:variant)       begin         console.log('Service Worker registered with scope: ', registration.scope);       end)       .catch(procedure(err:variant)       begin         console.log('Service worker registration failed: ', err);       end)   end; (Adding the link to the external navigator object in the first line means no asm blocks are required. The above could be wrapped up in a TServiceWorker object).
     
    1) network request interceptions (fetch)
    For the serviceworker : start a new project and delete all pre-generated forms and units. Set output to js file (linker) and unclick 'use main body' in code generation. Replace contents of root-unit with
    var sw : variant; asm @sw = self; end; sw.addEventListener("fetch", procedure(event:variant) begin   if (event.request.url.includes("res/app.css")) then begin     event.respondWith(         fetch("res/appmodified.css");       )     );   end end); Soon as the request to load the standard Smart resource-file 'res/app.css' is detected, it is intercepted and replaced with another resourcefile.
    Usually communication between worker and main is done through messaging. There is however a short-cut where the worker can modify the calling main page directly : add a Response object to the event.responseWith method with appropriate headers 
        asm     event.respondWith(       new Response(         "body {background: green !important;}",         {headers: {"Content-Type": "text/css" }}       )     );     end; this will change the backgroundcolor of the form to green. Change the Content-Type to "text/html" and the preceding string to valid html and the form will be replaced with the rendered html content.
    demo (click button and do refresh) and projects (main and worker)
     
  12. Like
    lynkfs reacted to warleyalex in ecma.promise   
    The unit ECMA.Promise is broken. I use this definition Using Promises in SMS
    unit uPromises; interface uses W3C.Console, W3C.DOM, W3C.XMLHttpRequest; type TVariantDynArray = array of Variant; JDeferred = class; TJPromiseCallback = procedure(Value: Variant); TJDeferredObject_fn = function(d: TJPromiseCallback): Variant; TJDeferredObject = procedure(resolve: TJPromiseCallback; reject: TJPromiseCallback); TJPromiseCallback_fn = function(Value: Variant): Variant; TJDeferredEventHandler = function(event: Variant): Variant; JPromise = class external 'Promise' constructor Create(fn: TJDeferredObject_fn { = nil}); overload; constructor Create(resolve: TJDeferredObject_fn; reject: TJDeferredObject_fn); overload; constructor Create(fn: TJDeferredObject); overload; function always(alwaysCallbacks: TVariantDynArray): JPromise; function done(doneCallbacks: TVariantDynArray): JPromise; overload; function done(doneCallbacks: Variant): JPromise; overload; function fail(failCallbacks: TVariantDynArray): JPromise; function progress(progressCallbacks: TVariantDynArray): JPromise; function state(): string; function &then(doneCallbacks: Variant; failCallbacks: Variant{ = undefined}; progressCallbacks: Variant { = undefined}): JPromise; external 'then'; function &then(onFulfilled: TJPromiseCallback_fn = nil): JPromise; overload; external 'then'; function &then(onFulfilled: TJPromiseCallback_fn; onRejected: TJPromiseCallback_fn): JPromise; overload; external 'then'; function &then(onFulfilled: TJPromiseCallback; onRejected: TJPromiseCallback): JPromise; overload; external 'then'; function catch(rejecTJPromiseCallback: Variant = nil): JPromise; overload; function catch(rejecTJPromiseCallback: TJPromiseCallback_fn): JPromise; overload; class function promise(target: Variant): JPromise; end; type JDeferred = class external 'Promise'(JPromise) function notify(args: TVariantDynArray): JDeferred; function notifyWith(context: Variant; args: TVariantDynArray): JDeferred; function reject(args: TVariantDynArray): JDeferred; overload; function reject(args: Variant): JDeferred; overload; function reject(args: TJDeferredEventHandler): JDeferred; overload; function rejectWith(context: Variant; args: TVariantDynArray): JDeferred; function resolve(args: TVariantDynArray): JDeferred; overload; function resolve(value: Variant = nil): JPromise; overload; function resolveWith(context: Variant; args: TVariantDynArray): JDeferred; function all(iterable: TVariantDynArray): JPromise; overload; function race(iterable: TVariantDynArray): JPromise; end; { global external functions } function Promise : JDeferred; external 'Promise' property; function queue: JPromise; external 'Promise.resolve()'; function Error(message: variant): variant; external 'Error'; function document: variant; external "document" property; function window : Variant; external 'window' property; function &typeof(obj:variant): variant; overload; external "typeof"; function wait(ms: Integer): JPromise; function getURI(url: string): Variant; function getFile(url: string): variant; //function myRequire(url: string): Variant; implementation function wait(ms: Integer): JPromise; function setTimeout(ahandler : TJPromiseCallback; aTimeout : Integer): Integer; external 'window.setTimeout'; begin result := JPromise.Create( procedure (resolve, reject: TJPromiseCallback) begin setTimeout(resolve, ms); end); end; function getURI(url: string): Variant; var request: JXMLHttpRequest; procedure p(resolve: TJPromiseCallback; reject: TJPromiseCallback); // Standard XHR to load an image procedure doOnLoad; begin // This is called even on 404 etc // so check the status if (request.status = 200) then begin // If successful, resolve the promise by passing back the request response resolve(request.response); end else begin // Otherwise reject with the status text // which will hopefully be a meaningful error reject(Error('File didn''t load successfully; error code: ' + request.statusText)); end; end; procedure doOnError; begin // Also deal with the case when the entire request fails to begin with // This is probably a network error, so reject the promise with an appropriate message reject(Error('There was a network error.')); end; Begin request := JXMLHttpRequest.Create; request.open('GET', url); // When the request loads, check whether it was successful request.addEventListener('load', @doOnLoad); // Handle network errors request.addEventListener('abort', @doOnError); // Send the request request.send(); End; begin // Create new promise with the Promise() constructor; // This has as its argument a function // with two parameters, resolve and reject Result := JPromise.Create(@p); end; function getFile(url: string): variant; begin // Create new promise with the Promise() constructor; // This has as its argument a function // with two parameters, resolve and reject Result := JPromise.create( procedure(resolve: TJPromiseCallback; reject: TJPromiseCallback) // Standard XHR to load an image var request: JXMLHttpRequest; begin request := new JXMLHttpRequest(); request.open('GET', url); // When the request loads, check whether it was successful request.onload := lambda begin // This is called even on 404 etc // so check the status if (request.status = 200) then begin // If successful, resolve the promise by passing back the request response resolve(request.response); end else begin // Otherwise reject with the status text // which will hopefully be a meaningful error reject(Error("File didn't load successfully; error code: " + request.statusText)); end; end; end; // Handle network errors request.onerror := lambda // Also deal with the case when the entire request fails to begin with // This is probably a network error, so reject the promise with an appropriate message reject(Error('There was a network error.')); end; // Send the request request.send(); end); end; /* function myRequire( url: string): Variant; function ev(win: Variant; arr: array of Variant): Variant; external 'eval.apply'; var ajax: JXMLHttpRequest; function onReady(event: JEvent): Variant; var script: Variant; begin script := ajax.response; // ?? ajax.responseText; if (ajax.readyState = 4) then begin case( (ajax.status)) of 200: begin //eval.apply( window, [script] ); ev( window, [script] ); console.log('script loaded: '+ url); end else console.log('ERROR: script not loaded: '+ url); end; end; end; begin ajax := JXMLHttpRequest.Create; ajax.open( 'GET', url, false ); // <-- the 'false' makes it synchronous ajax.onreadystatechange := @onReady; ajax.send(null); end;*/ end.  
  13. Like
    lynkfs reacted to jarto in Packing Observation   
    For deployment, you can also add extra complexity against preying eyes by using Google's closure-compiler.
    Download the latest binary from: https://github.com/google/closure-compiler/wiki/Binary-Downloads Uncheck "Embed Javascripg into HTML file" in Project options Select both Code packing and Code obfuscation Build Run closure-compiler on the generated main.js: java -jar closure-compiler.jar --js main.js --js_output_file mainp.js And then replace main.js with mainp.js. The compiler will give some warnings about unreachable code but they are safe to ignore.
  14. Like
    lynkfs got a reaction from jarto in serviceWorkers (fetch)   
    WebWorkers are a way of off-loading tasks from the main browser into a separate thread. ServiceWorkers sit between the browser and the network and extend these capabilities by a couple of powerful features :
    offline detection and interception possibilities of network requests (fetch api) resource caching under program control (new cacheStorage api) background syncing saving browser apps as icons on the homescreen serving push notifications ServiceWorkers are integral to Progressive Web Apps
    Architecturally a serviceWorker is just a separate js file, which means that 2 Smart projects are needed (one for the main program, one for the serviceWorker). For normal webWorkers there is a workaround in that it is possible to generate an in-memory js-file using the blob: protocol (see forum post here), so the webWorker can be generated from the main program. For serviceWorkers this approach should work as well, however all modern browsers have closed this avenue (see here, here and here). Not sure if this is temporary or permanent.
    ServiceWorkers are created in the main program, a bit differently then normal. No 'new' object constructor but instead a call to a registration function, returning a promise.
    var navigator external 'navigator': variant;   if navigator.serviceWorker then   begin     navigator.serviceWorker.register('sw-v1.js')       .then(procedure(registration:variant)       begin         console.log('Service Worker registered with scope: ', registration.scope);       end)       .catch(procedure(err:variant)       begin         console.log('Service worker registration failed: ', err);       end)   end; (Adding the link to the external navigator object in the first line means no asm blocks are required. The above could be wrapped up in a TServiceWorker object).
     
    1) network request interceptions (fetch)
    For the serviceworker : start a new project and delete all pre-generated forms and units. Set output to js file (linker) and unclick 'use main body' in code generation. Replace contents of root-unit with
    var sw : variant; asm @sw = self; end; sw.addEventListener("fetch", procedure(event:variant) begin   if (event.request.url.includes("res/app.css")) then begin     event.respondWith(         fetch("res/appmodified.css");       )     );   end end); Soon as the request to load the standard Smart resource-file 'res/app.css' is detected, it is intercepted and replaced with another resourcefile.
    Usually communication between worker and main is done through messaging. There is however a short-cut where the worker can modify the calling main page directly : add a Response object to the event.responseWith method with appropriate headers 
        asm     event.respondWith(       new Response(         "body {background: green !important;}",         {headers: {"Content-Type": "text/css" }}       )     );     end; this will change the backgroundcolor of the form to green. Change the Content-Type to "text/html" and the preceding string to valid html and the form will be replaced with the rendered html content.
    demo (click button and do refresh) and projects (main and worker)
     
  15. Like
    lynkfs got a reaction from IElite in Websockets OR Node?   
    it depends
    websockets is but one mechanism for client-server communication. Node supports ws but there are php websocket implementations as well. Node runs on most if not all platforms, but there are alternatives.
    Ultimately you'll have to make choices re client type (browser web app, native, ...), communication protocol (websocket, ajax/xmlhttp, ...), middleware (if any), server platform (windows, linux, cloud, ...), server language (node/smart/js, delphi, php, aws), back-end database (oracle, mysql, firebase, ...).
    These choices will be influenced / dictated by the functional requirements of your app (is your json file unique for all users or per user, do updates need to be pushed in real time, ...), scale (concurrent clients), reliability, availability and costs (all servers incur costs, although some providers provide limited free tiers).
    hny
     
  16. Like
    lynkfs got a reaction from jarto in serviceWorkers   
    I was working on a PWA but postponed it until after my servers got upgraded to https (which has now happened). I'll have another look soon
  17. Like
    lynkfs reacted to warleyalex in mORMot with SMS   
    In fact, there is an bug on older SMS versions 1.2 | 2.0 | 2.0.1 | 2.2 and 2.2.2 - the TObject::Destroy method would just delete the property named "prop" rather than the actually all the properties of the object itself. For instance, obj.Free is doing nothing because the method Destroy was buggy
    // old SMS version var TObject={ (...) Destroy: function (s) { for (var prop in s) if (s.hasOwnProperty(prop)) delete s.prop }, Destroy$: function(s) { return s.ClassType.Destroy(s) }, (...) } On newer SMS version 3.x, they fixed the TObject::Destroy method. 
  18. Like
    lynkfs got a reaction from IElite in mORMot with SMS   
    Having read the posts in this thread, I'm warming to using mORMot.
    Looking for a working project and a bit of explanatory text
  19. Like
    lynkfs got a reaction from jarto in inter-tab processing   
    Would it be possible to implement a 'client-server' architecture where both the client and the server are executed locally (but in separate spaces). Or just divide an app up in different parts where each part is executed in its own environment and communicates with the other parts as necessary. And all this pure locally. 
    The answer is yes: use separate browser tabs.
    Surprisingly there are multiple ways of doing this, and the candidate technologies enabling inter-tab communication are :
    local storage (really) shared web workers broadcast channelling webrtc The demo in this post is based on using localStorage and consists of two separate but standard Smart projects, dubbed 'server' and 'client'.
    The server-project is just a form with an embedded anchor html element (<a>). When clicked the href-attribute is set to the output of the client-project ('client.html') and the target-attribute to '_blank'. This has the effect of opening up a new browser-tab which runs the client-project.
    So now there are two browser tabs open, each running its own project.
    Communication between these tabs is possible using localStorage : mutations in localStorage generate storage-events and these events can be captured and used for communication purposes.
    This url (https://www.lynkfs.com/Experiments/webrtc/localstorage/server.html) opens up both tabs at once (you might have to allow pop-ups in Chrome or FireFox), and mimics a login process. 
    Server-code and Client-code (native framework but you'll get the idea)
    Login form :
      button.OnClick := procedure(sender:TObject)   begin //this sends 2 events to the server, which can then validate name and password     window.localStorage.setItem('name',name.handle.value);     window.localStorage.setItem('pw',  pw.handle.value);   end;   window.onstorage := procedure(e:variant)   begin //after validation the server sends a new event with the results     console.log(e.key);     console.log(e.oldValue);     console.log(e.newValue);     footer.SetBounds(100,300,200,30);     if (e.key = 'result') and (e.newValue = 'ok') then       footer.setInnerHTML('login successful');   end;  
    happy holidays
     
     
  20. Like
    lynkfs got a reaction from Czar in inter-tab processing   
    Would it be possible to implement a 'client-server' architecture where both the client and the server are executed locally (but in separate spaces). Or just divide an app up in different parts where each part is executed in its own environment and communicates with the other parts as necessary. And all this pure locally. 
    The answer is yes: use separate browser tabs.
    Surprisingly there are multiple ways of doing this, and the candidate technologies enabling inter-tab communication are :
    local storage (really) shared web workers broadcast channelling webrtc The demo in this post is based on using localStorage and consists of two separate but standard Smart projects, dubbed 'server' and 'client'.
    The server-project is just a form with an embedded anchor html element (<a>). When clicked the href-attribute is set to the output of the client-project ('client.html') and the target-attribute to '_blank'. This has the effect of opening up a new browser-tab which runs the client-project.
    So now there are two browser tabs open, each running its own project.
    Communication between these tabs is possible using localStorage : mutations in localStorage generate storage-events and these events can be captured and used for communication purposes.
    This url (https://www.lynkfs.com/Experiments/webrtc/localstorage/server.html) opens up both tabs at once (you might have to allow pop-ups in Chrome or FireFox), and mimics a login process. 
    Server-code and Client-code (native framework but you'll get the idea)
    Login form :
      button.OnClick := procedure(sender:TObject)   begin //this sends 2 events to the server, which can then validate name and password     window.localStorage.setItem('name',name.handle.value);     window.localStorage.setItem('pw',  pw.handle.value);   end;   window.onstorage := procedure(e:variant)   begin //after validation the server sends a new event with the results     console.log(e.key);     console.log(e.oldValue);     console.log(e.newValue);     footer.SetBounds(100,300,200,30);     if (e.key = 'result') and (e.newValue = 'ok') then       footer.setInnerHTML('login successful');   end;  
    happy holidays
     
     
  21. Like
    lynkfs got a reaction from IElite in inter-tab processing   
    Would it be possible to implement a 'client-server' architecture where both the client and the server are executed locally (but in separate spaces). Or just divide an app up in different parts where each part is executed in its own environment and communicates with the other parts as necessary. And all this pure locally. 
    The answer is yes: use separate browser tabs.
    Surprisingly there are multiple ways of doing this, and the candidate technologies enabling inter-tab communication are :
    local storage (really) shared web workers broadcast channelling webrtc The demo in this post is based on using localStorage and consists of two separate but standard Smart projects, dubbed 'server' and 'client'.
    The server-project is just a form with an embedded anchor html element (<a>). When clicked the href-attribute is set to the output of the client-project ('client.html') and the target-attribute to '_blank'. This has the effect of opening up a new browser-tab which runs the client-project.
    So now there are two browser tabs open, each running its own project.
    Communication between these tabs is possible using localStorage : mutations in localStorage generate storage-events and these events can be captured and used for communication purposes.
    This url (https://www.lynkfs.com/Experiments/webrtc/localstorage/server.html) opens up both tabs at once (you might have to allow pop-ups in Chrome or FireFox), and mimics a login process. 
    Server-code and Client-code (native framework but you'll get the idea)
    Login form :
      button.OnClick := procedure(sender:TObject)   begin //this sends 2 events to the server, which can then validate name and password     window.localStorage.setItem('name',name.handle.value);     window.localStorage.setItem('pw',  pw.handle.value);   end;   window.onstorage := procedure(e:variant)   begin //after validation the server sends a new event with the results     console.log(e.key);     console.log(e.oldValue);     console.log(e.newValue);     footer.SetBounds(100,300,200,30);     if (e.key = 'result') and (e.newValue = 'ok') then       footer.setInnerHTML('login successful');   end;  
    happy holidays
     
     
  22. Like
    lynkfs reacted to jarto in Development updates   
    New update available:
    RTL:
    TW3TabControl: AnimateTabs-property to control how tabs are changed. TW3ListBox: Prevent an exception if TW3Image is used as a line control and OnShowItem is not set. TW3ListMenu, TW3HeaderControl and TW3SimpleLabel: Don't set default caption to classname during initialization. DWScript: Capitalize day and month names correctly (January instead of january, Sunday instead of sunday) IDE:
    Improvements to the way the IDE reacts to a changed external file. Use caption while drawing generic controls instead of component name.  
  23. Like
    lynkfs got a reaction from jarto in mORMot with SMS   
    Having read the posts in this thread, I'm warming to using mORMot.
    Looking for a working project and a bit of explanatory text
  24. Like
    lynkfs reacted to IElite in TW3ListBox Doesn't Work with TW3Image Items   
    If this will help you, here is a demo project (attached) where I created my own ListBox item (Image (left-aligned) and Label (client-aligned))
     
    Listbox3.zip
  25. Thanks
    lynkfs reacted to warleyalex in mORMot with SMS   
    It is a bug!  SmartMS 2.2.2.4694 emits correct JS, it comes with delete s.prop
    var myObject = { "ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*" }; delete myObject.regex; // it also work with delete myObject['regex']; Note
    delete s[prop] instead of
    delete s["prop"] Source: https://stackoverflow.com/questions/208105/how-do-i-remove-a-property-from-a-javascript-object
×
×
  • Create New...