-
Notifications
You must be signed in to change notification settings - Fork 5
Implement fair randomized ordering for design help providers #66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,12 @@ | |
| sub_title: "Get assistance with your GF180MCU chip designs" | ||
| header_image: "/assets/images/header/mpw-one-partial-dice-top-1.jpg" | ||
| --- | ||
| <style> | ||
| #provider-list { | ||
| display: flex; | ||
| flex-direction: column; | ||
| } | ||
| </style> | ||
| {% include layouts/nav/nav.html drop_search=false alignment_class="ms-auto" %} | ||
| {% include layouts/header/page-title.html %} | ||
|
|
||
|
|
@@ -16,11 +22,104 @@ <h3 class="section-title text-center mb-20">Professional Services</h3> | |
| <br><small class="text-muted"><em>Note: These services are not affiliated with or endorsed by wafer.space. | ||
| Please contact them directly to discuss your project needs.</em></small> | ||
| </p> | ||
| <div class="sr-only" aria-live="polite"> | ||
| Provider order is randomized for fairness. Visual order may differ from screen reader order. | ||
| </div> | ||
|
|
||
| <div id="provider-list"> | ||
| {% assign professional_help = site.design_help | where: "category", "professional" %} | ||
| {% for provider in professional_help %} | ||
| {% include design_help/provider.html provider=provider %} | ||
| {% endfor %} | ||
| </div> | ||
|
|
||
| <script> | ||
| (function() { | ||
| 'use strict'; | ||
|
|
||
| // LCG (Linear Congruential Generator) parameters - MINSTD | ||
| var LCG_MODULUS = 2147483647; // 2^31 - 1 (Mersenne prime) | ||
| var LCG_MULTIPLIER = 16807; | ||
|
|
||
| // Seeded Random Number Generator (Linear Congruential Generator) | ||
| function SeededRandom(seed) { | ||
| this.seed = seed % LCG_MODULUS; | ||
| if (this.seed <= 0) this.seed += LCG_MODULUS - 1; | ||
| } | ||
|
|
||
| SeededRandom.prototype.next = function() { | ||
| this.seed = (this.seed * LCG_MULTIPLIER) % LCG_MODULUS; | ||
| return (this.seed - 1) / (LCG_MODULUS - 1); | ||
| }; | ||
|
|
||
| // Fisher-Yates shuffle with seeded random | ||
| function shuffleArray(array, random) { | ||
| var shuffled = array.slice(); | ||
| for (var i = shuffled.length - 1; i > 0; i--) { | ||
| var j = Math.floor(random.next() * (i + 1)); | ||
| var temp = shuffled[i]; | ||
| shuffled[i] = shuffled[j]; | ||
| shuffled[j] = temp; | ||
| } | ||
| return shuffled; | ||
| } | ||
|
|
||
| // Get or create seed from localStorage | ||
| var SEED_KEY = 'designHelpProviderSeed'; | ||
| var seed; | ||
|
|
||
| try { | ||
| seed = localStorage.getItem(SEED_KEY); | ||
| if (!seed) { | ||
| seed = Math.floor(Math.random() * LCG_MODULUS); | ||
| localStorage.setItem(SEED_KEY, seed); | ||
| } else { | ||
| seed = parseInt(seed, 10); | ||
| // Validate seed is a valid number in expected range | ||
| if (isNaN(seed) || seed <= 0 || seed >= LCG_MODULUS) { | ||
| seed = Math.floor(Math.random() * LCG_MODULUS); | ||
| localStorage.setItem(SEED_KEY, seed); | ||
| } | ||
| } | ||
|
mithro marked this conversation as resolved.
|
||
| } catch (e) { | ||
| // localStorage not available (private mode, etc.) | ||
| if (console && console.debug) { | ||
| console.debug('Failed to access localStorage for provider shuffle:', e); | ||
| } | ||
| seed = Math.floor(Math.random() * LCG_MODULUS); | ||
| } | ||
|
|
||
| // Get all provider items | ||
| var container = document.getElementById('provider-list'); | ||
| if (!container) return; | ||
|
|
||
| var providers = container.querySelectorAll('.provider-item'); | ||
| if (providers.length <= 1) return; // No need to shuffle if 0 or 1 items | ||
|
|
||
| // Create array of indices | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor optimization: Creating a separate |
||
| var indices = []; | ||
| for (var i = 0; i < providers.length; i++) { | ||
| indices.push(i); | ||
| } | ||
|
|
||
| // Shuffle indices using seeded random | ||
| var random = new SeededRandom(seed); | ||
| var shuffledIndices = shuffleArray(indices, random); | ||
|
|
||
| // Apply CSS order to each provider | ||
| for (var i = 0; i < providers.length; i++) { | ||
| providers[i].style.order = shuffledIndices[i]; | ||
|
mithro marked this conversation as resolved.
mithro marked this conversation as resolved.
|
||
| } | ||
|
|
||
| {% assign professional_help = site.design_help | where: "category", "professional" %} | ||
| {% for provider in professional_help %} | ||
| {% include design_help/provider.html provider=provider %} | ||
| {% endfor %} | ||
| // Re-scroll to hash target if present (fixes race condition) | ||
| if (window.location.hash) { | ||
| var target = document.getElementById(window.location.hash.substring(1)); | ||
| if (target) { | ||
| target.scrollIntoView(); | ||
| } | ||
| } | ||
| })(); | ||
| </script> | ||
| </div> | ||
| </div> | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.