Jump to content

lynkfs

Moderators
  • Content Count

    743
  • Joined

  • Last visited

  • Days Won

    146

Reputation Activity

  1. Like
    lynkfs got a reaction from jarto in visual processing   
    A while ago I posted some ideas and a demo on the subject of 'nocode' or 'locode' development. The idea was to do a domain modelling exercise, and extract or generate an application from that with no or minimal coding required. The demo put a couple of the proposed models through its paces.
    After that post I put the subject back in the incubator for a bit.
    Sort of recently I realised that having an rtl with visual components and an ide with a form painter is a good thing to have, but only covers part of what is necessary if we need to cover process logic, or business rules, without having to resort to coding. 
    Various computing packages (datamining, visual analytics etc) model business logic by providing specialised components, which can be strung together and parametrised.
    I tried this approach out (using KNIME) with the following (nonsensical) example process :
    "from the NorthWind database get all companies, and from the FishFacts database extract all species, collate only those entries from both datasources where the name starts with the letter 'L'  and list them. Also produce a pie-chart of all fish species showing their length in cm."
     

     
    This (nonsense) process translates to the node structure above. Nodes typically can be selected from a list of available nodes and right-clicking gives parametrisation forms, f.i. the MYSQL connector asks for a host, database name, credentials etc.
    Stringing these components together is a simple process in itself, and the output produces something like

    Not too bad.
     
    I've coded a couple of these type of components in Smart, which works really well.
    For the technical architecture I've based these on the principles of FBP (flow based programming) where every node is a webworker, and the connectors between these nodes/webworkers are defined by channel-objects. Data transfer between these nodes/channels is done by messaging. See post here.
    It would be nice to extend the rtl with these types of components, including a process painter
     
  2. Like
    lynkfs reacted to jarto in Development updates   
    New update is available:
    Bug fixes and improvements to the IDE:
    BringToFront and SendToBack will now affect component creation order Opening files from Project Search Path is fixed
  3. Like
    lynkfs got a reaction from Tim Koscielski in Mixing Javascript and SMS   
    Example 2 : see below (first post in that thread) for some function call examples
     
    Example 1 : depends on what attribute.
    In your example you want to manipulate the visibility property of a button. These types of properties usually are mapped on a property or attribute of the underlying DOM-element. In this case you could use the style element visibility : W3Button1.handle.style.visibility := 'hidden' / 'visible'. 
    'handle' is the doorway between object pascal on the left hand side and the dom on the right hand side. No need for an asm block here. 
    you can go the other way  too :
      var x : variant := W3Button1.handle;   asm     console.log((@x).style.visibility);   end; but you can't directly manipulate the properties of an object pascal object, as in asm @W3Button1.Visible = true
    Of course you can do some conditional js coding and execute object pascal code (like W3Button1.Visible := true;) depending on the return outcomes.
     
    Out of habit I suppose I try to minimise the use of asm blocks (although there is nothing wrong with using them). 
    The only times I have to use them if a js object doesn't have a create constructor but instead can only be instantiated by the 'new' keyword
      var formData : variant;   asm @formData = new FormData(); end;   //from here all methods and attributes of the js object are accessible outside an asm block     formData.append("userfile", EditBox1.handle.files[0]); or wrapping a js function. (you can set @result in an asm block)
     
     
  4. Like
    lynkfs got a reaction from Tim Koscielski in Uploading a file that has been selected using INPUT box type=itFile   
    Post rewritten.
    If using the html <form> element, as below, works for a DMVC server, then it will work for other servers like php, node as well.
    <form action="/file" method="post" enctype="multipart/form-data"> <input type="file" name="fupload"> <input type="submit"> </form> So the best bet would be to follow this same mechanism in Smart. The questions are then 
    A:  since there is no component in Smart which encapsulates the <form> element, how can we get one, or B:  would it be possible to circumvent this <form> element completely Ad B (the difficult one first)
    This involves looking at what exactly happens when a <form> is used for file uploads, and reproduce that process in object pascal. Personally I am not in favour of this approach as it duplicates functionality which is freely available in the browser. 
    However, it can be done. The <form> submit process for uploading files goes something like
    select a file to upload (type = itFile) read this file using the File api chop the content up in chunks surround each chunk with a unique border (something like "-----------------------------244962545219104") send these chunks using the xmlhttp post protocol using some specific headers There is an example here using this approach (with a simple php server as backend). A modified working version is available here, which gives as output (FF Params tab) something similar to
    -----------------------------168b2ce8400 Content-Disposition: form-data; name="myfile"; filename="bar.txt" Content-Type: text/plain test file -----------------------------168b2ce8400-- If this looks promising, the next step would be to translate the js framework into object pascal.
     
    Ad A
    It should be feasible to create a new component which encapsulates a <form> element.
    Stub like
      TW3FormElement = Class(TW3CustomControl)   protected     function  MakeElementTagId: string; override;     Procedure ObjectReady;Override;     procedure InitializeObject;override;   End; implementation function TW3FormElement.MakeElementTagId: String; Begin   result:='FORM'; end;  
    Note
    There is another thread which might be of use as well : 
     
     
  5. Like
    lynkfs reacted to Tim Koscielski in Uploading a file that has been selected using INPUT box type=itFile   
    Ok, this first follow up is what I did to get it working based on some of the links for handling forms in javascript. Fortunately because I could mix and match SMS Pascal and Javascript, I get the best of both worlds.
    On my Smart Form, I have a TW3Button and a TW3EditBox with a type of ltFile. Then with the following javascript, I can get the form posted correctly to a backend which is able to capture the file and other variables of the form. Note that the other elements are created dynamically based on an example I was using. The ShowMessage and Alert items were just feedback mechanisms for me to see this part working. Both my DMVC server and a PHP script were able to process this.
    I am sure that there is a more friendly SMS way of writing this, but for now it got my form working and I was able to continue to plow forward with this upload piece being reasonably well contained. My key take way was getting the file upload field and the code below did the trick. This may not be the best way, but at least it was a starting point.
    myFile = document.getElementById('id', 'fupload1'); The InitializeObject was important to label the TW3EditBox element correctly. Below that is the code that I stuck in the OnClick event for the button. I saw many other ways to deal with this, but I just wanted to keep it straight forward for the UI.
     
    procedure TForm_ImportFile.InitializeObject; begin inherited; {$I 'Form_ImportFile:impl'} W3ButtonBack.InnerHTML := '<i class="fa fa-arrow-left fa-2x"></i>'; // this is a good place to initialize components W3EditBox1.handle.setAttribute('name','fupload'); W3EditBox1.handle.setAttribute('id', 'fupload1'); // Initialize EditBox id to find it with getElementById below W3EditBox1.InputType := itFile; end; // BUTTON CLICK EVENT CODE ShowMessage('Starting'); asm var formData = new FormData(); alert('Trying to get file box'); myFile = document.getElementById("fupload1").files[0]; alert('Got file: ' + myFile.name); formData.append("username", "Groucho"); formData.append("accountnum", 123456); // number 123456 is immediately converted to a string "123456" // HTML file input, chosen by user //formData.append("fupload", fileInputElement.files[0]); //var myFile = new Blob([content], {type: "text/plain"}); formData.append("userfile", myFile, myFile.name); // JavaScript file-like object var content = '<a id="a"><b id="b">hey!</b></a>'; // the body of the new file... var blob = new Blob([content], { type: "text/xml"}); formData.append("webmasterfile", blob); var request = new XMLHttpRequest(); request.open("POST", "http://127.0.0.1:2001/file"); request.send(formData); end; ShowMessage('Done');  
  6. Like
    lynkfs reacted to warleyalex in Hoping for a Better Way: Delphi Objects to JS Objects   
    to match/map the JSON fieldname, you have to declare the record definition is
    type TFishRecord = record Category: String; external 'Category'; Common_Name: String; external 'Common_Name'; Length_Cm: String; external 'Length_Cm'; Length_In: String; external 'Length_In'; Notes: String; external 'Notes'; Species_Name: String; external 'Species_Name'; Species_No: String; external 'Species_No'; end; to emit this JS Object, for instance:
    {
        Category : "Snapper",
        Common_Name : "Red Emperor",
        Length_Cm : "60",
        Length_In : "23.6220472440945",
        Notes : "Called seaperch in Australia.",
        Species_Name : "Lutjanus sebae",
        Species_No : "90030"
    }
  7. Like
    lynkfs got a reaction from Tim Koscielski in Uploading a file that has been selected using INPUT box type=itFile   
    I had a look at the DelphiMVCFramework files-upload demo. The upload page, see below, lets the user select a file and submits a form with the selected file to the server.
    <html> <body> <h2>DMVCFramework - FileUpload DEMO</h2> <form action="/file" method="post" enctype="multipart/form-data"> <input type="file" name="fupload"> <input type="submit"> </form> </body> </html> To emulate this in Smart, the <input type="file ... line will be taken care of by an edit box with type =itFile. You will have to set the name attribute as well : 
    procedure TForm1.InitializeForm; begin   inherited;   // this is a good place to initialize components   var EditBox1 : TW3EditBox := TW3EditBox.Create(self);   EditBox1.SetBounds(50,50,400,30);   EditBox1.InputType := itFile;   EditBox1.handle.setAttribute('name','fupload');  
    The tricky part is to emulate the <form> element.
    While it is doable to make a new component based on the <form> element, it is probably easier to use a FormData object.
    FormData objects can capture the data entered in forms and these objects can then just be sent server-side using normal xmlhttprequests. 
    See here.
    You can link this ajax call to a button, or alternatively to the onchange event of the editbox :
      EditBox1.OnChanged := procedure(sender:TObject)   begin     var formData : variant := new JObject;     asm @formData = new FormData(); end;     formData.append("userfile", EditBox1.handle.files[0]);     var FHttp : TW3HttpRequest := TW3HttpRequest.Create;     FHttp.OnDataReady := nil;  //or a callback procedure     FHttp.open("POST","/file");     FHttp.RequestHeaders.Add("Content-type","multipart/form-data");      FHttp.send(formData);   end; end; I have not used the DelphiMVCFramework before and don't have it installed, so the above may not work. But this is how I would attack this.
     
  8. Thanks
    lynkfs reacted to warleyalex in Declaring Record Type Constants   
    solution I: =========== var // _TableList: array[0..0] of variant = [ _TableList:= [ CLASS TableName:= 'Server'; external 'TableName'; CreateFunc:= @CreateServer; external 'CreateFunc' END ]; // This works ========================================================== var _TableList2: array[0..0] of TMySqlCreateTable = [ ( TableName: 'Server'; CreateFunc: @CreateServer ) ]; // Syntax Error: Constant expression expected [line: 85, column: 52, file: unit2] ========================================================== _TableList2[0].TableName := 'Server'; _TableList2[0].CreateFunc := @CreateServer; // This works  
     
  9. Like
    lynkfs reacted to warleyalex in SMS 3 + mORMot = Error   
    I download the mORMot_and_Open_Source_friends_234301_06b24ae728 today and patched some needed SynCrossPlatform units and mORMotWrappers (generate mORMot cross-platform clients code from the server). and some changes at the project 27 and 29,
    Now, it compiles and works in both SMS 2.2.2.04694 (lastest WinXP compatible) and SMS 3.1.0.80 (development version)! 
    download link: mORMot with SMS 2x and 3x
  10. Like
    lynkfs got a reaction from jarto in printing   
    update 2 :
    after some more testing on different platforms, the conclusion is that the window.print() method basically works on all platforms (Windows, MacOs, iOS, Android) and modern browsers (Chrome, FireFox, Safari), but only using the iFrame setup as mentioned in the prev. posts. The other methods may or may not work.
    The main exception is Chrome and FireFox on iOS where window.print() doesn't work at all : apparently Apple does not allow printing from Chrome in iOS due to it's policy on using alternative browser engines.
    These guys deserve a thumbs down, really
     
     
  11. Like
    lynkfs got a reaction from IElite in Endpoints & Resources ?   
    I'm not up to scratch on node myself, but what I understand is that when the node http-server receives a (post or get) request from a client, the body of the request is read by the server in chunks. Every chunk-read triggers an ondata event, and usually it is there where these chunks need to be concatenated until the onend event happens (end of read of request body).
    There is an example here
  12. Like
    lynkfs got a reaction from IElite in Endpoints & Resources ?   
    yep, express has routing built in
    If you're not using express, then its a matter of parsing the url yourself
    //add unit NodeJS.url //code based on simplehttpserver in featured demos procedure TServer.HandleRequest(Sender: TObject; const Request: TNJHttpRequest; const Response: TNJHttpResponse); var content: String; begin //Example on how to read content data (for example data sent using POST. //TNJHttpRequest itself is actually a readable stream, which can be read //in many ways. Hence, we don't automatically read it before HandleRequest is triggered. var url_parts : variant := url.parse(request.Url); case url_parts.pathname of '/kkk' : begin console.log(url_parts.pathname); end; end; Request.Handle.on('data', procedure(data: variant) begin content := data; end); Request.Handle.on('end', procedure(data: variant) begin Response.&End('Headers: '+request.Headers.ToString()+#13#10+ 'Content: '+Variant(Content)); //These are not automatically freed after HandleRequest as that would //prevent reading of content data using async functions. Request.Free; Response.Free; end); end; http://127.0.0.1:1881/kkk will execute the case branch
     
    side note : console.log() needs
    type   JConsole = class external 'Console'   public     procedure log(data: Variant);   end; var Console external 'console': JConsole; (or maybe there is a unit for that)
  13. Like
    lynkfs reacted to jarto in Enable User Selection of Text   
    I don't know. Maybe because text in Delphi apps is not selectable as default?
    Anyway, I'd propose changing this so, that we don't prevent ContentSelectionMode even if cfAllowSelections is missing. And if cfAllowSelection is in creation flags, we could set ContentSelectionMode automatically to tmsAuto. What do you guys think?
  14. Like
    lynkfs got a reaction from IgorSavkic in printing   
    Working on a component which involves printing.
    I've used external libraries like jsPDF, which generate printable content and they generally work fine. They also have some drawbacks though. So this component is going to rely on the browsers native 'print' command to print a complete page/form, or part thereof.
    1) The print command is tied to a window object (window.print), so the possible implementations are limited to manipulating either
    the current window an iFrame element, which encapsulates a window object a new pop-up window (or new tab) Just to try these out, button 1-3 in the code below correspond to these possible implementations. 
      var Button1 : TW3Button := TW3Button.Create(self);   Button1.SetBounds(20,470,120,30);   Button1.Caption := 'this window';   Button1.OnClick := procedure(sender:TObject)   begin     var originalContents := browserapi.document.body.innerHTML;     browserapi.document.body.innerHTML := SrcDoc;    browserapi.window.print();     browserapi.document.body.innerHTML = originalContents;   end;   var Button2 : TW3Button := TW3Button.Create(self);   Button2.SetBounds(150,470,120,30);   Button2.Caption := 'iframe window'; var IFrame1 := TW3IFrameHtmlElement.Create(self); IFrame1.SetBounds(20,20,400,400);   Button2.OnClick := procedure(sender:TObject)   begin IFrame1.handle.srcdoc := SrcDoc;     IFrame1.handle.contentWindow.print();   end;   var Button3 : TW3Button := TW3Button.Create(self);   Button3.SetBounds(280,470,120,30);   Button3.Caption := 'other window';   Button3.OnClick := procedure(sender:TObject)   begin     asm      var mywindow = window.open('', 'PRINT', 'height=400,width=600');      mywindow.document.write(@SrcDoc);      mywindow.setTimeout(function(){ mywindow.print(); mywindow.close(); }, 1000);      //mywindow.print();      //mywindow.close();     end;   end; //SrcDoc content : see below All of these approaches work. However if printable content contains images or other sizable resources, the actual printing must be delayed until all these resources have been downloaded - so either preload or set an appropriate Timeout, as in Button3
     
    2) Screen and print layout differ in a couple of aspects :
    screens are continuous, paper is not and some elements like tables and images should not be cut in half over page breaks readability of fonts is different on screens and print output hints like blue links on webpages don't translate well to printing many web page elements like menus should not appear on print and more. A good overview is given in this article A separate print stylesheet can handle some/most/all of these concerns. A generic print stylesheet based on @media print is included below. Probably not the solution for each and every situation, but it handles most of the aspects above
      var SrcDoc : string := #'       <!DOCTYPE html>       <HTML>       <HEAD>       <style>         @media print {         @page { margin: 2cm }         body {           font: 13pt Georgia, "Times New Roman", Times, serif;           line-height: 1.3;           background: #fff !important;           color: #000;         }         h1 {           font-size: 24pt;         }         h2, h3, h4 {           font-size: 14pt;           margin-top: 25px;         }         a {           page-break-inside:avoid         }         blockquote {           page-break-inside: avoid;         }         h1, h2, h3, h4, h5, h6 { page-break-after:avoid;           page-break-inside:avoid }         img { page-break-inside:avoid;           page-break-after:avoid; }         table, pre { page-break-inside:avoid }         ul, ol, dl  { page-break-before:avoid }         a:link, a:visited, a {           background: transparent;           color: #520;           font-weight: bold;           text-decoration: underline;           text-align: left;         }         a {           page-break-inside:avoid         }         a[href^=http]:after {           content:" <" attr(href) "> ";         }         $a:after > img {           content: "";         }         article a[href^="#"]:after {           content: "";         }         a:not(:local-link):after {           content:" <" attr(href) "> ";         }         nav, .sidebar, .heading         {           display: none;         }         p, address, li, dt, dd, blockquote {           font-size: 100%         }         code, pre { font-family: "Courier New", Courier, mono}         ul, ol {           list-style: square; margin-left: 18pt;           margin-bottom: 20pt;         }         li {           line-height: 1.6em;         }       }       </style>       </HEAD>       <BODY BGCOLOR="FFFFFF">       <CENTER><IMG SRC="res/logo.png"> </CENTER>       <HR>       <H1>Header H1</H1>       <H2>Header H2</H2>       <P>Paragraph       <P><B>Bold paragraph</B>       <BR><BR><B><I>This is a sentence with some length, longer than the iframe width,       in bold italic.</I></B>       <HR>       </BODY>       </HTML>';
    This generates a print preview in all major browsers, with options to set paper size, select printer, orientation etc.
    see https://www.lynkfs.com/Experiments/ReportWriter/www/reportwriter.html
    Next thing to tackle is scaling.
     
     
  15. Like
    lynkfs got a reaction from jarto in printing   
    update :
    on Android (Chrome) only the iFrame solution works as expected :
    Button1 (manipulating the main window object) prints the whole page rather than just the demo html Button3 (popup window) results in a rendering error see https://www.lynkfs.com/Experiments/ReportWriter/www/reportwriter.html
    Going with the IFrame solution
  16. Like
    lynkfs got a reaction from IElite in printing   
    update :
    on Android (Chrome) only the iFrame solution works as expected :
    Button1 (manipulating the main window object) prints the whole page rather than just the demo html Button3 (popup window) results in a rendering error see https://www.lynkfs.com/Experiments/ReportWriter/www/reportwriter.html
    Going with the IFrame solution
  17. Like
    lynkfs reacted to jarto in Development updates   
    New update available:
    RTL:
    New controls: TW3SpinButton, TW3ArrowUpButton, TW3ArrowDownButton, TW3ArrowLeftButton and TW3ArrowRightButton. Add 1px margin to TW3ButtonBorder to prevent the border from being clipped. Bug fixes to Tween.Effects IDE:
    Bug fixes and changes to renaming of forms: Renaming in Project Manager will not change form class any more. Form class name can be renamed in Object Inspector. Improvements to Project Statistics: Only count Total time when Smart Mobile Studio IDE has focus. Only Count Design time when changes are made in Form Designer. Add clear button. Component Palette: Added new controls New icons for many existing controls
  18. Like
    lynkfs got a reaction from IElite in printing   
    Working on a component which involves printing.
    I've used external libraries like jsPDF, which generate printable content and they generally work fine. They also have some drawbacks though. So this component is going to rely on the browsers native 'print' command to print a complete page/form, or part thereof.
    1) The print command is tied to a window object (window.print), so the possible implementations are limited to manipulating either
    the current window an iFrame element, which encapsulates a window object a new pop-up window (or new tab) Just to try these out, button 1-3 in the code below correspond to these possible implementations. 
      var Button1 : TW3Button := TW3Button.Create(self);   Button1.SetBounds(20,470,120,30);   Button1.Caption := 'this window';   Button1.OnClick := procedure(sender:TObject)   begin     var originalContents := browserapi.document.body.innerHTML;     browserapi.document.body.innerHTML := SrcDoc;    browserapi.window.print();     browserapi.document.body.innerHTML = originalContents;   end;   var Button2 : TW3Button := TW3Button.Create(self);   Button2.SetBounds(150,470,120,30);   Button2.Caption := 'iframe window'; var IFrame1 := TW3IFrameHtmlElement.Create(self); IFrame1.SetBounds(20,20,400,400);   Button2.OnClick := procedure(sender:TObject)   begin IFrame1.handle.srcdoc := SrcDoc;     IFrame1.handle.contentWindow.print();   end;   var Button3 : TW3Button := TW3Button.Create(self);   Button3.SetBounds(280,470,120,30);   Button3.Caption := 'other window';   Button3.OnClick := procedure(sender:TObject)   begin     asm      var mywindow = window.open('', 'PRINT', 'height=400,width=600');      mywindow.document.write(@SrcDoc);      mywindow.setTimeout(function(){ mywindow.print(); mywindow.close(); }, 1000);      //mywindow.print();      //mywindow.close();     end;   end; //SrcDoc content : see below All of these approaches work. However if printable content contains images or other sizable resources, the actual printing must be delayed until all these resources have been downloaded - so either preload or set an appropriate Timeout, as in Button3
     
    2) Screen and print layout differ in a couple of aspects :
    screens are continuous, paper is not and some elements like tables and images should not be cut in half over page breaks readability of fonts is different on screens and print output hints like blue links on webpages don't translate well to printing many web page elements like menus should not appear on print and more. A good overview is given in this article A separate print stylesheet can handle some/most/all of these concerns. A generic print stylesheet based on @media print is included below. Probably not the solution for each and every situation, but it handles most of the aspects above
      var SrcDoc : string := #'       <!DOCTYPE html>       <HTML>       <HEAD>       <style>         @media print {         @page { margin: 2cm }         body {           font: 13pt Georgia, "Times New Roman", Times, serif;           line-height: 1.3;           background: #fff !important;           color: #000;         }         h1 {           font-size: 24pt;         }         h2, h3, h4 {           font-size: 14pt;           margin-top: 25px;         }         a {           page-break-inside:avoid         }         blockquote {           page-break-inside: avoid;         }         h1, h2, h3, h4, h5, h6 { page-break-after:avoid;           page-break-inside:avoid }         img { page-break-inside:avoid;           page-break-after:avoid; }         table, pre { page-break-inside:avoid }         ul, ol, dl  { page-break-before:avoid }         a:link, a:visited, a {           background: transparent;           color: #520;           font-weight: bold;           text-decoration: underline;           text-align: left;         }         a {           page-break-inside:avoid         }         a[href^=http]:after {           content:" <" attr(href) "> ";         }         $a:after > img {           content: "";         }         article a[href^="#"]:after {           content: "";         }         a:not(:local-link):after {           content:" <" attr(href) "> ";         }         nav, .sidebar, .heading         {           display: none;         }         p, address, li, dt, dd, blockquote {           font-size: 100%         }         code, pre { font-family: "Courier New", Courier, mono}         ul, ol {           list-style: square; margin-left: 18pt;           margin-bottom: 20pt;         }         li {           line-height: 1.6em;         }       }       </style>       </HEAD>       <BODY BGCOLOR="FFFFFF">       <CENTER><IMG SRC="res/logo.png"> </CENTER>       <HR>       <H1>Header H1</H1>       <H2>Header H2</H2>       <P>Paragraph       <P><B>Bold paragraph</B>       <BR><BR><B><I>This is a sentence with some length, longer than the iframe width,       in bold italic.</I></B>       <HR>       </BODY>       </HTML>';
    This generates a print preview in all major browsers, with options to set paper size, select printer, orientation etc.
    see https://www.lynkfs.com/Experiments/ReportWriter/www/reportwriter.html
    Next thing to tackle is scaling.
     
     
  19. Like
    lynkfs got a reaction from jarto in printing   
    Working on a component which involves printing.
    I've used external libraries like jsPDF, which generate printable content and they generally work fine. They also have some drawbacks though. So this component is going to rely on the browsers native 'print' command to print a complete page/form, or part thereof.
    1) The print command is tied to a window object (window.print), so the possible implementations are limited to manipulating either
    the current window an iFrame element, which encapsulates a window object a new pop-up window (or new tab) Just to try these out, button 1-3 in the code below correspond to these possible implementations. 
      var Button1 : TW3Button := TW3Button.Create(self);   Button1.SetBounds(20,470,120,30);   Button1.Caption := 'this window';   Button1.OnClick := procedure(sender:TObject)   begin     var originalContents := browserapi.document.body.innerHTML;     browserapi.document.body.innerHTML := SrcDoc;    browserapi.window.print();     browserapi.document.body.innerHTML = originalContents;   end;   var Button2 : TW3Button := TW3Button.Create(self);   Button2.SetBounds(150,470,120,30);   Button2.Caption := 'iframe window'; var IFrame1 := TW3IFrameHtmlElement.Create(self); IFrame1.SetBounds(20,20,400,400);   Button2.OnClick := procedure(sender:TObject)   begin IFrame1.handle.srcdoc := SrcDoc;     IFrame1.handle.contentWindow.print();   end;   var Button3 : TW3Button := TW3Button.Create(self);   Button3.SetBounds(280,470,120,30);   Button3.Caption := 'other window';   Button3.OnClick := procedure(sender:TObject)   begin     asm      var mywindow = window.open('', 'PRINT', 'height=400,width=600');      mywindow.document.write(@SrcDoc);      mywindow.setTimeout(function(){ mywindow.print(); mywindow.close(); }, 1000);      //mywindow.print();      //mywindow.close();     end;   end; //SrcDoc content : see below All of these approaches work. However if printable content contains images or other sizable resources, the actual printing must be delayed until all these resources have been downloaded - so either preload or set an appropriate Timeout, as in Button3
     
    2) Screen and print layout differ in a couple of aspects :
    screens are continuous, paper is not and some elements like tables and images should not be cut in half over page breaks readability of fonts is different on screens and print output hints like blue links on webpages don't translate well to printing many web page elements like menus should not appear on print and more. A good overview is given in this article A separate print stylesheet can handle some/most/all of these concerns. A generic print stylesheet based on @media print is included below. Probably not the solution for each and every situation, but it handles most of the aspects above
      var SrcDoc : string := #'       <!DOCTYPE html>       <HTML>       <HEAD>       <style>         @media print {         @page { margin: 2cm }         body {           font: 13pt Georgia, "Times New Roman", Times, serif;           line-height: 1.3;           background: #fff !important;           color: #000;         }         h1 {           font-size: 24pt;         }         h2, h3, h4 {           font-size: 14pt;           margin-top: 25px;         }         a {           page-break-inside:avoid         }         blockquote {           page-break-inside: avoid;         }         h1, h2, h3, h4, h5, h6 { page-break-after:avoid;           page-break-inside:avoid }         img { page-break-inside:avoid;           page-break-after:avoid; }         table, pre { page-break-inside:avoid }         ul, ol, dl  { page-break-before:avoid }         a:link, a:visited, a {           background: transparent;           color: #520;           font-weight: bold;           text-decoration: underline;           text-align: left;         }         a {           page-break-inside:avoid         }         a[href^=http]:after {           content:" <" attr(href) "> ";         }         $a:after > img {           content: "";         }         article a[href^="#"]:after {           content: "";         }         a:not(:local-link):after {           content:" <" attr(href) "> ";         }         nav, .sidebar, .heading         {           display: none;         }         p, address, li, dt, dd, blockquote {           font-size: 100%         }         code, pre { font-family: "Courier New", Courier, mono}         ul, ol {           list-style: square; margin-left: 18pt;           margin-bottom: 20pt;         }         li {           line-height: 1.6em;         }       }       </style>       </HEAD>       <BODY BGCOLOR="FFFFFF">       <CENTER><IMG SRC="res/logo.png"> </CENTER>       <HR>       <H1>Header H1</H1>       <H2>Header H2</H2>       <P>Paragraph       <P><B>Bold paragraph</B>       <BR><BR><B><I>This is a sentence with some length, longer than the iframe width,       in bold italic.</I></B>       <HR>       </BODY>       </HTML>';
    This generates a print preview in all major browsers, with options to set paper size, select printer, orientation etc.
    see https://www.lynkfs.com/Experiments/ReportWriter/www/reportwriter.html
    Next thing to tackle is scaling.
     
     
  20. Like
    lynkfs got a reaction from IElite in Renaming form in ObjectInspector   
    Looking at @IgorSavkic's argument to be able to have different form class names and unit names, I agree with him.
    We all have different styles and the IDE should accommodate that
    (so only the project manager should change unit/file names)
  21. 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
     
     
     
  22. Like
    lynkfs got a reaction from jarto in Renaming form in ObjectInspector   
    This behaviour is not limited to Forms but to other classes as well 
    For example: Looking at the 'unit structure' tab with the SmartCL.Borders unit open, I can rename the TW3Border class to something else
    For Forms I don't see any advantage of changing a form class and not change the unit and filename, but for other object classes changing the class name only is somewhat handy
    (although a search and replace old/new classname will have the same effect)
  23. Thanks
    lynkfs got a reaction from IgorSavkic 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
     
     
     
  24. Like
    lynkfs got a reaction from IElite in Send an email ?   
    This api doesn't allow local execution (file:///C:/Users/.../www/index.html) but requires a http(s) based url (https://.../www/index.html)
    so index.html / index.js needs to be server-side
  25. Like
    lynkfs got a reaction from jorn 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
     
     
     
×
×
  • Create New...