Jump to content


  • Content count

  • Joined

  • Last visited

  • Days Won


lynkfs last won the day on April 25

lynkfs had the most liked content!

About lynkfs

  • Rank

Profile Information

  • Gender
  • Location

Recent Profile Visitors

327 profile views
  1. webhooks

    It took me a while to get my head around the concept of webhooks. These have been around for 10 years or more but there is almost no to-the-point info or 'webhook-for-dummies' article on the web available. Webhooks are basically a notification system between disparate systems or servers, where the notifications are based on Http (XmlHttpRequests), so no messaging protocols or middleware software necessary. Like this : In this example there is a service which exposes changes in stock-prices. This service also has an api which allows applications to subscribe to this service (1). Subscription involves providing the url of the application-server. When a stock-price change event occurs, the service POST's a HttpRequest to the url of the server with a payload of the new price (2a) The server responds with a simple OK (2b) and initiates an action towards the client. This action can be maybe sending an email, or just sending a socket-message to the client (3) which allows the client to update its db or user-interface Setting this up in SMS takes a bit of effort as the servers need to have publicly accessible urls. Meaning nodejs servers have to be hosted somewhere (Heroku, Google Cloud). Doable I think.
  2. lazy loading SEO

    Checking the SEO audits on a webpage constructed with SMS, I noticed I got negative points for not lazy loading images. Lazy loading is to defer loading of images which are initially not visible when the page loads (below the fold), and to only start loading them when users scroll down sufficiently that they (probably will) become visible. There is the Intersection Observer Api which can help with that. See https://developers.google.com/web/updates/2016/04/intersectionobserver and https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API Have a form with an element (say button) and position the button so that it is not visible (top=1200px). Set up an IntersectionObserver and check the intersectionRatio in the asynchronous callback. Scrolling down so that the button becomes visible changes the form's background. procedure TForm1.InitializeForm; begin inherited; // this is a good place to initialize components NativeScrolling := True; W3Button1.Top := 1200; procedure mycallback(changes: variant); begin If changes[0].intersectionRatio > 0 //between 0 and 1 = partly visible then ThemeBackGround := bsDecorativeInvertBackground; end; var io : variant; asm io = new IntersectionObserver( @mycallback ); end; io.observe(W3Button1.handle); end; Note - does not work in ide but works fine from file or server - for lazy loading images thinking of a TW3Image descendant or class helper which implements a VisibilityChange callback which supplies src parameter ...
  3. Node.JS - simple server - fails to compile

    if you're referring to the SimpleHttpServer demo in the node.js directory, that one compiles (and works) at my place Maybe do a SmartUpdate ?
  4. Async keyword

    2) Async/Await See previous posts in this thread. Async functions are basically functions returning promises, but in disguise. All Async functions can be re-written using Promises : This ES6 javascript code async function addAsync(x) { const a = await myAsyncProc(10); return x+a; } is equivalent to this ES6 javascript code function addPromise(x){ return new Promise(resolve => { MyAsyncProc(10).then((a) => { resolve(x + a); }) }); } which is equivalent (sort of) to this Smart code function resolve(arg: variant): variant; begin writeln('async/await'); result := 75+arg; end; procedure await(ok,err: procedure(result:variant); arg:variant); begin TW3Dispatch.Execute(procedure() begin ok(resolve(arg)); end, 2000); end; function MyAsync(arg:variant): variant; begin var q : variant; asm @q = new Promise(function (ok,err) { @await(ok,err,@arg) }); end; result := q; end; MyAsync(60).then(procedure(val:variant) begin writeln(val); // 75 + 60 = 135 after 2 seconds MyAsync(val+10).then(procedure(val:variant) begin writeln(val); // 75 + 135 + 10 = 220 after 4 seconds end); end); function "MyAsync" returns a promise "q" which "resolve"s after the asynchronous "await" process ends and is invoked by calling the "MyAsync.then" method (which can be stacked). works, but not liking it very much. 3) TW3Dispatch The polling construct below is used in the rtl in some places and is much more compact. Depends on suitability procedure MyAwait; begin if (completion of asynchronous process = true) then begin // proceed end else //If not, call back in 100ms TW3Dispatch.Execute(MyAwait, 100); end; MyAwait;
  5. Async keyword

    Some modern libraries return Promises or require Async/Await type of constructions in order to use them. While these javascript constructs are not supported natively by the compiler, sometimes it may be necessary to use them. Hopefully very seldomly I must add. 1) Promise Essentially, a promise is a returned object to attach callbacks to. See https://developers.google.com/web/fundamentals/primers/promises for an indepth article on Promises. The javascript syntax is (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) let myFirstPromise = new Promise((resolve, reject) => { // We call resolve(...) when what we were doing asynchronously was successful, and reject(...) when it failed. // In this example, we use setTimeout(...) to simulate async code. // In reality, you will probably be using something like XHR or an HTML5 API. setTimeout(function(){ resolve("Success!"); // Yay! Everything went well! }, 250); }); myFirstPromise.then((successMessage) => { // successMessage is whatever we passed in the resolve(...) function above. // It doesn't have to be a string, but if it is only a succeed message, it probably will be. console.log("Yay! " + successMessage); }); and the closest I could make it in Smart without having to write any javascript code (except for the static 1-liner constructor) //Promise function resolve: variant; begin result := 'successful'; end; procedure async(ok,err: procedure(result:variant)); begin //do something async : readfile, ajax call etc. In this case: timeout TW3Dispatch.Execute(procedure() begin ok(resolve); end, 2000); end; var p : variant; asm @p = new Promise(function (ok,err) { @async(ok,err) }); end; p.then(procedure(val:variant) begin writeln(val); // 'successful' after 2 seconds end); 'p' is the Promise object, 'async' is the method where something asynchronous takes place, 'resolve' (or 'reject') is the method invoked depending on the result of the async operation and the 'p.then' method finally executes after the promise is fulfilled. Just looking at it, the best thing to say about it that it does work, however the whole promise construct strikes me as overly complicated. I would not use it unless really necessary. Nevertheless, some libraries have functions which simply return promises, so need to be able to deal with those. 2) Async/Await See previous posts in this thread. Async functions are basically functions returning promises, but in disguise. All Async functions can be re-written using Promises.
  6. Tensorflow

    twimc : same Tensorflow.js example as in previous post, but without the asm blocks : var tf external 'tf' : variant; var window external 'window' : variant; implementation { TForm1 } procedure TForm1.W3Button1Click(Sender: TObject); begin var Script := w3_createHtmlElement('script'); Script.src := 'https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.6.1'; w3_setElementParentByRef(script, browserapi.document.head); Script.onload := procedure begin // Define a model for linear regression. var model := tf.sequential(); // model.add(tf.layers.dense({units: 1, inputShape: [1]})); model.add(tf.layers.dense(class units = 1; inputShape : array[0..0] of integer := [1]; end)); // Prepare the model for training: Specify the loss and the optimizer. // model.compile({loss: 'meanSquaredError', optimizer: 'sgd'}); model.compile(class loss = 'meanSquaredError'; optimizer = 'sgd'; end); // Generate some synthetic data for training. var xs := tf.tensor2d([1, 2, 3, 4], [4, 1]); var ys := tf.tensor2d([1, 3, 5, 7], [4, 1]); // Train the model using the data. // fit returns a promise model.fit(xs, ys).then(lambda model.predict(tf.tensor2d([5], [1, 1])).print(); end); end; // end; Tensorflow is a language in itself, not very intuitive, but pretty powerful nonetheless
  7. Tensorflow

    Tensorflow.js has arrived - exciting Google just announced tensorflow.js, its machine learning library which previously required access from python (or C# for more limited access), but now can be accessed from js The main page for this : https://js.tensorflow.org/ Just to see how this can be embedded in SMS : the (slightly) altered example on that main page, plunked under a button procedure TForm1.W3Button1Click(Sender: TObject); begin var Script := w3_createHtmlElement('script'); Script.src := 'https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.6.1'; w3_setElementParentByRef(script, browserapi.document.head); Script.onload := procedure begin asm //import * as tf from '@tensorflow/tfjs'; //var tf = require(['@tensorflow/tfjs']); // Define a model for linear regression. const model = tf.sequential(); model.add(tf.layers.dense({units: 1, inputShape: [1]})); // Prepare the model for training: Specify the loss and the optimizer. model.compile({loss: 'meanSquaredError', optimizer: 'sgd'}); // Generate some synthetic data for training. const xs = tf.tensor2d([1, 2, 3, 4], [4, 1]); const ys = tf.tensor2d([1, 3, 5, 7], [4, 1]); // Train the model using the data. model.fit(xs, ys).then(() => { // Use the model to do inference on a data point the model hasn't seen before: model.predict(tf.tensor2d([5], [1, 1])).print(); window.alert(model.predict(tf.tensor2d([5], [1, 1]))); }); end; end; end; The example above is not the most striking one, the others are better. But at least got it working. PS : a neural network built from first principles was posted at http://www.lynkfs.com/Experiments/mnist/Neural01.sproj a while ago, see in action using a larger character recognition dataset at http://www.lynkit.com.au/native/www/ under 'projects' / 'AI-character recognition'. (Training takes approx 30sec on desktop, 5-6min on mobile)
  8. Confused on variants

    Confused on the following errors while setting up a tiered data structure (f.i. business with multiple departments with multiple staff per department) procedure TForm1.InitializeForm; begin inherited; // this is a good place to initialize components var MyList1 : variant := new JObject; MyList1.Business := TVariant.CreateObject; MyList1.Business.Name := 'MyBusiness'; MyList1.Business.Depts := TVariant.CreateArray; MyList1.Business.Depts.push(class DeptName := 'DepartmentA'; Staff := ['st1','st2']; end); MyList1.Business.Depts.push(class DeptName := 'DepartmentB'; end); MyList1.Business.Depts.push(class DeptName := 'DepartmentC'; end); writeln(JSON.stringify(MyList1)); //OK so far //{"Business":{"Name":"MyBusiness","Depts":[{"Staff":["st1","st2"],"DeptName":"DepartmentA"},{"DeptName":"DepartmentB"},{"DeptName":"DepartmentC"}]}} MyList1.Business.Depts[0].Staff[2] := 'st3'; //works MyList1.Business.Depts[0].Staff.add('st4'); //compiles but gives execution error : //Uncaught TypeError: MyList1.Business.Depts[0].Staff.add is not a function MyList1.Business.Depts[0].Staff.push('st5'); //works. Why does 'push' work but 'add' doesn't ? MyList1.Business.Depts[0].staff.push('st6'); //lowercase 'staff'. Compiles but gives execution error : //Uncaught TypeError: Cannot read property 'push' of undefined An alternative approach : var MyList2 := class Entries := [ class BusName := 'Bus01'; Depts := [ class DeptName := 'DeptA'; Staff := ['a1','a2']; end, class DeptName := 'DeptB'; Staff := ['b1','b2']; end, class DeptName := 'DeptC'; Staff := ['c1','c2']; end ]; end , class BusName := 'Bus02'; Depts := [ class DeptName := 'DeptD'; Staff := ['d1','d2']; end ]; end ]; end; writeln(JSON.stringify(MyList2)); //OK so far //{"Entries":[{"Depts":[{"Staff":["a1","a2"],"DeptName":"DeptA"},{"Staff":["b1","b2"],"DeptName":"DeptB"},{"Staff":["c1","c2"],"DeptName":"DeptC"}],"BusName":"Bus01"},{"Depts":[{"Staff":["d1","d2"],"DeptName":"DeptD"}],"BusName":"Bus02"}]} MyList2.Entries.push(class BusName := 'Bus03'; end); //Syntax Error: Array method "push" is restricted to dynamic arrays //Syntax Error: Array method "add" is restricted to dynamic arrays MyList2.Entries[0].Depts[0].DeptName := 'aaa'; //Syntax Error: There is no accessible member with name "Depts" There are a number of workarounds to avoid these errors, but I just don't get the picture of why the above errors occur at all. Any clarifications ?
  9. databases and applications

    Great, very much looking forward to it
  10. databases and applications

    Two bobs worth of thoughts on the interface between applications and databases. Every business today has its data stored in a number of databases. Whether SQL-based, proprietory, ms Office (Excel anyone ?), Hadoop on Google Cloud or whatever. On the application side apps need access to this data, and more often than not the data they need will reside in more than 1 datastore. The days that every application had its own private database are long gone. Which means we need something inbetween This middleware has the task of translating application requests into database calls, retrieving the data and making it available in some format the application understands. (Not ususally done, it could potentially also work the other way around : external changes to data could result in autonomously firing up of applications to process these changes, or at least put them in a queue for later processing). There are some products available which occupy this space. Conceivably 'ORM's, which talk 'object' on one side and SQL on the other, or products based on GraphQL (a specification opensourced by Facebook which covers some of the above), and possibly other products unknown to me. How would that work in SMS terms Middleware The middleware has to have a 'data'-model at its heart. This can be a traditional data-model, a UML model of sorts, a graph, or some other scheme - as long as it is able to represent data structure and dependencies. Since graphs are my new friends, I'm sticking with that for now. An ubiquitous example is 'the library'. a library ==> has books ==> have author(s) and books ==> have publisher And some variables associated with these nodes : title, ISBN number, publisher etc for books; name, contact info, autobiography details etc. for authors and co-authors. Databases Suppose the current situation of this imaginary library is something like this "Some former regional libraries have been amalgamated into the new current library. However staff at present still has to work with the old separate databases, waiting for a reconciliation effort by the IT-department later this year/cycle/decade". Applications. App-01 is meant to solve this problem. It is also meant to decouple application processing and database management as much as possible. As an example : one of its functions is to display book and author info based on selecting (partial) titles. Such a query call could look something like this { book(title: "*smart*") { ISBN author } } the middleware would reconcile this with its internal graph model, find out where and how to extract the data fields for this query and spawn calls to one or more book databases. These SQL calls would be something like select * from books a, authors b where a.author = b.author and a.title like '%smart%' and the middleware would amalgamate the select cursors into a single result set and return that to App-01, possibly in a format like { book: { 'A Smart Book' { ISBN : '' author: 'Primož Gabrijelcic' }, 'The Smart Company' { ISBN : 'coming' author: 'Jon Aasenden' } } } I think this would be feasible. The advantages of such an approach / product would be a certain amount of decoupling of dependencies between application and database.
  11. Payment Request API

    HTML5.2 was introduced a month or 2 ago, with a couple of new features. One of them being the payment request api. So basically it provides all the forms necessary to display a checkout, capture card info, addresses and shipping costs etc. The api is implemented in Chrome and Edge, but doesn't work (yet) in Firefox. Forms in these browsers are rendered somewhat browser specific : This includes validity check of cc details etc. I suppose in time there will be a "W3C.payment" file included in the API's/W3C subdirectory to help with structuring the payment request constructor (hint) For now this works procedure TForm1.W3Button1Click(Sender: TObject); begin //set up merchant structure var supportedInstruments : array of variant; supportedInstruments[0] := class supportedMethods := 'basic-card'; data := class supportedNetworks : array of string; supportedTypes : array of string; end; end; //set up invoice structure var details := class total := class label : string; amount := class currency : string; value : string; end; end; displayItems : array of Variant; shippingOptions : array of variant; end; //set up options var options := class requestShipping := true; end; //populate merchant structure with supported cards supportedInstruments[0].data.supportedNetworks[0] := 'visa'; supportedInstruments[0].data.supportedNetworks[1] := 'mastercard'; supportedInstruments[0].data.supportedNetworks[2] := 'amex'; supportedInstruments[0].data.supportedNetworks[3] := 'jcb'; supportedInstruments[0].data.supportedNetworks[4] := 'diners'; supportedInstruments[0].data.supportedNetworks[5] := 'discover'; supportedInstruments[0].data.supportedNetworks[6] := 'mir'; supportedInstruments[0].data.supportedNetworks[7] := 'unionpay'; //populate merchant structure with supported card types supportedInstruments[0].data.supportedTypes[0] := 'credit'; supportedInstruments[0].data.supportedTypes[1] := 'debit'; //populate invoice structure with totals details.total.label := 'Payments invoice Q2018-02'; details.total.amount.currency := 'AUD'; details.total.amount.value := '230.00'; //populate invoice structure with line items var displayItems : array of variant; // displayItems[0] := new JObject; displayItems[0].label := 'labour hire'; displayItems[0].amount := new JObject; displayItems[0].amount.currency := 'AUD'; displayItems[0].amount.value := '65.00'; // displayItems[1] := new JObject; displayItems[1].label := 'material costs'; displayItems[1].amount := new JObject; displayItems[1].amount.currency := 'AUD'; displayItems[1].amount.value := '165.00'; // details.displayItems := displayItems; //populate invoice structure with shipping costs var shippingOptions : array of variant; shippingOptions[0] := new JObject; shippingOptions[0].id := 'standard'; shippingOptions[0].label := 'Standard shipping'; shippingOptions[0].amount := new JObject; shippingOptions[0].amount.currency := 'AUD'; shippingOptions[0].amount.value := '0.00'; details.shippingOptions := shippingOptions; //writeln(json.stringify(details)); //finally do a payment request var request : variant := new JObject; asm @request = new PaymentRequest(@supportedInstruments, @details, @options); end; request.show(details); // end; Does not work in the ide, starting from file system is ok
  12. Edit/Memo Copy Paste fails in Firefox

    there are numerous entries on the web on this problem. Seems to be a firefox idiosyncracy most of these web entries fall in 2 categories : enable a setting in FF through 'about:config' manipulate the contenteditable attribute The first doesn't work for me, I've tried a couple of settings mentioned, but no joy The second works a bit better, not sure if it fully solves your problem though. See also https://jonlennartaasenden.wordpress.com/2014/06/14/creating-an-edit-box-in-smart-pascal/ After setting the 'contenteditable' attribute to true on the second box, I can select all text in the first box through Ctrl-A (select all), or alternatively part of it with mouse, then Ctrl-C (copy). On the second box, executing Ctrl-V (paste), or right-clicking and pasting, now works as expected.
  13. Node startup

    I suppose it is not possible to start up node / a node server, from the client. or is it ?
  14. Autocomplete Address INformation

    I might take you on on that (also just adding the tag 'geolocation' to this post for future references)
  15. TypeError - Converting circular structure to JSON 

    not sure if this answers your question, but did notice you're sending a postmessage to the window object. That is usually done to enable cross or intra-window communication. If you want to communicate with a specific webworker, send it to that webworker instead. monOuvrier.postMessage([fichier]);