@effekt-lang/effekt 0.28.0 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/effekt CHANGED
Binary file
@@ -64,8 +64,39 @@
64
64
  (display str)
65
65
  (newline))
66
66
 
67
+ ; Custom structural equality that properly handles records
67
68
  (define (equal_impl obj1 obj2)
68
- (equal? obj1 obj2))
69
+ (cond
70
+ ; Same object reference (fast path)
71
+ [(eq? obj1 obj2) #t]
72
+
73
+ ; If both are records, compare them structurally
74
+ [(and (record? obj1) (record? obj2))
75
+ (let* ([rtd1 (record-rtd obj1)]
76
+ [rtd2 (record-rtd obj2)])
77
+ ; Check if same record type
78
+ (if (eq? rtd1 rtd2)
79
+ (let* ([n (vector-length (record-type-field-names rtd1))]
80
+ [result #t])
81
+ ; Compare all fields recursively
82
+ (do ([i 0 (+ i 1)])
83
+ ((or (= i n) (not result)) result)
84
+ (let ([field1 ((record-accessor rtd1 i) obj1)]
85
+ [field2 ((record-accessor rtd2 i) obj2)])
86
+ (if (not (equal_impl field1 field2))
87
+ (set! result #f)))))
88
+ #f))]
89
+
90
+ ; For lists, compare elements recursively
91
+ [(and (list? obj1) (list? obj2))
92
+ (and (= (length obj1) (length obj2))
93
+ (let loop ([l1 obj1] [l2 obj2])
94
+ (or (null? l1)
95
+ (and (equal_impl (car l1) (car l2))
96
+ (loop (cdr l1) (cdr l2))))))]
97
+
98
+ ; For all other types, use Scheme's built-in equal?
99
+ [else (equal? obj1 obj2)]))
69
100
 
70
101
  (define-syntax thunk
71
102
  (syntax-rules ()
@@ -110,7 +110,7 @@ extern io def inspect[R](value: R): Unit =
110
110
  // Strings
111
111
  // =======
112
112
  extern pure def infixConcat(s1: String, s2: String): String =
113
- js "((${s1}) + (${s2}))"
113
+ js "${s1} + ${s2}"
114
114
  chez "(string-append ${s1} ${s2})"
115
115
  llvm """
116
116
  %spz = call %Pos @c_bytearray_concatenate(%Pos ${s1}, %Pos ${s2})
@@ -203,7 +203,7 @@ def println(o: Ordering): Unit = println(o.show)
203
203
  /// Structural equality: Not available in the LLVM backend
204
204
  extern pure def equals[R](x: R, y: R): Bool =
205
205
  js "$effekt.equals(${x}, ${y})"
206
- chez "(equal? ${x} ${y})"
206
+ chez "(equal_impl ${x} ${y})"
207
207
 
208
208
  def differsFrom[R](x: R, y: R): Bool =
209
209
  not(equals(x, y))
@@ -344,7 +344,7 @@ extern pure def infixSub(x: Double, y: Double): Double =
344
344
 
345
345
  extern pure def infixDiv(x: Double, y: Double): Double =
346
346
  js "(${x} / ${y})"
347
- chez "(/ ${x} ${y})"
347
+ chez "(fl/ ${x} ${y})"
348
348
  llvm "%z = fdiv %Double ${x}, ${y} ret %Double %z"
349
349
  vm "effekt::infixDiv(Double, Double)"
350
350
 
@@ -442,14 +442,14 @@ extern pure def toInt(d: Double): Int =
442
442
 
443
443
  extern pure def toDouble(d: Int): Double =
444
444
  js "${d}"
445
- chez "${d}"
445
+ chez "(fixnum->flonum ${d})"
446
446
  llvm "%z = sitofp i64 ${d} to double ret double %z"
447
447
  vm "effekt::toDouble(Int)"
448
448
 
449
449
 
450
450
  extern pure def round(d: Double): Int =
451
451
  js "Math.round(${d})"
452
- chez "(round ${d})"
452
+ chez "(flonum->fixnum (round ${d}))"
453
453
  llvm """
454
454
  %i = call %Double @llvm.round.f64(double ${d})
455
455
  %z = fptosi double %i to %Int ret %Int %z
@@ -0,0 +1,186 @@
1
+ module random
2
+
3
+ import stream
4
+ import io/error
5
+
6
+ /// Infinite pull stream of random bytes.
7
+ effect random(): Byte
8
+
9
+ // ---------------------
10
+ // Sources of randomness
11
+
12
+ /// A streaming source (push stream) of byte-level randomness
13
+ /// based on Park and Miller's MINSTD with revised parameters.
14
+ ///
15
+ /// Deterministic: needs a 32bit `seed` -- you can use `bench::timestamp`.
16
+ def minstd(seed: Int): Unit / emit[Byte] = {
17
+ // Initialize state with seed, ensuring it's not zero
18
+ var state = if (seed == 0) 1 else seed
19
+
20
+ def nextInt(): Int = {
21
+ // Uses only at most 32-bit integers internally
22
+ // (Schrage's method: https://en.wikipedia.org/wiki/Lehmer_random_number_generator#Schrage's_method)
23
+ val a = 48271
24
+ val m = 2147483647
25
+
26
+ val q = m / a // 44488
27
+ val r = m.mod(a) // 3399
28
+
29
+ val div = state / q // max: M / Q = A = 48271
30
+ val rem = state.mod(q) // max: Q - 1 = 44487
31
+
32
+ val s = rem * a; // max: 44487 * 48271 = 2147431977
33
+ val t = div * r; // max: 48271 * 3399 = 164073129
34
+
35
+ val result = s - t
36
+ // keep the state positive
37
+ if (result < 0) result + m else result
38
+ }
39
+
40
+ while (true) {
41
+ state = nextInt()
42
+ val b = state.mod(256).toByte
43
+ do emit(b)
44
+ }
45
+ }
46
+
47
+ /// A thin wrapper over `minstd`, handling a reader of random bytes.
48
+ ///
49
+ /// Deterministic: needs a 32bit `seed` -- you can use `bench::timestamp`.
50
+ ///
51
+ /// Implementation is similar to `stream::source`, specialized for bytes and the `random` effect.
52
+ def minstd(seed: Int) { randomnessReader: () => Unit / random }: Unit = {
53
+ var next = box { 255.toByte } // sentinel value
54
+ next = box {
55
+ try {
56
+ minstd(seed)
57
+ <> // safe: randomness generator cannot run out of numbers...
58
+ } with emit[Byte] { v =>
59
+ next = box { resume(()) }
60
+ v
61
+ }
62
+ }
63
+
64
+ try randomnessReader() with random {
65
+ resume(next())
66
+ }
67
+ }
68
+
69
+ /// CSPRNG from `/dev/urandom`, handling a reader of random bytes.
70
+ /// Only works on Unix-like OSes!
71
+ def devurandom { randomnessReader: () => Unit / random }: Unit / Exception[IOError] =
72
+ try {
73
+ with readFile("/dev/urandom")
74
+ try randomnessReader() with random {
75
+ resume(do read[Byte]())
76
+ }
77
+ } with stop {
78
+ do raise(io::error::EOF(), "Unexpected EOF when reading /dev/urandom!")
79
+ }
80
+
81
+ // ------------------------
82
+ // Functions using `random`
83
+ //
84
+ // Always two variants:
85
+ // - readType(): Type / random
86
+ // - readTypes(): Unit / {emit[Type], random}
87
+
88
+ def randomByte(): Byte / random = do random()
89
+ def randomBytes(): Unit / {emit[Byte], random} =
90
+ while (true) do emit(do random())
91
+
92
+ def randomBool(): Bool / random = {
93
+ val b = do random()
94
+ b.toInt.mod(2) == 1
95
+ }
96
+ def randomBools(): Unit / {emit[Bool], random} =
97
+ while (true) do emit(randomBool())
98
+
99
+ def randomInt32(): Int / random = {
100
+ var result = 0
101
+ repeat(4) {
102
+ val b = do random()
103
+ result = result * 256 + b.toInt
104
+ }
105
+ val signBit = result.bitwiseShr(31).bitwiseAnd(1) == 0
106
+ result.mod(1.bitwiseShl(31)).abs * if (signBit) 1 else -1
107
+ }
108
+ def randomInt32s(): Unit / {emit[Int], random} =
109
+ while (true) do emit(randomInt32())
110
+
111
+ /// `max` is _inclusive_!
112
+ def randomInt(min: Int, max: Int): Int / random = {
113
+ if (min > max) {
114
+ randomInt(max, min)
115
+ } else {
116
+ val range = max - min + 1
117
+ val bytesNeeded = (log(range.toDouble) / log(256.0)).ceil
118
+
119
+ var result = 0
120
+ repeat(bytesNeeded) {
121
+ val b = do random()
122
+ result = result * 256 + b.toInt
123
+ }
124
+
125
+ min + (abs(result).mod(range))
126
+ }
127
+ }
128
+ /// `max` is _inclusive_!
129
+ def randomInts(min: Int, max: Int): Unit / {emit[Int], random} =
130
+ while (true) do emit(randomInt(min, max))
131
+
132
+
133
+ /// Random double between 0.0 and 1.0
134
+ def randomDouble(): Double / random =
135
+ (randomInt32().toDouble / 1.bitwiseShl(31).toDouble).abs
136
+ // This is not perfect, but it will do for now.
137
+ def randomDoubles(): Unit / {emit[Double], random} =
138
+ while (true) do emit(randomDouble())
139
+
140
+
141
+ namespace examples {
142
+ def main() = {
143
+ println("prng")
144
+ prngRandom()
145
+ }
146
+
147
+ def prngRandom(): Unit = {
148
+ with minstd(1337);
149
+
150
+ println("int32s:")
151
+ repeat(10) {
152
+ println(randomInt32())
153
+ }
154
+
155
+ println("int32s, part2:")
156
+ repeat(10) {
157
+ println(randomInt(0, 2147483647))
158
+ println(randomInt(-2147483648, 0))
159
+ }
160
+
161
+ println("doubles:")
162
+ repeat(10) {
163
+ println(randomDouble().round(3))
164
+ }
165
+
166
+ println("randomInt:")
167
+ repeat(10) {
168
+ val a = randomInt(0, 9)
169
+ val b = randomInt(0, 9)
170
+ val c = randomInt(0, 9)
171
+ println(a.show ++ " " ++ b.show ++ " " ++ c.show)
172
+ println(a*100 + b*10 + c)
173
+ }
174
+ }
175
+
176
+ def unixRandom(): Unit = {
177
+ with on[IOError].report;
178
+ with devurandom;
179
+
180
+ val a = randomInt32()
181
+ val b = randomInt32()
182
+
183
+ // This is just to use the generated numbers :)
184
+ println((a.show ++ b.show).length != 0)
185
+ }
186
+ }
@@ -173,10 +173,23 @@ def replicate[A](number: Int) { action: () => A }: Unit / emit[A] =
173
173
  replicate(number - 1) {action}
174
174
  }
175
175
 
176
+ /// Creates an infinite iterated stream given by an `initial` seed and a `step` function:
177
+ /// iterate(a){f} ~> a, f(a), f(f(a)), f(f(f(a))), ...
178
+ def iterate[A](initial: A) { step: A => A }: Unit / emit[A] = {
179
+ var current = initial
180
+ while (true) {
181
+ do emit(current)
182
+ current = step(current)
183
+ }
184
+ }
176
185
 
177
- def sum { stream : () => Unit / emit[Int] }: Int =
186
+
187
+ def sum { stream: () => Unit / emit[Int] }: Int =
178
188
  returning::sum[Unit]{stream}.second
179
189
 
190
+ def product { stream: () => Unit / emit[Int] }: Int =
191
+ returning::product[Unit]{stream}.second
192
+
180
193
  def collectList[A] { stream: () => Unit / emit[A] }: List[A] =
181
194
  returning::collectList[A, Unit]{stream}.second
182
195
 
@@ -409,6 +422,88 @@ def each(string: String): Unit / emit[Char] =
409
422
  def collectString { stream: () => Unit / emit[Char] }: String =
410
423
  returning::collectString[Unit]{stream}.second
411
424
 
425
+ namespace internal {
426
+ effect snapshot(): Unit
427
+ }
428
+
429
+ /// Use cons to handle prod, but also emit to the outside.
430
+ /// The outside controls iteration, i.e., if cons aborts, the rest of prod will still be emitted.
431
+ ///
432
+ /// Starts by executing cons. Will stop cons during execution if the outside stops consuming.
433
+ ///
434
+ /// Example, printing all values consumed by the outside:
435
+ ///
436
+ /// with teeing{ {s} => for{s}{ e => println(e) } }
437
+ /// prod() // some producer
438
+ ///
439
+ /// Laws-ish (hopefully):
440
+ /// - hnd{ prd() } === hnd{ teeing{t}{ prd() } } for all hnd and t that calls its argument at most once (and has no other captures)
441
+ def teeing[A]{ cons: { => Unit / emit[A] } => Unit }{ prod: => Unit / emit[A] }: Unit / emit[A] = region r {
442
+ var consDone = false
443
+ var k in r = box { prod() } // what still needs to run of prod after cons exits
444
+ try {
445
+ cons{
446
+ try {
447
+ prod()
448
+ k = box { () }
449
+ } with emit[A] { v =>
450
+ do internal::snapshot() // remember that we need to continue here if cons aborts
451
+ if(not(consDone)) do emit(v)
452
+ outer.emit(v)
453
+ resume(())
454
+ }
455
+ if(consDone) do stop() // cons already exited, so skip continuing there
456
+ } // end cons
457
+ consDone = true
458
+ }
459
+ with stop { () => () }
460
+ with outer: emit[A]{ v => resume(do emit(v)) }
461
+ with internal::snapshot{ () =>
462
+ k = box { resume(()) }
463
+ resume(())
464
+ }
465
+ k()
466
+ }
467
+
468
+ /// Binds a `teeing`-like function in the body, stopping the inner producer once all consumers in tees are done consuming.
469
+ ///
470
+ /// Example of use, equivalent to `tee[A]{cns1}{cns2}{prd}`:
471
+ ///
472
+ /// manyTee[A] { {tee} =>
473
+ /// with tee{cns1}
474
+ /// with tee{cns2}
475
+ /// prd()
476
+ /// }
477
+ ///
478
+ def manyTee[A]{ body: { { { => Unit / emit[A] } => Unit }{ => Unit / emit[A] } => Unit / emit[A] } => Unit / emit[A] }: Unit = {
479
+ var running = 0
480
+ try {
481
+ body{ {hnd}{prod} =>
482
+ running = running + 1
483
+ teeing[A]{ {b} => hnd{b}; running = running - 1 }{prod}
484
+ }
485
+ } with emit[A] { _ =>
486
+ if(running > 0) resume(())
487
+ }
488
+ }
489
+
490
+ /// Streams prod to both cons1 and cons2. Stops once both cons1 and cons2 stopped.
491
+ /// Only runs prod once, resuming at most once at each emit.
492
+ ///
493
+ /// var sumRes = 0
494
+ /// var productRes = 0
495
+ /// tee{ s => sumRes = sum{s} }{ s => productRes = product{s} }{ range(0, 10) }
496
+ /// assertEquals(sum{ range(0, 10) }, sumRes)
497
+ /// assertEquals(product{ range(0, 10) }, productRes)
498
+ ///
499
+ def tee[A]{ cons1: { => Unit / emit[A] } => Unit }{ cons2: { => Unit / emit[A] } => Unit }{ prod: => Unit / emit[A] }: Unit = {
500
+ manyTee[A]{ {tee} =>
501
+ with tee{cons1}
502
+ with tee{cons2}
503
+ prod()
504
+ }
505
+ }
506
+
412
507
  namespace returning {
413
508
 
414
509
  /// Canonical handler of push streams that performs `action` for every
@@ -461,7 +556,7 @@ def limit[A, R](number: Int) { stream: () => R / emit[A] }: R / { emit[A], stop
461
556
  }
462
557
  }
463
558
 
464
- def sum[R] { stream : () => R / emit[Int] }: (R, Int) = {
559
+ def sum[R] { stream: () => R / emit[Int] }: (R, Int) = {
465
560
  var s = 0;
466
561
  try {
467
562
  (stream(), s)
@@ -471,6 +566,16 @@ def sum[R] { stream : () => R / emit[Int] }: (R, Int) = {
471
566
  }
472
567
  }
473
568
 
569
+ def product[R] { stream: () => R / emit[Int] }: (R, Int) = {
570
+ var s = 1;
571
+ try {
572
+ (stream(), s)
573
+ } with emit[Int] { v =>
574
+ s = s * v;
575
+ resume(())
576
+ }
577
+ }
578
+
474
579
  def collectList[A, R] { stream: () => R / emit[A] }: (R, List[A]) =
475
580
  try {
476
581
  (stream(), Nil())
@@ -1,5 +1,5 @@
1
1
  <!doctype html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><title>Eclipse Public License 2.0 (EPL) | The Eclipse Foundation</title>
2
- <meta property="og:title" content="Eclipse Public License 2.0 (EPL) | The Eclipse Foundation"><meta name=twitter:title content="Eclipse Public License 2.0 (EPL) | The Eclipse Foundation"><meta name=description content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta property="og:description" content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta name=twitter:description content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta name=author content="Wayne Beaton"><link href=/favicon.ico rel=icon type=image/x-icon><meta property="og:image" content="https://www.eclipse.org/images/logos/eclipse-foundation-400x400.png"><meta name=twitter:image content="https://www.eclipse.org/images/logos/eclipse-foundation-400x400.png"><meta name=twitter:card content="summary"><meta name=twitter:site content="@eclipsefdn"><meta name=twitter:creator content="@eclipsefdn"><meta property="og:url" content="https://www.eclipse.org/legal/epl-2.0/"><meta property="og:type" content="website"><meta property="og:site_name" content="Eclipse Foundation"><meta name=keywords content="epl,epl-2.0,legal,foundation,eclipse,eclipse public license,license,licenses"><meta name=generator content="Hugo 0.144.2"><link rel=canonical href=https://www.eclipse.org/legal/epl-2.0/><link rel=alternate href=/legal/epl-2.0/index.xml type=application/rss+xml title><link rel=stylesheet href="/public/css/styles.css?v=1745172931"><script>(function(e,t,n,s,o){e[s]=e[s]||[],e[s].push({"gtm.start":(new Date).getTime(),event:"gtm.js"});var a=t.getElementsByTagName(n)[0],i=t.createElement(n),r=s!="dataLayer"?"&l="+s:"";i.async=!0,i.src="https://www.googletagmanager.com/gtm.js?id="+o+r,a.parentNode.insertBefore(i,a)})(window,document,"script","dataLayer","GTM-5WLCZXC")</script><script>var tableClasses="table"</script><link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel=stylesheet type=text/css></head><body><noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-5WLCZXC" height=0 width=0 style=display:none;visibility:hidden></iframe></noscript><a class=sr-only href=#content>Skip to main content</a><header class="header-wrapper header-wrapper" id=header><div class=header-toolbar><div class=container><div class=header-toolbar-row><div class="toolbar-btn toolbar-search-btn dropdown"><button class=dropdown-toggle id=toolbar-search type=button data-toggle=dropdown tabindex=0 aria-label=Search>
2
+ <meta property="og:title" content="Eclipse Public License 2.0 (EPL) | The Eclipse Foundation"><meta name=twitter:title content="Eclipse Public License 2.0 (EPL) | The Eclipse Foundation"><meta name=description content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta property="og:description" content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta name=twitter:description content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta name=author content="Wayne Beaton"><link href=/favicon.ico rel=icon type=image/x-icon><meta property="og:image" content="https://www.eclipse.org/images/logos/eclipse-foundation-400x400.png"><meta name=twitter:image content="https://www.eclipse.org/images/logos/eclipse-foundation-400x400.png"><meta name=twitter:card content="summary"><meta name=twitter:site content="@eclipsefdn"><meta name=twitter:creator content="@eclipsefdn"><meta property="og:url" content="https://www.eclipse.org/legal/epl-2.0/"><meta property="og:type" content="website"><meta property="og:site_name" content="Eclipse Foundation"><meta name=keywords content="epl,epl-2.0,legal,foundation,eclipse,eclipse public license,license,licenses"><meta name=generator content="Hugo 0.144.2"><link rel=canonical href=https://www.eclipse.org/legal/epl-2.0/><link rel=alternate href=/legal/epl-2.0/index.xml type=application/rss+xml title><link rel=stylesheet href="/public/css/styles.css?v=1746987328"><script>(function(e,t,n,s,o){e[s]=e[s]||[],e[s].push({"gtm.start":(new Date).getTime(),event:"gtm.js"});var a=t.getElementsByTagName(n)[0],i=t.createElement(n),r=s!="dataLayer"?"&l="+s:"";i.async=!0,i.src="https://www.googletagmanager.com/gtm.js?id="+o+r,a.parentNode.insertBefore(i,a)})(window,document,"script","dataLayer","GTM-5WLCZXC")</script><script>var tableClasses="table"</script><link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel=stylesheet type=text/css></head><body><noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-5WLCZXC" height=0 width=0 style=display:none;visibility:hidden></iframe></noscript><a class=sr-only href=#content>Skip to main content</a><header class="header-wrapper header-wrapper" id=header><div class=header-toolbar><div class=container><div class=header-toolbar-row><div class="toolbar-btn toolbar-search-btn dropdown"><button class=dropdown-toggle id=toolbar-search type=button data-toggle=dropdown tabindex=0 aria-label=Search>
3
3
  <i class="fa fa-search fa-lg" aria-role=none></i></button><div class="toolbar-search-bar-wrapper dropdown-menu dropdown-menu-right" aria-labelledby=toolbar-search><form action=https://www.eclipse.org/home/search method=get><div class=search-bar><input class=search-bar-input name=q placeholder=Search>
4
4
  <button>
5
5
  <i class="fa fa-search" type=submit></i></button></div></form></div></div><div class="toolbar-btn toolbar-user-menu-btn dropdown"><button class=dropdown-toggle id=toolbar-user-menu type=button data-toggle=dropdown tabindex=0 aria-label="User Menu">
@@ -60,4 +60,4 @@ open source software collaboration and innovation.</p></div><div class=mega-menu
60
60
  <i class="fa-brands fa-linkedin-in fa-stack-1x fa-inverse" aria-hidden=true></i>
61
61
  <span class=sr-only>Linkedin account</span></span></a></li></ul></div></div><div class="footer-sections row equal-height-md font-bold"><div class=col-md-15><div class=row><section id=footer-eclipse-foundation class="footer-section col-sm-8"><div class=menu-heading>Eclipse Foundation</div><ul class=nav><li><a href=https://www.eclipse.org/org/>About</a></li><li><a href=https://projects.eclipse.org/>Projects</a></li><li><a href=https://www.eclipse.org/collaborations/>Collaborations</a></li><li><a href=https://www.eclipse.org/membership/>Membership</a></li><li><a href=https://www.eclipse.org/sponsor/>Sponsor</a></li></ul></section><section id=footer-legal class="footer-section col-sm-8"><div class=menu-heading>Legal</div><ul class=nav><li><a href=https://www.eclipse.org/legal/privacy/>Privacy Policy</a></li><li><a href=https://www.eclipse.org/legal/terms-of-use/>Terms of Use</a></li><li><a href=https://www.eclipse.org/legal/compliance/>Compliance</a></li><li><a href=https://www.eclipse.org/org/documents/Community_Code_of_Conduct.php>Code of Conduct</a></li><li><a href=https://www.eclipse.org/legal/>Legal Resources</a></li><li><a class=toolbar-manage-cookies href=# onclick=event.preventDefault()>Manage Cookies</a></li></ul></section><section id=footer-more class="footer-section col-sm-8"><div class=menu-heading>More</div><ul class=nav><li><a href=https://www.eclipse.org/security/>Report a Vulnerability</a></li><li><a href=https://status.eclipse.org/>Service Status</a></li><li><a href=https://www.eclipse.org/org/foundation/contact.php>Contact Us</a></li><li><a href=https://www.eclipse.org/projects/support/>Support</a></li></ul></section></div></div><div id=footer-end class="footer-section col-md-8 col-md-offset-1 col-sm-24"><div class=footer-end-newsletter><form id=mc-embedded-subscribe-form action="https://eclipse.us6.list-manage.com/subscribe/post?u=eaf9e1f06f194eadc66788a85&amp;id=e7538485cd&amp;f_id=00f9c2e1f0" method=post novalidate target=_blank><label class=footer-end-newsletter-label for=email>Subscribe to our Newsletter</label><div class=footer-end-newsletter-input-wrapper><input class=footer-end-newsletter-input type=email id=email name=EMAIL autocomplete=email placeholder="Enter your email address">
62
62
  <button class="footer-end-newsletter-submit btn btn-link" id=mc-embedded-subscribe type=submit name=subscribe>
63
- <i class="fa fa-solid fa-envelope fa-lg" aria-hidden=true></i></button></div></form></div></div></div><div class="col-sm-24 margin-top-20"><div class=row><div id=copyright class=col-md-16><p id=copyright-text>Copyright &copy; Eclipse Foundation AISBL. All Rights Reserved.</p></div></div></div><a href=# class=scrollup>Back to the top</a></div></footer><div id=footer-js><script src="/public/js/main.js?v1.0?v=1745172931"></script><script>(function(){})(jQuery,document)</script></div></body></html>
63
+ <i class="fa fa-solid fa-envelope fa-lg" aria-hidden=true></i></button></div></form></div></div></div><div class="col-sm-24 margin-top-20"><div class=row><div id=copyright class=col-md-16><p id=copyright-text>Copyright &copy; Eclipse Foundation AISBL. All Rights Reserved.</p></div></div></div><a href=# class=scrollup>Back to the top</a></div></footer><div id=footer-js><script src="/public/js/main.js?v1.0?v=1746987328"></script><script>(function(){})(jQuery,document)</script></div></body></html>