From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail2-relais-roc.national.inria.fr (mail2-relais-roc.national.inria.fr [192.134.164.83]) by c5ff346549e7 (Postfix) with ESMTPS id B67DC5D5 for ; Tue, 15 Mar 2022 09:59:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=inria.fr; s=dc; h=from:to:date:message-id:mime-version:subject:reply-to: sender:list-id:list-help:list-subscribe:list-unsubscribe: list-post:list-owner:list-archive; bh=yLENT9C7mfZpYtZ0Ru86tY7P3tAjRHw1XcP9cl5LZtA=; b=bQVZWqoy92b6n1kfU/OpezFDsp7z22C8I5rcsBar28jkrHYy+d61WtYk cH+Y0qxLHI7dT/5is7I27qBuqCJ4d8f1FGPbBiGbknjikHot44EV63e/V YyJTJ0x/ZZWDkPAmO2OE99auW2LXSlGfAGZy8/GsRwsmviHt/YoWPk2X+ I=; Authentication-Results: mail2-relais-roc.national.inria.fr; dkim=none (message not signed) header.i=none; spf=SoftFail smtp.mailfrom=caml-list-owner@inria.fr; spf=None smtp.helo=postmaster@sympa.inria.fr Received-SPF: SoftFail (mail2-relais-roc.national.inria.fr: domain of caml-list-owner@inria.fr is inclined to not designate 128.93.162.160 as permitted sender) identity=mailfrom; client-ip=128.93.162.160; receiver=mail2-relais-roc.national.inria.fr; envelope-from="caml-list-owner@inria.fr"; x-sender="caml-list-owner@inria.fr"; x-conformance=spf_only; x-record-type="v=spf1"; x-record-text="v=spf1 ip4:192.134.164.0/24 mx ~all" Received-SPF: None (mail2-relais-roc.national.inria.fr: no sender authenticity information available from domain of postmaster@sympa.inria.fr) identity=helo; client-ip=128.93.162.160; receiver=mail2-relais-roc.national.inria.fr; envelope-from="caml-list-owner@inria.fr"; x-sender="postmaster@sympa.inria.fr"; x-conformance=spf_only X-IronPort-AV: E=Sophos;i="5.90,183,1643670000"; d="scan'208,217";a="26186106" Received: from prod-listesu18.inria.fr (HELO sympa.inria.fr) ([128.93.162.160]) by mail2-relais-roc.national.inria.fr with ESMTP; 15 Mar 2022 10:59:29 +0100 Received: by sympa.inria.fr (Postfix, from userid 20132) id 89B5FE031F; Tue, 15 Mar 2022 10:59:29 +0100 (CET) Received: from mail2-relais-roc.national.inria.fr (mail2-relais-roc.national.inria.fr [192.134.164.83]) by sympa.inria.fr (Postfix) with ESMTPS id DB1B3E0045 for ; Tue, 15 Mar 2022 10:59:24 +0100 (CET) IronPort-SDR: NMOiSL9nPQ+Anhbkxqi3l6F3gOtA+HCY9A3y1zkojyaalWHfGljwXXAJQtgsMO43B1LT2aFI11 Yyw79jsVapQLRXmRdpRK0PxZG9eKkzSYRfoTEqUZms3ZnZDqaPA8/rupjGYbOF2LCu5/GCxIgs qrH7Oo354L6nEuAAazZVV4KgBTSYssn8CIr+FLjqHp7aFHLr6b5TNF+Y1dQA37/4GLN4pYJ+K9 l/6VOftu8z8JetrnH1+pQdW1aTLIg6BIzwOijJXFFBbi5V657l4FcGSS+0hIz+zO4JQK/Nd6zu ToxXw6J0t9Qp4LOiTjtp/it3 X-IPAS-Result: =?us-ascii?q?A0DXAAAcYzBimCIeaIFahARfKBkBZFcrBwhEhFSJBogSi?= =?us-ascii?q?UyGdo1HA08QAQMBDSoBDgUBAgQBAYUghBACHgYBBTMTAQIEAQEBAQMCAwEBA?= =?us-ascii?q?QEBAQMBAQUBAQECAQECAwQBEwEBAQEBAQEBCQsJBwYMBRAOBTxkZASBSwSBd?= =?us-ascii?q?As0DYI1DAwDA4N3ARgJBAZAJSMDFAEGAwIEDQEXARQKFwESGoIMXgGDFgUKk?= =?us-ascii?q?VacDH8ygQGDTwEDAgENAw8vg3OBZA0CFIECF4YUVkqDAwmEBgInEIFVRIItg?= =?us-ascii?q?RFKB26BQQEOAQF6FwEBAQEBgScUAQGDOheCTgSWWwgCBDgIHlYUBRQWAQEgA?= =?us-ascii?q?i4IIxUBBxsBJg4VBS8BFgIeDQIDkV4kAg+YR5QZejQHg0yBOgYLiCSBHYxzi?= =?us-ascii?q?CGDc4FOil+YGSGWNiCJGIEPCYJDlBQdCAsfhQaBTiqBTRwCDAczGjBDgmkJR?= =?us-ascii?q?QEDAg0BAgIDAQIBAgkBAQJUjVUWgQQBCII8B2VZgSaBdTuFSQJANAIBATQCB?= =?us-ascii?q?gEKAQEDCYVjAQEFEwsBhnkrgh0BAQ?= IronPort-PHdr: A9a23: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 IronPort-Data: A9a23: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 28JSw+/Lw== IronPort-HdrOrdr: A9a23:05mECaxKGjmwqVcYNU9xKrPwK71zdoMgy1knxilNoH1uEvBw+P rAoB1273XJYVUqOU3I++rvBEDoexq1nqKdirN8AV7NZmTbkVrtBL4nx4rvyT/tFkTFh41g/J YlVbNxTPn5DV0St7ee3OBUKadD/OW6 X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="5.90,183,1643670000"; d="scan'208,217";a="26186085" X-MGA-submission: =?us-ascii?q?MDFqU7q/gKIb9kXDM9sIytJokWRx1U9MpqY/Dl?= =?us-ascii?q?dl22t1N4rEe48NHdN28YKLhjvkglrKvzZk2GQcVeE+0btXBGidS1xhaR?= =?us-ascii?q?Ya1u/X48QnWHh4/ePzvcHbMwAR9/wgTwTdZ4DF8VJVJW0FGsZPuqzMU6?= =?us-ascii?q?T1KOtvzPkvnS30SF98mbl7Cg=3D=3D?= Received: from mx1.polytechnique.org ([129.104.30.34]) by mail2-smtp-roc.national.inria.fr with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Mar 2022 10:59:24 +0100 Received: from set (set.irisa.fr [131.254.10.170]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ssl.polytechnique.org (Postfix) with ESMTPSA id 0518F565B45; Tue, 15 Mar 2022 10:59:23 +0100 (CET) From: Alan Schmitt To: "lwn" , "cwn" , caml-list@inria.fr Date: Tue, 15 Mar 2022 10:59:22 +0100 Message-ID: <87a6dr1qpx.fsf@m4x.org> MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="=-=-=" X-AV-Checked: ClamAV using ClamSMTP at svoboda.polytechnique.org (Tue Mar 15 10:59:23 2022 +0100 (CET)) X-Spam-Flag: No, tests=bogofilter, spamicity=0.065726, queueID=4951B565B46 X-Org-Mail: alan.schmitt.1995@polytechnique.org Subject: [Caml-list] Attn: Development Editor, Latest OCaml Weekly News Reply-To: Alan Schmitt X-Loop: caml-list@inria.fr X-Sequence: 18727 Errors-To: caml-list-owner@inria.fr Precedence: list Precedence: bulk Sender: caml-list-request@inria.fr X-no-archive: yes List-Id: List-Help: List-Subscribe: List-Unsubscribe: List-Post: List-Owner: List-Archive: Archived-At: --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: base64 SGVsbG8NCg0KSGVyZSBpcyB0aGUgbGF0ZXN0IE9DYW1sIFdlZWtseSBOZXdzLCBmb3IgdGhlIHdl ZWsgb2YgTWFyY2ggMDggdG8gMTUsDQoyMDIyLg0KDQpUYWJsZSBvZiBDb250ZW50cw0K4pSA4pSA 4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSADQoNClJvYnVyIFJl cHJvZHVjaWJsZSBCdWlsZHMNCk9DYW1sIFRlWG1hY3MgcGx1Z2luDQpSZWxlYXNlIG9mIG9jYW1s LXNmL2xlYXJuLW9jYW1sOjAuMTQuMA0KVHV0b3JpYWw6IFJvZ3VlbGlrZSB3aXRoIGVmZmVjdCBo YW5kbGVycw0KQXdlc29tZSBNdWx0aWNvcmUgT0NhbWwgYW5kIE11bHRpY29yZSBNb25vcmVwbw0K cHB4X3ZpZXdwYXR0ZXJuIGluaXRpYWwgcmVsZWFzZQ0KT2xkIENXTg0KDQoNClJvYnVyIFJlcHJv ZHVjaWJsZSBCdWlsZHMNCuKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKV kOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkA0KDQogIEFyY2hpdmU6DQogIDxodHRw czovL2Rpc2N1c3Mub2NhbWwub3JnL3QvYW5uLXJvYnVyLXJlcHJvZHVjaWJsZS1idWlsZHMvODgy Ny82Pg0KDQoNCkNvbnRpbnVpbmcgdGhpcyB0aHJlYWQsIEhhbm5lcyBNZWhuZXJ0IGFubm91bmNl ZA0K4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA 4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA 4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSADQoNCiAgVGhlIGJhY2tncm91bmQgYXJ0 aWNsZSBieSBAcmFuZCBpcyBub3cgb25saW5lDQogIDxodHRwczovL3I3cDUuZWFydGgvYmxvZy8y MDIyLTMtNy9CdWlsZGVyLXdlYiUyMHZpc3VhbGl6YXRpb25zJTIwYXQlMjBSb2J1cj4NCg0KDQpP Q2FtbCBUZVhtYWNzIHBsdWdpbg0K4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ 4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQDQoNCiAgQXJjaGl2ZToNCiAgPGh0dHBzOi8vc3ltcGEu aW5yaWEuZnIvc3ltcGEvYXJjL2NhbWwtbGlzdC8yMDIyLTAzL21zZzAwMDA5Lmh0bWw+DQoNCg0K Tmljb2xhcyBSYXRpZXIgYW5ub3VuY2VkDQrilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDi lIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIANCg0KICBJIG1hZGUgYSBi YXNpYyBPQ2FtbCBwbHVnaW4gZm9yIFRlWG1hY3MgKDxodHRwOi8vd3d3LnRleG1hY3Mub3JnPikg SQ0KICB3b3VsZCBsaWtlIHRvIGtlZXAgaXQgc2ltcGxlLCBidXQgY29tbWVudHMgYW5kIGltcHJv dmVtZW50cyBhcmUNCiAgd2VsY29tZS4NCiAgPGh0dHA6Ly9mb3J1bS50ZXhtYWNzLmNuL3Qvb2Nh bWwtYS1iYXNpYy1vY2FtbC1wbHVnaW4tZm9yLXRleG1hY3MvODEzPg0KDQoNClJlbGVhc2Ugb2Yg b2NhbWwtc2YvbGVhcm4tb2NhbWw6MC4xNC4wDQrilZDilZDilZDilZDilZDilZDilZDilZDilZDi lZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDi lZDilZDilZDilZDilZDilZDilZDilZDilZDilZANCg0KICBBcmNoaXZlOg0KICA8aHR0cHM6Ly9k aXNjdXNzLm9jYW1sLm9yZy90L2Fubi1yZWxlYXNlLW9mLW9jYW1sLXNmLWxlYXJuLW9jYW1sLTAt MTQtMC85NDkxLzE+DQoNCg0KWXVydWcgYW5ub3VuY2VkDQrilIDilIDilIDilIDilIDilIDilIDi lIDilIDilIDilIDilIDilIDilIDilIANCg0KICBXZSBhcmUgdmVyeSBwbGVhc2VkIHRvIGFubm91 bmNlIHRoZSBsYXRlc3Qgc3RhYmxlIHJlbGVhc2Ugb2YNCiAgW0xlYXJuLU9DYW1sXSwgdmVyc2lv biBgMC4xNC4wJy4NCg0KICBNYW55IHRoYW5rcyB0byBhbGwgdXNlcnMgYW5kIGRldmVsb3BlcnMg d2hvIHJlcG9ydGVkIGJ1Z3MsIGNvbnRyaWJ1dGVkDQogIGZlYXR1cmVzLCBvciBwYXRjaGVzISBT cGVjaWFsIHRoYW5rcyB0byBAZXJpa21kIHdobyBtYWRlIG1hbnkgb2YgdGhlDQogIGNoYW5nZXMg aW5jbHVkZWQgaW4gdGhpcyByZWxlYXNlLg0KDQogIEEgKG1vc3RseSkgY29tcHJlaGVuc2l2ZSBs aXN0IG9mIHRoZSBmZWF0dXJlcywgZml4ZXMsIGFuZCBlbmhhbmNlbWVudHMNCiAgb2ZmZXJlZCBi eSB0aGlzIHJlbGVhc2UgaXMgYXZhaWxhYmxlIGluIFt0aGUgUmVsZWFzZSBOb3RlcyBdLg0KDQog IEEgYnJpZWYgYW5kIGluY29tcGxldGUgc3VtbWFyeSBvZiB0aGUgY2hhbmdlczoNCg0KICDigKIg QSBsb25nLXN0YW5kaW5nIGJ1ZyBoYXMgYmVlbiBmaXhlZC4gVGhpcyBidWcgd2FzIHRyaWdnZXJl ZCB3aGVuIHRoZQ0KICAgIHVzZXIgb3BlbmVkIHNldmVyYWwgc2Vzc2lvbnM6IHRoZSBhdXRvLXN5 bmMgbWVjaGFuaXNtIGNvdWxkIGxlYWQgdG8NCiAgICBvdmVyd3JpdGluZyB0aGUgc3R1ZGVudCdz IGNvZGUgd2l0aCBhbiBvbGRlciB2ZXJzaW9uLg0KDQogIOKAoiBUaGUgcmVsZWFzZSBhc3NldHMg bm93IGluY2x1ZGUgYSB6aXAgZmlsZSBjb250YWluaW5nIHRoZSBjb250ZW50cyBvZg0KICAgIHRo ZSBgd3d3YCBkaXJlY3RvcnkuIFRoaXMgZWFzZXMgdGhlIHVzYWdlIG9mIHRoZSBkaXN0cmlidXRl ZA0KICAgIGJpbmFyaWVzLg0KDQogIElmIG5lZWQgYmUsIGZlZWwgZnJlZSB0byBvcGVuIGlzc3Vl cyBpbiB0aGUgW0xlYXJuLU9DYW1sIGJ1ZyB0cmFja2VyXQ0KICBvciB0aGUgW2xlYXJuLW9jYW1s LmVsIGJ1ZyB0cmFja2VyXSwgb3IgcG9zdCBpbiB0aGlzIHRocmVhZCB0byBzaGFyZQ0KICB0aG91 Z2h0cyBvciBleHBlcmllbmNlLWZlZWRiYWNrLg0KDQogIEhhcHB5IE9DYW1sIGxlYXJuaW5nIGFu ZCB0ZWFjaGluZyENCg0KDQpbTGVhcm4tT0NhbWxdIDxodHRwczovL2dpdGh1Yi5jb20vb2NhbWwt c2YvbGVhcm4tb2NhbWw+DQoNClt0aGUgUmVsZWFzZSBOb3RlcyBdDQo8aHR0cHM6Ly9naXRodWIu Y29tL29jYW1sLXNmL2xlYXJuLW9jYW1sL3JlbGVhc2VzL3RhZy92MC4xNC4wPg0KDQpbTGVhcm4t T0NhbWwgYnVnIHRyYWNrZXJdDQo8aHR0cHM6Ly9naXRodWIuY29tL29jYW1sLXNmL2xlYXJuLW9j YW1sL2lzc3Vlcz4NCg0KW2xlYXJuLW9jYW1sLmVsIGJ1ZyB0cmFja2VyXQ0KPGh0dHBzOi8vZ2l0 aHViLmNvbS9wZml0YXhlbC9sZWFybi1vY2FtbC5lbC9pc3N1ZXM+DQoNCg0KVHV0b3JpYWw6IFJv Z3VlbGlrZSB3aXRoIGVmZmVjdCBoYW5kbGVycw0K4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ 4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ 4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQDQoNCiAgQXJjaGl2ZToNCiAgPGh0 dHBzOi8vZGlzY3Vzcy5vY2FtbC5vcmcvdC90dXRvcmlhbC1yb2d1ZWxpa2Utd2l0aC1lZmZlY3Qt aGFuZGxlcnMvOTQyMi8xOD4NCg0KDQpDb250aW51aW5nIHRoaXMgdGhyZWFkLCBzdHcgc2FpZA0K 4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA 4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSADQoNCiAgU29ycnkgYWJvdXQg dGhlIGxhdGUgcmVwbHksIEkgd2FzIGJ1c3kgYWN0dWFsbHkgdmVyaWZ5aW5nIHRoYXQgbXkNCiAg Y29uY2VwdCB3b3JrcyBvdXQuIFRoYW5rZnVsbHkgaXQgZG9lcyA6c21pbGU6DQoNCiAgVGhlIFVJ IGZyYW1ld29yayBpcyBpbnNwaXJlZCBieSBbQ29uY3VyXSB3aGljaCBtZWFucyB0aGF0IGV2ZXJ5 IHdpZGdldA0KICBsaXN0ZW5zIGZvciBzb21lIHNldCBvZiBldmVudHMgYW5kIHN1c3BlbmRzIGNv bXB1dGF0aW9uIHVudGlsIG9uZSBvZg0KICB0aGVzZSBldmVudHMgb2NjdXJzLiBPbmNlIGl0IGRv ZXMsIGl0IGNvbnRpbnVlcyBleGVjdXRpb24gdW50aWwgaXQNCiAgZW5jb3VudGVyIHRoZSBuZXh0 IGF3YWl0IGF0IHdoaWNoIHBvaW50IGl0IHdpbGwgc3VzcGVuZCBvbmNlDQogIG1vcmUuIE9uY2Ug YSB3aWRnZXQgaGFzIGZ1bGZpbGxlZCBpdHMgcHVycG9zZSBpdCB0ZXJtaW5hdGVzIHdpdGggc29t ZQ0KICByZXR1cm4gdmFsdWUgKGUuZy4gdGV4dCBpbnB1dCBpcyBjb25maXJtZWQgd2l0aCBlbnRl ciAtPiByZXR1cm4gd2l0aCBhDQogIHN0cmluZykuICBDb21wbGV4IFVJcyBhcmUgdGhlbiBidWls dCBieSBjb21wb3Npbmcgc2ltcGxlciB3aWRnZXRzLiBBDQogIG1vcmUgZGV0YWlsZWQgZXhwbGFu YXRpb24gY2FuIGJlIGZvdW5kIGluIHRoZSBsaW5rIGFib3ZlLg0KDQogIEkndmUgaW1wbGVtZW50 ZWQgdGhpcyBjb25jZXB0IHVzaW5nIGFuIGF3YWl0IGZ1bmN0aW9uIHRoYXQgdGFrZXMgYQ0KICBs aXN0IG9mIHRyaWdnZXJzIGFuZCBhIGhhbmRsZXIgZm9yIGVhY2ggcG9zc2libGUgZXZlbnQ6DQog IOKUjOKUgOKUgOKUgOKUgA0KICDilIIgZWZmZWN0IEF3YWl0IDogRXZlbnQudCBsaXN0IC0+IEV2 ZW50LnQNCiAg4pSCIGxldCByZWMgYXdhaXQgdHJpZ2dlcnMgaGFuZGxlciA9DQogIOKUgiAgIGhh bmRsZXIgKEVmZmVjdEhhbmRsZXJzLnBlcmZvcm0gKEF3YWl0IHRyaWdnZXJzKSkNCiAg4pSCIA0K ICDilIIgbGV0IHJlYyBjaGVja19ib3ggY2hlY2tlZCAgPQ0KICDilIIgICAoKiBkaXNwbGF5IGNo ZWNrIGJveCAqKQ0KICDilIIgICAuLi47DQogIOKUgiAgIGF3YWl0IFtNb3VzZV9wcmVzczsgS2V5 X3ByZXNzXSAoZnVuY3Rpb24NCiAg4pSCICAgfCBNb3VzZV9wcmVzcyAtPg0KICDilIIgICAgIHBy aW50X2VuZGxpbmUgIkkndmUgYmVlbiAodW4tKWNoZWNrZWQhIjsNCiAg4pSCICAgICBjaGVja19i b3ggKG5vdCBjaGVja2VkKQ0KICDilIIgICB8IEtleV9wcmVzcyAtPiAoKiBUZXJtaW5hdGUgaWYg YW55IGtleSBpcyBwcmVzc2VkICopIGNoZWNrZWQpDQogIOKUlOKUgOKUgOKUgOKUgA0KDQogIEV2 ZXJ5IHdpZGdldCBjYW4gdGhlbiBiZSBpbXBsZW1lbnRlZCBhcyBhIGZ1bmN0aW9uIHdoaWNoIGRp c3BsYXlzIHRoZQ0KICB3aWRnZXQgYW5kIHBlcmZvcm1zIGFuIGBBd2FpdCB0cmlnZ2Vycycgd2hp Y2ggaXMgcmVzdW1lZCBieSBwYXNzaW5nIGFuDQogIGV2ZW50IGZyb20gYHRyaWdnZXJzJywgZm9y IGV4YW1wbGUgdGhlIGNoZWNrIGJveCBhYm92ZS4NCg0KICBUaGUgbW9zdCBjb21wbGV4IHdpZGdl dCBJJ3ZlIGltcGxlbWVudGVkIHNvIGZhciBpcyBhIHNpbmdsZSBsaW5lIHRleHQNCiAgaW5wdXQu IEl0IGNhbiBiZSBjbGlja2VkIG9yIHNlbGVjdGVkIHdpdGggdGFiLiAgTW92aW5nIHRoZSBtb3Vz ZSB3aGlsZQ0KICBob2xkaW5nIHRoZSBidXR0b24gZG93biBjaGFuZ2VzIHRoZSBzZWxlY3Rpb24u IEFzIGFuIGF1dG9tYXRvbjoNCg0KICA8aHR0cHM6Ly9hd3MxLmRpc2NvdXJzZS1jZG4uY29tL3N0 YW5kYXJkMTEvdXBsb2Fkcy9vY2FtbC9vcmlnaW5hbC8yWC81LzU3NGUxNjRiNjE4OTYwODI4M2Rl MzJkOWYzNzU1MzRjYTgwY2FmZmEucG5nPg0KDQogIE9idmlvdXNseSwgdGhpcyBpcyBub3QgYSBk aXJlY3RlZCBhY3ljbGljIGdyYXBoIGFuZCB0aGVyZWZvcmUgbm90IGENCiAgcGVyZmVjdCBmaXQg Zm9yIHRoZSBpbXBsaWNpdCBzdGF0ZSBzdG9yZWQgaW4gdGhlDQogIGNvbnRpbnVhdGlvbi4gU3Bl Y2lmaWNhbGx5LCBgUHJlc3NlZCcgaGFzIGFuIGVkZ2UgdG8gb25lIG9mIGl0cw0KICBtdWx0aXBs ZSBwYXJlbnRzLiBXZSBjYW4gZXh0cmFjdCB0aGUgYFByZXNzZWQnIHN0YXRlIGludG8gaXRzIG93 bg0KICBmdW5jdGlvbiBhbmQgdGhlcmVmb3JlIGF2b2lkIHRoaXMgaXNzdWUgYnkgJ2R1cGxpY2F0 aW5nJyB0aGlzDQogIHN0YXRlLiBOb3cgYFByZXNzZWQnIG5vIGxvbmdlciBoYXMgbXVsdGlwbGUg cGFyZW50czoNCg0KICA8aHR0cHM6Ly9hd3MxLmRpc2NvdXJzZS1jZG4uY29tL3N0YW5kYXJkMTEv dXBsb2Fkcy9vY2FtbC9vcmlnaW5hbC8yWC83LzcwYTM0ZDJmNGJiODE4MDBhNWUzYjEyYjhlNDkx NDdhMGQ4MGVjZTQucG5nPg0KDQogIFNvbWUgY3ljbGVzIHJlbWFpbiBhbmQgd2UgY2FuJ3QgcmVt b3ZlIHRoZW0gYmVjYXVzZSB0aGV5IGFyZSBlc3NlbnRpYWwNCiAgdG8gdGhlIGZ1bmN0aW9uYWxp dHkuIEluc3RlYWQgd2UgdGhyb3cgYW4gYGV4Y2VwdGlvbiBSZXBlYXQnIHRoYXQNCiAgcmV0dXJu cyB1cyB0byBhIHBhcmVudCBub2RlIChleHBsaWNpdGx5IHNob3duIGZvciBGb2N1c2VkIC0+IFBy ZXNzZWQNCiAgLT4gUmVsZWFzZWQgLT4gRm9jdXNlZCkuICBUbyBkbyB0aGF0IHdlIG1vZGlmeSBg YXdhaXQnOg0KICDilIzilIDilIDilIDilIANCiAg4pSCIGxldCByZWMgYXdhaXQgdHJpZ2dlcnMg aGFuZGxlciA9DQogIOKUgiAgIHRyeSBoYW5kbGVyIChFZmZlY3RIYW5kbGVycy5wZXJmb3JtIChB d2FpdCB0cmlnZ2VycykpIHdpdGgNCiAg4pSCICAgfCBSZXBlYXQgLT4gYXdhaXQgdHJpZ2dlcnMg aGFuZGxlcg0KICDilJTilIDilIDilIDilIANCiAgSW4gdGhlIGVuZCB0aGlzIHJlc3VsdHMgaW4g dGhpcyBtYWluIG1ldGhvZCBmb3IgdGhlIHRleHQgaW5wdXQsIHdpdGgNCiAgb25seSBtaW5vciBz aW1wbGlmaWNhdGlvbnM6DQogIOKUjOKUgOKUgOKUgOKUgA0KICDilIIgbWV0aG9kIGV4ZWN1dGUg PQ0KICDilIIgICAoKiBSZXByZXNlbnQgdGhlIFByZXNzZWQgc3RhdGUuDQogIOKUgiAgICAgIFdl IGF3YWl0IHRoZSBNb3VzZV9yZWxlYXNlIGFuZCBoYW5kbGUgTW91c2VfbW90aW9uIHdoaWxlIHdl IHdhaXQuICopDQogIOKUgiAgIGxldCBwcmVzc2VkICh4LF8pID0NCiAg4pSCICAgICBzZWxlY3Rp b24gPC0gUG9pbnQgeDsNCiAg4pSCICAgICBhd2FpdCBbYE1vdXNlX3JlbGVhc2U7IGBNb3VzZV9t b3Rpb25dIEBAIGZ1bmN0aW9uDQogIOKUgiAgICAgfCBgTW91c2VfcmVsZWFzZSAoXywgTE1CKSAt Pg0KICDilIIgICAgICAgKCkNCiAg4pSCICAgICB8IGBNb3VzZV9tb3Rpb24gKHgsXykgLT4NCiAg 4pSCICAgICAgIHNlbGYjc2VsZWN0IHg7DQogIOKUgiAgICAgICByYWlzZSBSZXBlYXQgKCogVGhp cyByZXN0YXJ0cyB0aGUgYXdhaXQgZnVuY3Rpb24gKikNCiAg4pSCICAgICB8IF8gLT4NCiAg4pSC ICAgICAgIHJhaXNlIFJlcGVhdA0KICDilIIgICBpbg0KICDilIIgDQogIOKUgiAgICgqIFdlIHN0 YXJ0IGluIHRoZSBVbmZvY3VzZWQgc3RhdGUgKikNCiAg4pSCICAgYmVnaW4NCiAg4pSCICAgICBh d2FpdCBbYE1vdXNlX3ByZXNzOyBgS2V5X3ByZXNzXSBAQCBmdW5jdGlvbg0KICDilIIgICAgIHwg YE1vdXNlX3ByZXNzIChwb3MsIExNQikgLT4NCiAg4pSCICAgICAgICAoKiBXZSBoYXZlIHJlZ2lz dGVyZWQgdGhlIHByZXNzLCBidXQgb25seSB3aGVuIGl0IGlzIHJlbGVhc2VkDQogIOKUgiAJICB3 aWxsIHdlIGJlIGZvY3VzZWQuICopDQogIOKUgiAgICAgICAgcHJlc3NlZCBwb3MNCiAg4pSCICAg ICB8IGBLZXlfcHJlc3MgVGFiIC0+DQogIOKUgiAgICAgICBzZWxlY3Rpb24gPC0gQXJlYSAoMCwg TGlzdC5sZW5ndGgga2V5cykNCiAg4pSCICAgICB8IF8gLT4gcmFpc2UgUmVwZWF0DQogIOKUgiAg IGVuZDsNCiAg4pSCIA0KICDilIIgICAoKiBXZSBtb3ZlIGludG8gdGhlIEZvY3VzZWQgc3RhdGUg KikNCiAg4pSCICAgYmVnaW4NCiAg4pSCICAgICBhd2FpdCBbYENvZGVwb2ludDsgYEtleV9wcmVz czsgYE1vdXNlX3ByZXNzXSBAQCBmdW5jdGlvbg0KICDilIIgICAgIHwgYEtleV9wcmVzcyBUYWIg fCBgS2V5X3ByZXNzIFJldHVybiAtPg0KICDilIIgICAgICAgKCkgKCogVGhlIG9ubHkgcGF0aCB3 aXRob3V0IHJhaXNpbmcgUmVwZWF0Lg0KICDilIIgCSAgICBUaGVyZWZvcmUgd2Ugb25seSBsZWF2 ZSB0aGlzIGF3YWl0IHdoZW4gYSB0YWIgb3IgcmV0dXJuIG9jY3VycyAqKQ0KICDilIIgICAgIHwg YE1vdXNlX3ByZXNzIChwb3MsIExNQikgLT4NCiAg4pSCICAgICAgIHByZXNzZWQgcG9zOw0KICDi lIIgICAgICAgcmFpc2UgUmVwZWF0DQogIOKUgiAgICAgfCBgS2V5X3ByZXNzIGMgLT4NCiAg4pSC ICAgICAgIHNlbGYjaW5zZXJ0IGM7DQogIOKUgiAgICAgICByYWlzZSBSZXBlYXQNCiAg4pSCICAg ICB8IF8gLT4gcmFpc2UgUmVwZWF0DQogIOKUgiAgIGVuZDsNCiAg4pSCICAgKCogV2UgaGF2ZSBy ZWFjaGVkIHRoZSBmaW5pc2hlZCBzdGF0ZS4gV2UgY2FuIG5vdyByZXR1cm4gdGhlIGVudGVyZWQg dGV4dC4gKikNCiAg4pSCICAgc2VsZiN0ZXh0DQogIOKUlOKUgOKUgOKUgOKUgA0KICBJIHRoaW5r IHRoYXQgdGhpcyBtZXRob2QgY2FwdHVyZXMgdGhlIGF1dG9tYXRvbiBhYm92ZSBxdWl0ZSBuaWNl bHkgYW5kDQogIGNhbiBiZSByZWxhdGl2ZWx5IGVhc2lseSB1bmRlcnN0b29kIChob3BlZnVsbHkg ZXZlbiB3aGVuIG9uZSBpcw0KICB1bmZhbWlsaWFyIHdpdGggdGhlIGZyYW1ld29yayBhbmQgYWNj ZXB0cyB0aGF0IHNvbWUgbWFnaWMgaXMgaGFwcGVuaW5nDQogIGluIHRoZSBiYWNrZ3JvdW5kICg6 ICkuICBJbXBsZW1lbnRpbmcgYXV0b21hdG9ucyBpbiB0ZXJtcyBvZiBlZmZlY3QNCiAgaGFuZGxl cnMgc2VlbXMgdG8gd29yayBxdWl0ZSB3ZWxsLCBhdCBsZWFzdCBmb3IgZ2FtZXMgYW5kIFVJcy4g V2hhdA0KICB0aGVzZSBhdXRvbWF0b25zIGhhdmUgaW4gY29tbW9uIGlzIHRoYXQgdGhleSBjYW4g YmUgdGhvdWdodCBvZiBhcw0KICBmbG93cywgc3RhcnRpbmcgYXQgc29tZSBzdGF0ZSBhbmQgZW5k aW5nIGF0IG9uZSBvZiBtdWx0aXBsZSBmaW5hbA0KICBzdGF0ZXMgYW5kIG9ubHkgaGF2ZSBmZXcg ZWRnZXMgdGhhdCBkb24ndCBmaXQgdGhpcyBzY2hlbWUsIHR1cm5pbmcNCiAgdGhlbSBpbnRvICdk aXJlY3RlZCBhbG1vc3QgYWN5Y2xpYyBncmFwaHMnLg0KDQogIFRoZXJlIGlzIG9idmlvdXNseSBh IGxvdCBtb3JlIG5lY2Vzc2FyeSBmb3IgYSBVSSBmcmFtZXdvcmsNCiAgKGUuZy4gcmVzaXppbmcg dGhlIHdpbmRvdy93aWRnZXRzLCBkZWxlZ2F0aW5nIHRoZSBldmVudHMgdG8gdGhlDQogIGNvcnJl Y3Qgd2lkZ2V0LCBjb21wb3Npbmcgd2lkZ2V0cywgZHJhd2luZyBvbiB0aGUgc2NyZWVuIGV0Yy4p IGFuZCBJDQogIHBsYW4gdG8gd3JpdGUgYWJvdXQgaXQgYXQgc29tZSBwb2ludCBpbiB0aGUgZnV0 dXJlLiBCdXQgZm9yIHRoYXQgSQ0KICB3aWxsIGZpcnN0IG5lZWQgdG8gYWN0dWFsbHkgc29sdmUg dGhlc2UgcHJvYmxlbXMgYXMgcmlnaHQgbm93IHRoZWlyDQogIGltcGxlbWVudGF0aW9uIGlzIHF1 aXRlIGJhcmVib25lcy4gVGhlIGNvZGUgY2FuIGJlIGZvdW5kIGhlcmUgZm9yDQogIHRob3NlIGlu dGVyZXN0ZWQgKHN0aWxsIHZlcnkgZWFybHkgaW4gZGV2ZWxvcG1lbnQhKToNCiAgPGh0dHBzOi8v Z2l0aHViLmNvbS9XaWxsZW5icmluay9ib2d1ZS8+DQoNCg0KW0NvbmN1cl0NCjxodHRwczovL2Fq bnNpdC5naXRodWIuaW8vY29uY3VyLWRvY3VtZW50YXRpb24vY2gwMi0wMS1hbmF0b215LW9mLWEt d2lkZ2V0Lmh0bWw+DQoNCg0KQXdlc29tZSBNdWx0aWNvcmUgT0NhbWwgYW5kIE11bHRpY29yZSBN b25vcmVwbw0K4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ 4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ 4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQDQoNCiAgQXJjaGl2ZToNCiAgPGh0dHBz Oi8vZGlzY3Vzcy5vY2FtbC5vcmcvdC9hd2Vzb21lLW11bHRpY29yZS1vY2FtbC1hbmQtbXVsdGlj b3JlLW1vbm9yZXBvLzk1MTUvMT4NCg0KDQpQYXRyaWNrIEZlcnJpcyBhbm5vdW5jZWQNCuKUgOKU gOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKU gOKUgOKUgOKUgA0KDQogIEEgc2hvcnQgYW5ub3VuY2VtZW50IG9mIHR3byByZXBvc2l0b3JpZXMg d2hpY2ggc29tZSBwZW9wbGUgbWF5IG9yIG1heQ0KICBub3QgaGF2ZSBzZWVuLiBGaXJzdGx5LCBb QXdlc29tZSBNdWx0aWNvcmUgT0NhbWxdLCBhIHBsYWNlIGZvcg0KICBnYXRoZXJpbmcgYWxsIG9m IHRoZSByYXBpZGx5IGNoYW5naW5nIGV4cGVyaW1lbnRzLCBpZGVhcywgbGlicmFyaWVzDQogIGFu ZCByZXNvdXJjZXMgZm9yIE11bHRpY29yZSBPQ2FtbCAoaW5jbHVkaW5nIHNvbWUgb2YgdGhlIGRp c2N1c3MNCiAgdGhyZWFkcykuIElmIHlvdSBhcmUgd29ya2luZyBvbiBzb21ldGhpbmcgb3IgZmVl bCBhbnl0aGluZyBpcyBtaXNzaW5nDQogIHBsZWFzZSBvcGVuIGEgUFIhDQoNCiAgU2Vjb25kbHks IGEgW011bHRpY29yZSBNb25vcmVwb10gd2hpY2ggYWltcyB0byBwcm92aWRlIGEgdmVyeSBxdWlj aw0KICBhbmQgZWFzeSB3YXkgdG8gdHJ5IG91dCBlZmZlY3RzIGFuZCBwYXJhbGxlbGlzbSB3aXRo IHF1aXRlIGEgZmV3DQogIGxpYnJhcmllcyAoc3VjaCBhcyBFaW8sIERyZWFtIGV0Yy4pLiBUaGUg YnJlYWtpbmcgY2hhbmdlcyBpbnRyb2R1Y2VkDQogIGJ5IE9DYW1sIDUgY2FuIG1ha2UgaXQgZnJ1 c3RyYXRpbmcgdG8gZ2V0IHN1Y2ggYSBzZXR1cCBpbiBwbGFjZSwNCiAgYWx0aG91Z2ggdGhpcyBp cyBsZXNzIGFuZCBsZXNzIHRydWUgdGhhbmtzIHRvIHRoZSBbYWxwaGENCiAgcmVwb3NpdG9yeV0u IFRoZSBpZGVhIGlzIHRoYXQgeW91IHNob3VsZCBqdXN0IGJlIGFibGUgdG8gY2xvbmUgdGhpcw0K ICByZXBvc2l0b3J5LCBjcmVhdGUgYSBuZXcgYDUuMC4wK3RydW5rJyBzd2l0Y2gsIGluc3RhbGwg YGR1bmUnIGFuZA0KICBzdGFydCBoYWNraW5nLiBJZiB0aGF0J3Mgbm90IHRoZSBjYXNlIHBsZWFz ZSBkbyBvcGVuIGFuIGlzc3VlLg0KDQoNCltBd2Vzb21lIE11bHRpY29yZSBPQ2FtbF0NCjxodHRw czovL2dpdGh1Yi5jb20vcGF0cmljb2ZlcnJpcy9hd2Vzb21lLW11bHRpY29yZS1vY2FtbD4NCg0K W011bHRpY29yZSBNb25vcmVwb10NCjxodHRwczovL2dpdGh1Yi5jb20vcGF0cmljb2ZlcnJpcy9v Y2FtbC1tdWx0aWNvcmUtbW9ub3JlcG8+DQoNClthbHBoYSByZXBvc2l0b3J5XQ0KPGh0dHBzOi8v Z2l0aHViLmNvbS9raXQtdHkta2F0ZS9vcGFtLWFscGhhLXJlcG9zaXRvcnk+DQoNCg0KcHB4X3Zp ZXdwYXR0ZXJuIGluaXRpYWwgcmVsZWFzZQ0K4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ 4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ 4pWQ4pWQDQoNCiAgQXJjaGl2ZToNCiAgPGh0dHBzOi8vZGlzY3Vzcy5vY2FtbC5vcmcvdC9hbm4t cHB4LXZpZXdwYXR0ZXJuLWluaXRpYWwtcmVsZWFzZS85NTE2LzE+DQoNCg0KU2ltbW8gU2FhbiBh bm5vdW5jZWQNCuKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKU gOKUgOKUgOKUgOKUgA0KDQogIEknbSBnbGFkIHRvIGFubm91bmNlIHRoZSBpbml0aWFsIHJlbGVh c2Ugb2YgW3BweF92aWV3cGF0dGVybl0g4oCTDQogIHRyYW5zZm9ybWF0aW9uIGZvciB2aWV3IHBh dHRlcm5zIGluIE9DYW1sLg0KDQogIEl0IF9hdHRlbXB0cyB0b18gaW1pdGF0ZSBbSGFza2VsbCB2 aWV3IHBhdHRlcm5zXS4gSSB3cm90ZSB0aGlzIHBweA0KICByZXdyaXRlciBtb3N0bHkgb3V0IG9m IGN1cmlvc2l0eSwgcmF0aGVyIHRoYW4gbmVlZCwgYnV0IGl0IHR1cm5lZCBvdXQNCiAgbmVhdCBl bm91Z2ggdGhhdCBvdGhlcnMgbWlnaHQgZmluZCBpdCBpbnRlcmVzdGluZyBvciBldmVuIHVzZWZ1 bC4NCg0KDQpbcHB4X3ZpZXdwYXR0ZXJuXSA8aHR0cHM6Ly9naXRodWIuY29tL3NpbTY0Mi9wcHhf dmlld3BhdHRlcm4+DQoNCltIYXNrZWxsIHZpZXcgcGF0dGVybnNdDQo8aHR0cHM6Ly9naGMuZ2l0 bGFiLmhhc2tlbGwub3JnL2doYy9kb2MvdXNlcnNfZ3VpZGUvZXh0cy92aWV3X3BhdHRlcm5zLmh0 bWw+DQoNClN5bnRheA0K4pWM4pWM4pWM4pWM4pWM4pWMDQoNCiAgVXNlIGBbJXZpZXc/IHBhdCB3 aGVuIGV4cF0nIGFzIGEgcGF0dGVybiB0byBhcHBseSBgZXhwJyB0byB3aGF0ZXZlcg0KICB0aGUg cGF0dGVybiBpcyBtYXRjaGluZyBhbmQgbWF0Y2ggdGhlIHJlc3VsdCBvZiB0aGUgYGV4cCcgYXBw bGljYXRpb24NCiAgYWdhaW5zdCBgcGF0Jy4gIFRoaXMgaXMgYW5hbG9nb3VzIHRvIHRoZSBIYXNr ZWxsIHZpZXcgcGF0dGVybiBgZXhwIC0+DQogIHBhdCcuDQoNCiAgVGhlIGFib3ZlIGV4dGVuc2lv biBub2RlIHBheWxvYWQgc3ludGF4IGlzIHRoZSBiZXN0IEkgY291bGQgY29tZSB1cA0KICB3aXRo IHRvIGNvbWJpbmUgYW4gZXhwcmVzc2lvbiBhbmQgYSBwYXR0ZXJuLiAgSG9uZXN0bHksIEkgd2Fz IGV2ZW4NCiAgc3VycHJpc2VkIHRoYXQgYHdoZW4gZXhwJyBpcyBhdHRhY2hlZCB0byBhIHBhdHRl cm4gaW4gdGhlIEFTVCAobm90IGENCiAgY2FzZSksIGJlY2F1c2Ugbm9ybWFsbHkgaXQgaXNuJ3Qg cGFydCBvZiB0aGUgcGF0dGVybiBpdHNlbGYuDQoNCg0KRXhhbXBsZQ0K4pWM4pWM4pWM4pWM4pWM 4pWM4pWMDQoNCiAgVGhpcyBhbGxvd3Mgb25lIHRvIHdyaXRlDQogIOKUjOKUgOKUgOKUgOKUgA0K ICDilIIgKCogVGhlc2UgY2FzZXMgYXJlIGV4YWN0bHkgbGlrZSByZWR1Y3Rpb24gcnVsZXMhICop DQogIOKUgiBsZXQgcmVjIHJlZHVjZSA9IGZ1bmN0aW9uDQogIOKUgiAgIHwgQWRkIChJbnQgbjEs IEludCBuMikgLT4gU29tZSAoSW50IChuMSArIG4yKSkNCiAg4pSCICAgfCBBZGQgKFsldmlldz8g U29tZSBwMScgd2hlbiByZWR1Y2VdLCBwMikgLT4gU29tZSAoQWRkIChwMScsIHAyKSkNCiAg4pSC ICAgfCBBZGQgKHAxLCBbJXZpZXc/IFNvbWUgcDInIHdoZW4gcmVkdWNlXSkgLT4gU29tZSAoQWRk IChwMSwgcDInKSkNCiAg4pSCICAgKCogLi4uICopDQogIOKUgiAgIHwgXyAtPiBOb25lDQogIOKU lOKUgOKUgOKUgOKUgA0KICBpbnN0ZWFkIG9mDQogIOKUjOKUgOKUgOKUgOKUgA0KICDilIIgKCog VGhlc2UgbmVzdGVkIGNhc2VzIGFyZSBzbyBhbm5veWluZyEgKikNCiAg4pSCIGxldCByZWMgcmVk dWNlID0gZnVuY3Rpb24NCiAg4pSCICAgfCBBZGQgKEludCBuMSwgSW50IG4yKSAtPiBTb21lIChJ bnQgKG4xICsgbjIpKQ0KICDilIIgICB8IEFkZCAocDEsIHAyKSAtPg0KICDilIIgICAgIGJlZ2lu IG1hdGNoIHJlZHVjZSBwMSB3aXRoDQogIOKUgiAgICAgICB8IFNvbWUgcDEnIC0+IFNvbWUgKEFk ZCAocDEnLCBwMikpDQogIOKUgiAgICAgICB8IE5vbmUgLT4NCiAg4pSCIAliZWdpbiBtYXRjaCBy ZWR1Y2UgcDIgd2l0aA0KICDilIIgCSAgfCBTb21lIHAyJyAtPiBTb21lIChBZGQgKHAxLCBwMicp KQ0KICDilIIgCSAgfCBOb25lIC0+IE5vbmUNCiAg4pSCIAllbmQNCiAg4pSCICAgICBlbmQNCiAg 4pSCICAgKCogLi4uICopDQogIOKUgiAgIHwgXyAtPiBOb25lDQogIOKUlOKUgOKUgOKUgOKUgA0K DQogIFNlZSBbYGV4YW1wbGVzLycgb24gR2l0SHViXSBmb3IgbW9yZS4NCg0KDQpbYGV4YW1wbGVz Lycgb24gR2l0SHViXQ0KPGh0dHBzOi8vZ2l0aHViLmNvbS9zaW02NDIvcHB4X3ZpZXdwYXR0ZXJu L3RyZWUvbWFzdGVyL2V4YW1wbGU+DQoNCg0KT2xkIENXTg0K4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ DQoNCiAgSWYgeW91IGhhcHBlbiB0byBtaXNzIGEgQ1dOLCB5b3UgY2FuIFtzZW5kIG1lIGEgbWVz c2FnZV0gYW5kIEknbGwgbWFpbA0KICBpdCB0byB5b3UsIG9yIGdvIHRha2UgYSBsb29rIGF0IFt0 aGUgYXJjaGl2ZV0gb3IgdGhlIFtSU1MgZmVlZCBvZiB0aGUNCiAgYXJjaGl2ZXNdLg0KDQogIElm IHlvdSBhbHNvIHdpc2ggdG8gcmVjZWl2ZSBpdCBldmVyeSB3ZWVrIGJ5IG1haWwsIHlvdSBtYXkg c3Vic2NyaWJlDQogIFtvbmxpbmVdLg0KDQogIFtBbGFuIFNjaG1pdHRdDQoNCg0KW3NlbmQgbWUg YSBtZXNzYWdlXSA8bWFpbHRvOmFsYW4uc2NobWl0dEBwb2x5dGVjaG5pcXVlLm9yZz4NCg0KW3Ro ZSBhcmNoaXZlXSA8aHR0cHM6Ly9hbGFuLnBldGl0ZXBvbW1lLm5ldC9jd24vPg0KDQpbUlNTIGZl ZWQgb2YgdGhlIGFyY2hpdmVzXSA8aHR0cHM6Ly9hbGFuLnBldGl0ZXBvbW1lLm5ldC9jd24vY3du LnJzcz4NCg0KW29ubGluZV0gPGh0dHA6Ly9saXN0cy5pZHlsbC5vcmcvbGlzdGluZm8vY2FtbC1u ZXdzLXdlZWtseS8+DQoNCltBbGFuIFNjaG1pdHRdIDxodHRwczovL2FsYW4ucGV0aXRlcG9tbWUu bmV0Lz4NCg0K --=-=-= Content-Type: text/html Content-Disposition: inline OCaml Weekly News

OCaml Weekly News

Previous Week Up Next Week

Hello

Here is the latest OCaml Weekly News, for the week of March 08 to 15, 2022.

Robur Reproducible Builds

Continuing this thread, Hannes Mehnert announced

OCaml TeXmacs plugin

Nicolas Ratier announced

I made a basic OCaml plugin for TeXmacs (http://www.texmacs.org) I would like to keep it simple, but comments and improvements are welcome. http://forum.texmacs.cn/t/ocaml-a-basic-ocaml-plugin-for-texmacs/813

Release of ocaml-sf/learn-ocaml:0.14.0

Yurug announced

We are very pleased to announce the latest stable release of Learn-OCaml, version 0.14.0.

Many thanks to all users and developers who reported bugs, contributed features, or patches! Special thanks to @erikmd who made many of the changes included in this release.

A (mostly) comprehensive list of the features, fixes, and enhancements offered by this release is available in the Release Notes .

A brief and incomplete summary of the changes:

  • A long-standing bug has been fixed. This bug was triggered when the user opened several sessions: the auto-sync mechanism could lead to overwriting the student's code with an older version.
  • The release assets now include a zip file containing the contents of the `www` directory. This eases the usage of the distributed binaries.

If need be, feel free to open issues in the Learn-OCaml bug tracker or the learn-ocaml.el bug tracker, or post in this thread to share thoughts or experience-feedback.

Happy OCaml learning and teaching!

Tutorial: Roguelike with effect handlers

Continuing this thread, stw said

Sorry about the late reply, I was busy actually verifying that my concept works out. Thankfully it does :smile:

The UI framework is inspired by Concur which means that every widget listens for some set of events and suspends computation until one of these events occurs. Once it does, it continues execution until it encounter the next await at which point it will suspend once more. Once a widget has fulfilled its purpose it terminates with some return value (e.g. text input is confirmed with enter -> return with a string). Complex UIs are then built by composing simpler widgets. A more detailed explanation can be found in the link above.

I've implemented this concept using an await function that takes a list of triggers and a handler for each possible event:

effect Await : Event.t list -> Event.t
let rec await triggers handler =
  handler (EffectHandlers.perform (Await triggers))

let rec check_box checked  =
  (* display check box *)
  ...;
  await [Mouse_press; Key_press] (function
  | Mouse_press ->
    print_endline "I've been (un-)checked!";
    check_box (not checked)
  | Key_press -> (* Terminate if any key is pressed *) checked)

Every widget can then be implemented as a function which displays the widget and performs an Await triggers which is resumed by passing an event from triggers, for example the check box above.

The most complex widget I've implemented so far is a single line text input. It can be clicked or selected with tab. Moving the mouse while holding the button down changes the selection. As an automaton:

574e164b6189608283de32d9f375534ca80caffa.png

Obviously, this is not a directed acyclic graph and therefore not a perfect fit for the implicit state stored in the continuation. Specifically, Pressed has an edge to one of its multiple parents. We can extract the Pressed state into its own function and therefore avoid this issue by 'duplicating' this state. Now Pressed no longer has multiple parents:

70a34d2f4bb81800a5e3b12b8e49147a0d80ece4.png

Some cycles remain and we can't remove them because they are essential to the functionality. Instead we throw an exception Repeat that returns us to a parent node (explicitly shown for Focused -> Pressed -> Released -> Focused). To do that we modify await:

let rec await triggers handler =
  try handler (EffectHandlers.perform (Await triggers)) with
  | Repeat -> await triggers handler

In the end this results in this main method for the text input, with only minor simplifications:

method execute =
  (* Represent the Pressed state.
     We await the Mouse_release and handle Mouse_motion while we wait. *)
  let pressed (x,_) =
    selection <- Point x;
    await [`Mouse_release; `Mouse_motion] @@ function
    | `Mouse_release (_, LMB) ->
      ()
    | `Mouse_motion (x,_) ->
      self#select x;
      raise Repeat (* This restarts the await function *)
    | _ ->
      raise Repeat
  in

  (* We start in the Unfocused state *)
  begin
    await [`Mouse_press; `Key_press] @@ function
    | `Mouse_press (pos, LMB) ->
       (* We have registered the press, but only when it is released
          will we be focused. *)
       pressed pos
    | `Key_press Tab ->
      selection <- Area (0, List.length keys)
    | _ -> raise Repeat
  end;

  (* We move into the Focused state *)
  begin
    await [`Codepoint; `Key_press; `Mouse_press] @@ function
    | `Key_press Tab | `Key_press Return ->
      () (* The only path without raising Repeat.
            Therefore we only leave this await when a tab or return occurs *)
    | `Mouse_press (pos, LMB) ->
      pressed pos;
      raise Repeat
    | `Key_press c ->
      self#insert c;
      raise Repeat
    | _ -> raise Repeat
  end;
  (* We have reached the finished state. We can now return the entered text. *)
  self#text

I think that this method captures the automaton above quite nicely and can be relatively easily understood (hopefully even when one is unfamiliar with the framework and accepts that some magic is happening in the background (: ). Implementing automatons in terms of effect handlers seems to work quite well, at least for games and UIs. What these automatons have in common is that they can be thought of as flows, starting at some state and ending at one of multiple final states and only have few edges that don't fit this scheme, turning them into 'directed almost acyclic graphs'.

There is obviously a lot more necessary for a UI framework (e.g. resizing the window/widgets, delegating the events to the correct widget, composing widgets, drawing on the screen etc.) and I plan to write about it at some point in the future. But for that I will first need to actually solve these problems as right now their implementation is quite barebones. The code can be found here for those interested (still very early in development!): https://github.com/Willenbrink/bogue/

Awesome Multicore OCaml and Multicore Monorepo

Patrick Ferris announced

A short announcement of two repositories which some people may or may not have seen. Firstly, Awesome Multicore OCaml, a place for gathering all of the rapidly changing experiments, ideas, libraries and resources for Multicore OCaml (including some of the discuss threads). If you are working on something or feel anything is missing please open a PR!

Secondly, a Multicore Monorepo which aims to provide a very quick and easy way to try out effects and parallelism with quite a few libraries (such as Eio, Dream etc.). The breaking changes introduced by OCaml 5 can make it frustrating to get such a setup in place, although this is less and less true thanks to the alpha repository. The idea is that you should just be able to clone this repository, create a new 5.0.0+trunk switch, install dune and start hacking. If that's not the case please do open an issue.

ppx_viewpattern initial release

Simmo Saan announced

I'm glad to announce the initial release of ppx_viewpattern – transformation for view patterns in OCaml.

It attempts to imitate Haskell view patterns. I wrote this ppx rewriter mostly out of curiosity, rather than need, but it turned out neat enough that others might find it interesting or even useful.

Syntax

Use [%view? pat when exp] as a pattern to apply exp to whatever the pattern is matching and match the result of the exp application against pat. This is analogous to the Haskell view pattern exp -> pat.

The above extension node payload syntax is the best I could come up with to combine an expression and a pattern. Honestly, I was even surprised that when exp is attached to a pattern in the AST (not a case), because normally it isn't part of the pattern itself.

Example

This allows one to write

(* These cases are exactly like reduction rules! *)
let rec reduce = function
  | Add (Int n1, Int n2) -> Some (Int (n1 + n2))
  | Add ([%view? Some p1' when reduce], p2) -> Some (Add (p1', p2))
  | Add (p1, [%view? Some p2' when reduce]) -> Some (Add (p1, p2'))
  (* ... *)
  | _ -> None

instead of

(* These nested cases are so annoying! *)
let rec reduce = function
  | Add (Int n1, Int n2) -> Some (Int (n1 + n2))
  | Add (p1, p2) ->
    begin match reduce p1 with
      | Some p1' -> Some (Add (p1', p2))
      | None ->
        begin match reduce p2 with
          | Some p2' -> Some (Add (p1, p2'))
          | None -> None
        end
    end
  (* ... *)
  | _ -> None

See examples/ on GitHub for more.

Old CWN

If you happen to miss a CWN, you can send me a message and I'll mail it to you, or go take a look at the archive or the RSS feed of the archives.

If you also wish to receive it every week by mail, you may subscribe online.

--=-=-=--