Explain difference of two JavaScript generator implementations of Heap’s permutation algorithm

I have two implementations of Heap’s permutation algorithm in JavaScript using generator functions and I would like to understand better how they are related under the hood. Please explain. They both run with Node.js. Since it is often the case that different implementations can be derived or deduced from each other, I would also be interested to get some such code transformation pointed out. Note, that I am not asking, which implementation is ‘better’, since that is an opinion, or which you like most.

Implementation 1:

function permute(N) {
    function swap(x, y) { [ P[x], P[y] ] = [ P[y], P[x] ] }
    function heap(n, i) { return (n % 2) || i }

    var P = []; for (let i = 1; i <= N; i++) P[i] = i;
    var count = 1;
    console.log(count++, ":", P.slice(1));
    
    for (p of permutations(N)) console.log(count++, ":", p.slice(1));

    function* permutations(n) {
        if (n > 1) {
            for (let i = 1; i <= n; i++) {
                yield* permutations(n - 1);
                if (i < n) { swap(n, heap(n, i)); yield P }
            }
        }
    }
}

permute(4);

Implementation 2:

function permute(N) {
    function swap(x, y) { [ P[x], P[y] ] = [ P[y], P[x] ] }
    function heap(n, i) { return (n % 2) || i }

    var P = []; for (let i = 1; i <= N; i++) P[i] = i;
    var count = 1;
    
    for (p of permutations(N)) console.log(count++, ":", p.slice(1));

    function* permutations(n) {
        if (n == 1) yield P;
        else {
            for (let i = 1; i <= n; i++) {
                yield* permutations(n - 1);
                if (i < n) swap(n, heap(n, i));
            }
        }
    }
}

permute(4);

Output:

1 ':' [ 1, 2, 3, 4 ]
2 ':' [ 2, 1, 3, 4 ]
3 ':' [ 3, 1, 2, 4 ]
4 ':' [ 1, 3, 2, 4 ]
5 ':' [ 2, 3, 1, 4 ]
6 ':' [ 3, 2, 1, 4 ]
7 ':' [ 4, 2, 1, 3 ]
8 ':' [ 2, 4, 1, 3 ]
9 ':' [ 1, 4, 2, 3 ]
10 ':' [ 4, 1, 2, 3 ]
11 ':' [ 2, 1, 4, 3 ]
12 ':' [ 1, 2, 4, 3 ]
13 ':' [ 1, 3, 4, 2 ]
14 ':' [ 3, 1, 4, 2 ]
15 ':' [ 4, 1, 3, 2 ]
16 ':' [ 1, 4, 3, 2 ]
17 ':' [ 3, 4, 1, 2 ]
18 ':' [ 4, 3, 1, 2 ]
19 ':' [ 4, 3, 2, 1 ]
20 ':' [ 3, 4, 2, 1 ]
21 ':' [ 2, 4, 3, 1 ]
22 ':' [ 4, 2, 3, 1 ]
23 ':' [ 3, 2, 4, 1 ]
24 ':' [ 2, 3, 4, 1 ]

I have based both generator functions on Robert Sedgewick’s paper, Permutation Generation Methods (1977), where on page 140 the author gives the following basic recursive algorithm:

To generate all permutations of P[1], …, P[N], we repeat N times the step: “first generate all permutations of P[1], …, P[N-1], then exchange P[N] with one of the elements P[1], …, P[N-1].”

In implementation 2 I have added the obvious recursion base case n==1 and a routinely chosen position of the yield statement. Also, to avoid “unnecessary” swaps during the last iteration of the for loop, there is the guard if (i < n). In this way, it seems to be equivalent to Heap’s recursive algorithm given in Wikipedia. In any case, when called with N = 4 it reproduces Heap’s enumeration as given in Sedgewick’s paper.

Also note that in implementation 1 the position of the yield statement is entirely different. I would like to know to what extent that is actually arbitrary or in what way it is determined.

How to block the page from loading in an inline script until async operations finish

I have this embed script that needs to be placed in the head of websites:

<script src="https://www.example.com/track.js?wid=123”></script>

It needs to execute before the page body renders (hence it presumably shouldn’t use async or defer – it’s for A/B testing, where inserting CSS late could cause content shift etc).

However, example.com may not always be reliable (i.e. the server could be down or slow, and I don’t want it blocking the page from loading for long; a small delay is ok – I assume the script with src attribute would delay the page from loading if added that way), hence I built this ‘abort-if-not-fast’ INLINE script (for the head):

<script>
(async () => {
  // If the body is already present, it's too late to inject A/B changes
  if (document.body) return;

  // Setup an AbortController to kill the request after n ms
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), 5000);

  function delayedFetchSimulation(url, { signal }) {
    return new Promise((resolve, reject) => {
      // Simulate network latency (e.g., 6000ms)
      const delay = 6000;

      const timeout = setTimeout(() => {
        resolve(new Response("// simulated script content"));
      }, delay);

      // Abort logic
      signal.addEventListener("abort", () => {
        clearTimeout(timeout);
        reject(new DOMException("Aborted", "AbortError"));
      });
    });
  }

  try {
    const response = await delayedFetchSimulation("https://www.example.com/scripts/tracking/track.js?wid=demo", {
      signal: controller.signal
    });

    clearTimeout(timeoutId); // clear the timeout if fetch succeeded

    if (!response.ok) {
      console.warn("A/B test script failed to load (HTTP error).");
      return;
    }

    let scriptText;
    try {
      scriptText = await response.text();
    } catch (readErr) {
      console.warn("Failed to read A/B test script body:", readErr);
      return;
    }

    // Abort if body has now started rendering while we were fetching
    if (document.body) {
      console.log('Body already started rendering - returning early...');
      return;
    }

    // Inject the fetched script into the page
    const script = document.createElement("script");
    script.id = 'ab-testing-script';
    script.textContent = scriptText;
    document.head.appendChild(script);

  } catch (err) {
    console.log('body exists?', Boolean(document.body), document.body) // logs as true, meaning script does not prevent body from rendering
    console.warn("A/B test script not loaded in time or fetch failed:", err);
    // No need to throw — we fail silently on purpose
  }
})();
</script>

The problem is that it doesn’t seem to block the page from rendering the body until async operations finish. How can this inline script be made to block the page from rendering until async operations finish (or abort if the timeout takes too long to not prevent the page from loading)? Or alternatively is there another solution?

Get iframe src from external link [closed]

I have an link where always fresh domain update
https://lernodydenknow.info/current_domain?tid=1151232&enc=0&srv=rt_adblock_backup

I want any script that can pick always new domain from this link and use in my iframe

My iframe example is this

witalfialdt.com this domain name will change when new domain update in “https://lernodydenknow.info/current_domain?tid=1151232&enc=0&srv=rt_adblock_backup” this link

so script always use up to date domain name in iframe

MemberExpression evaluation order of null/undefined base

Why does the following code throw TypeError: Cannot set properties of null instead of Error: property key evaluated?

var base = null;
var prop = {
  toString: function() {
    throw new Error("property key evaluated");
  }
};

base[prop] = 2;

This behavior suggests the base is converted to object before the index is converted to string. But the ECMAScript specification…

https://tc39.es/ecma262/#sec-assignment-operators-runtime-semantics-evaluation
https://tc39.es/ecma262/#sec-property-accessors-runtime-semantics-evaluation
https://tc39.es/ecma262/#sec-evaluate-property-access-with-expression-key
https://tc39.es/ecma262/#sec-topropertykey
https://tc39.es/ecma262/#sec-putvalue

…seems to indicate clearly that ? ToPropertyKey(propertyNameValue) (calling ToString(prop), which should throw new Error()) happens before ? ToObject(V.[[Base]]) (calling ToObject(base), throwing a TypeError). What’s going on here?

(If this is nonconformance by major engines, why is Test262 expecting this behavior?)

Contentful multiple content types filtering

I’ve an Intros content type in Contentful, and this is some portion of the JSON representation of the content type

{
  "name": "Intros",
  "description": "Inserted into existing pages",
  "displayField": "title",
  "fields": [
    {
      "id": "title",
      "name": "Title",
      "type": "Symbol",
      "localized": false,
      "required": true,
      "validations": [],
      "disabled": false,
      "omitted": false
    },
    {
      "id": "reviewStatus",
      "name": "Review Status",
      "type": "Symbol",
      "localized": false,
      "required": false,
      "validations": [
        {
          "in": [
            "Internal",
            "Accepted"
          ]
        }
      ],
      "disabled": false,
      "omitted": false
    },
    {
      "id": "referencePages",
      "name": "Reference Pages",
      "type": "Array",
      "localized": false,
      "required": false,
      "validations": [],
      "disabled": false,
      "omitted": false,
      "items": {
        "type": "Link",
        "validations": [
          {
            "linkContentType": [
              "application",
              "activity",
              "assessments",
              "book",
              "client",
              "landing",
              "list",
              "onlineProgram",
              "organization",
              "person",
              "podcast",
              "topics",
              "video"
            ]
          }
        ],
        "linkType": "Entry"
      }
    },
    {
      "id": "excludeClient",
      "name": "Exclude Client",
      "type": "Array",
      "localized": false,
      "required": false,
      "validations": [],
      "disabled": false,
      "omitted": false,
      "items": {
        "type": "Link",
        "validations": [
          {
            "linkContentType": [
              "client"
            ]
          }
        ],
        "linkType": "Entry"
      }
    }
  ]
}

And I’ve a contentful query to get all intros where a reference page is used, like I want to get intros where 7HizEUDWMMWA4EMkm8kcKS application type resource is used and I’ve this query and it does return 1 item where the reference id is used which is correct.

    const ctfPayload = {
      content_type: 'intros',
      select:
        'fields.referencePages,fields.client,fields.excludeClient,fields.commonPages,fields.header,fields.description,fields.url,fields.linkName,fields.style,fields.image,fields.multipleImages,fields.tags,fields.context',
      'fields.reviewStatus': 'Accepted',
      limit: 1000,
      'fields.referencePages.sys.id': '7HizEUDWMMWA4EMkm8kcKS',
    };

    const response = await ctf.getEntries(ctfPayload);

So the first questions is: If I use GraphQl to do same thing, I got 0 items which is confusing as they’re exactly same query.

query {
  introsCollection(
    where: {
      reviewStatus: "Accepted",
      referencePages: {
        sys: {
          id: "7HizEUDWMMWA4EMkm8kcKS"
        }
      }
    }
    limit: 1000
  ) {
    items {
      title
    }
    total
  }
}

The second question is, all reference page content types have a slug properly with same id and type, and according to the documentation I can provide slug to filter intros by referencePages.slug
https://www.contentful.com/developers/docs/references/graphql/#/reference/collection-filters/nested-collection-filters

And as you can see the GraphQL playground it understood and we can apply a slug filter for a reference pages, but it does return 0 items, while the first intro does have a reference page called Calm with slug calm, I confirmed this as if I remove referencePages filter I got 141 intros and the first intro which contains calm reference page is also returned.

enter image description here

If I try same with the contentful JS api I got an error

    const ctfPayload = {
      content_type: 'intros',
      select:
        'fields.referencePages,fields.client,fields.excludeClient,fields.commonPages,fields.header,fields.description,fields.url,fields.linkName,fields.style,fields.image,fields.multipleImages,fields.tags,fields.context',
      'fields.reviewStatus': 'Accepted',
      limit: 1000,
      'fields.referencePages.slug': 'calm',
    };

    const response = await ctf.getEntries(ctfPayload);

This is the error I’m getting

{
    "sys": {
        "type": "Error",
        "id": "InvalidQuery"
    },
    "message": "The query you sent was invalid. Probably a filter or ordering specification is not applicable to the type of a field.",
    "details": {
        "errors": [
            {
                "name": "unknown",
                "path": [
                    "fields",
                    "referencePages",
                    "en-US",
                    "slug"
                ],
                "details": "The path "fields.referencePages.en-US.slug" is not recognized"
            }
        ]
    },
    "requestId": "8c86a826-0025-463c-8bcc-2a1bbb4955cd"
}

So I want to filter intros by referencePages.slug as all the reference page content types have a slug property with same id and type.

I tried to add referencePages.slug in contentful js api, and in GraphQL I tried to add both sys.id and slug filters for referencePages

Inferring the drawing direction of a rotation+reflection matrix applied to a canvas

I have a function that needs to know whether the canvas will draw up and/or left from the origin (pointsLeft and pointsUp are booleans). I am trying to determine, whether the axes are flipped visually from drawing down and right. The DOMMatrix applied to the canvas has reflection done with rotate/scale and then a further rotation applied.

    const radians = getAngleFromOrigin(line);
    const angle = getDegreesFromRadians(radians);
    matrix.rotateSelf(angle);
    matrix.scaleSelf(1, -1);
    matrix.rotateSelf(-angle);
    const longestEdgeAngle = getLongestEdgeAngle(originalPoints);
    const degrees = getDegreesFromRadians(longestEdgeAngle);
    matrix.rotateSelf(degrees);

I feel like I should be able to look at the signs of a and d and know, but they don’t seem to correspond to the actual drawing direction? I got better results by comparing the absolute values of a/b and c/d and then checking whether the value with the greater magnitude was < 0 (implemented in my snippet), but it still failed in one case. I also tried various things involving the net rotation (or taking atan2 of b/a) and trying to see if that changed which one I should check the sign of for each of a/b and c/d, but I couldn’t work it out.

Technically speaking, I don’t need to determine it from the matrix directly, as I have access to the transformations applied to the matrix. It just seemed safest to me. If context on my function is necessary, see my answer to my previous question here.

I tried looking at the values of the matrixes of my different test cases, but I cannot work out why matrixes with the same signs on a/b/c/d orient differently (in my example, the first test’s green piece – the long horizontal one – and the last test’s orange piece – the short one – have identical signs, but different drawing orientations).

Code below with some test cases embedded, the goal is to have the image perfectly overlap the outline when clipped (which it will do if I can get this working):

"use strict";
const canvasWidth = 600;
const canvasHeight = 830;
const pieces = [
  [{
    points: [new DOMPoint(140, 50), new DOMPoint(140.00000000000003, -90), new DOMPoint(90.00000000000001, -90), new DOMPoint(90, 0), ],
    line: {
      start: new DOMPoint(283.6663192636163, 193.66631926361632),
      end: new DOMPoint(-52.666319263616316, -142.66631926361632)
    },
    original: [new DOMPoint(140, 50), new DOMPoint(0, 50), new DOMPoint(0, 0), new DOMPoint(90, 0), ],
    intersects: [new DOMPoint(90, 0), new DOMPoint(140, 50), ],
    origTopLeft: new DOMPoint(0, 0),
    width: 50.00000000000003,
    height: 50.00000000000003
  }, {
    points: [new DOMPoint(158.36517719568567, 44.67326250912334), new DOMPoint(163.97896049896048, -53.783451143451146), new DOMPoint(213.82095634095634, -49.58802494802492), new DOMPoint(211.1386748844376, -2.5451301597599514), ],
    line: {
      start: new DOMPoint(252.24682141160773, -39.3261033682806),
      end: new DOMPoint(101.75317858839227, 95.3261033682806)
    },
    original: [new DOMPoint(158.36517719568567, 44.67326250912335), new DOMPoint(256.8378378378378, 50), new DOMPoint(258.18918918918916, -1.6317320576126618e-15), new DOMPoint(211.1386748844376, -2.5451301597599563), ],
    intersects: [new DOMPoint(211.1386748844376, -2.5451301597599514), new DOMPoint(158.36517719568567, 44.67326250912334), ],
    origTopLeft: new DOMPoint(158.36517719568567, -2.5451301597599563),
    width: 55.45577914527067,
    height: 55.45577914527067
  }, {
    points: [new DOMPoint(198.38255973344914, 8.868236027966603), new DOMPoint(-153.64897521683866, 5.578032470538176), new DOMPoint(-154.11627140114496, 55.57584876561373), new DOMPoint(143.07549812764987, 58.3535016752606), ],
    line: {
      start: new DOMPoint(436.3443301443184, -204.04492697123226),
      end: new DOMPoint(-82.3443301443184, 260.04492697123226)
    },
    original: [new DOMPoint(198.3825597334491, 8.868236027966553), new DOMPoint(162.65825355141538, 359.09787638799855), new DOMPoint(112.9163540869709, 354.0240772523315), new DOMPoint(143.0754981276499, 58.353501675260645), ],
    intersects: [new DOMPoint(143.07549812764987, 58.3535016752606), new DOMPoint(198.38255973344914, 8.868236027966603), ],
    origTopLeft: new DOMPoint(112.9163540869709, 8.868236027966553),
    width: 352.49883113459407,
    height: 352.49883113459407
  }, ],
  [{
    points: [new DOMPoint(183, 0), new DOMPoint(-115.80000000000018, -398.4000000000001), new DOMPoint(-155.80000000000018, -368.4000000000001), new DOMPoint(158, 50), ],
    line: {
      start: new DOMPoint(466.81944546997806, -567.6388909399561),
      end: new DOMPoint(-126.81944546997806, 619.6388909399561)
    },
    original: [new DOMPoint(183.00000000000003, 0), new DOMPoint(681, 0), new DOMPoint(681, 50), new DOMPoint(158, 50), ],
    intersects: [new DOMPoint(158, 50), new DOMPoint(183, 0), ],
    originalTopLeft: new DOMPoint(158, 0),
    width: 338.8000000000002,
    height: 338.8000000000002
  }, ],
  [{
    points: [new DOMPoint(157.50666666666666, 24.98461538461538), new DOMPoint(232.01174895512395, 458.84515237596656), new DOMPoint(182.7330781575854, 467.307575458501), new DOMPoint(121.1733333333333, 108.830769230769), ],
    line: {
      start: new DOMPoint(358.8607804360353, -439.6787240831585),
      end: new DOMPoint(-43.86078043603533, 489.6787240831585)
    },
    original: [new DOMPoint(157.50666666666666, 24.9846153846154), new DOMPoint(-210.00917431192647, 267.30275229357795), new DOMPoint(-182.48623853211006, 309.045871559633), new DOMPoint(121.17333333333352, 108.83076923076914), ],
    intersects: [new DOMPoint(121.1733333333333, 108.830769230769), new DOMPoint(157.50666666666666, 24.98461538461538), ],
    originalTopLeft: new DOMPoint(-210.00917431192647, 24.9846153846154),
    width: 110.83841562179065,
    height: 110.83841562179065
  }, {
    points: [new DOMPoint(118.49999999999997, 49.99999999999999), new DOMPoint(207.78082191780817, 127.91780821917807), new DOMPoint(240.6575342465753, 90.24657534246575), new DOMPoint(137.25, -4.9897642155143516e-15), ],
    line: {
      start: new DOMPoint(199.2848941516392, -165.42638440437122),
      end: new DOMPoint(55.71510584836079, 217.42638440437122)
    },
    original: [new DOMPoint(118.5, 50), new DOMPoint(0, 50), new DOMPoint(0, 0), new DOMPoint(137.25, 0), ],
    intersects: [new DOMPoint(137.25, -4.9897642155143516e-15), new DOMPoint(118.49999999999997, 49.99999999999999), ],
    originalTopLeft: new DOMPoint(0, 0),
    width: 122.15753424657532,
    height: 122.15753424657532
  }]
];

// reflect, rotate by angle of the longest edge of the pre-reflected shape so that the image renders at the right angle on the page

function getReflectionMatrix(piece, ctx) {
  const {
    line,
    original,
    points,
    intersects
  } = piece;
  const anchor = intersects[0]; // point where the line and the other edges meet, used as an origin for reflection

  const display = new DOMMatrix();
  reflectMatrix(display, line, anchor);
  rotateMatrix(display, original, anchor); // i do this so the image shows up at the right angle on the canvas
  translateMatrix(display, points, ctx);
  return display;
}

function reflectMatrix(matrix, line, anchor) {
  const radians = getAngleFromOrigin(line);
  const angle = getDegreesFromRadians(radians);

  matrix.translateSelf(anchor.x, anchor.y);
  matrix.rotateSelf(angle);
  matrix.scaleSelf(1, -1);
  matrix.rotateSelf(-angle);
}

function rotateMatrix(matrix, originalPoints, anchor) {
  const longestEdgeAngle = getLongestEdgeAngle(originalPoints);
  const degrees = getDegreesFromRadians(longestEdgeAngle);

  matrix.rotateSelf(degrees);
  matrix.translateSelf(-anchor.x, -anchor.y);
}

// snap the image to the appropriate point on the axis-aligned bounding box

function translateMatrix(matrix, newPoints, ctx) {
  const pt0T = new DOMPoint(0, 0).matrixTransform(matrix);
  const { pointsUp, pointsLeft } = getMatrixDirection(matrix);
  const corners = getRotatedBoundingBox(newPoints);

  let d = "topLeft";
  if (pointsUp && pointsLeft) d = "bottomRight";
  if (pointsUp && !pointsLeft) d = "bottomLeft";
  if (pointsLeft && !pointsUp) d = "topRight";
  const target = corners[d];

  const dx = target.x - pt0T.x;
  const dy = target.y - pt0T.y;
  const translated = new DOMMatrix().translateSelf(dx, dy);
  matrix.preMultiplySelf(translated);

  drawDebugMarker(target.x, target.y, "purple", ctx); // visualises the origin
}

// extracts the up/down and left/right orientation of the matrix as applied to a canvas

function getMatrixDirection(matrix) {
  const { a, b, c, d } = matrix;
  let pointsLeft = Math.abs(a) >= Math.abs(b) ? a < 0 : b < 0;
  let pointsUp = Math.abs(c) >= Math.abs(d) ? c < 0 : d < 0;
  return { pointsLeft, pointsUp };
}

// rotated bounding box helpers - everything below is pretty irrelevant to the question afaict

function getRotatedBoundingBox(points) {
    const { angle, corners } = getBestBox(points);
    const cos = Math.cos(-angle);
    const sin = Math.sin(-angle);
    const unrotated = corners.map(point => rotatePoint(point, sin, cos));
    return sortCorners(unrotated);
}

function sortCorners(points) {
  const sorted = points.toSorted((a, b) => a.y == b.y ? a.x - b.x : a.y - b.y);
  const [pt1, pt2, pt3, pt4] = sorted;
  const [topLeft, topRight] = pt1.x < pt2.x ? [pt1, pt2] : [pt2, pt1];
  const [bottomLeft, bottomRight] = pt3.x < pt4.x ? [pt3, pt4] : [pt4, pt3];
  return { topLeft, topRight, bottomRight, bottomLeft };
}

function getBestBox(points) {
    let bestArea = Infinity;
    let bestBox;
    for (let i = 0; i < points.length; i++) {
        const a = points[i];
        const b = points[(i + 1) % points.length];
        const angle = -Math.atan2(b.y - a.y, b.x - a.x);
        const cos = Math.cos(angle);
        const sin = Math.sin(angle);

        const rotated = points.map(point => rotatePoint(point, sin, cos));
        const { width, height } = getDimensions(rotated);
        const area = width * height;
        if (area < bestArea) {
            bestArea = area;
            bestBox = makeBoundingBox(rotated, angle);
        }
    }
    return bestBox;
}

function rotatePoint(point, sin, cos) {
    const { x, y } = point;
    return new DOMPoint(rotateX(x, y, sin, cos), rotateY(x, y, sin, cos));
}

function rotateX(x, y, sin, cos) {
    return x * cos - y * sin;
}

function rotateY(x, y, sin, cos) {
    return x * sin + y * cos;
}

function makeBoundingBox(points, angle) {
    const { minX, maxX, minY, maxY } = getBoundingBox(points);
    return {
        corners: [
            new DOMPoint(minX, minY),
            new DOMPoint(maxX, minY),
            new DOMPoint(maxX, maxY),
            new DOMPoint(minX, maxY),
        ],
        angle
    };
}

// helpers for getting shape dimensions etc.

function getAngleFromOrigin(line) {
  const { start, end } = line;
  const dx = end.x - start.x;
  const dy = end.y - start.y;
  return Math.atan2(dy, dx);
}

function getLongestEdgeAngle(points) {
  let maxLength = 0;
  let bestAngle = 0;
  for (let i = 0; i < points.length; i++) {
    const a = points[i];
    const b = points[(i + 1) % points.length];
    const dx = b.x - a.x;
    const dy = b.y - a.y;
    const length = Math.hypot(dx, dy);
    if (length > maxLength) {
      maxLength = length;
      bestAngle = Math.atan2(dy, dx);
    }
  }
  return bestAngle;
}

function getDegreesFromRadians(angle) {
  const degrees = angle * 180 / Math.PI;
  return ((degrees % 360) + 360) % 360;
}

function getTopLeft(points) {
  const { minX, maxX, minY, maxY } = getBoundingBox(points);
  return new DOMPoint(minX, minY);
}

function getBoundingBox(points) {
  const coordsX = points.map(point => point.x);
  const minX = Math.min(...coordsX);
  const maxX = Math.max(...coordsX);
  const coordsY = points.map(point => point.y);
  const minY = Math.min(...coordsY);
  const maxY = Math.max(...coordsY);
  return {
    minX,
    maxX,
    minY,
    maxY
  };
}

function getDimensions(points) {
  const { minX, maxX, minY, maxY } = getBoundingBox(points);
  const width = maxX - minX;
  const height = maxY - minY;
  return {
    width,
    height
  };
}

// drawing

function loopThroughPieces(test, ctx, testNum) {
  for (let i = 0; i < test.length; i++) {
    ctx.setTransform(canvasTransform);
    const piece = test[i];
    const colour = getColour(i);
    const display = getReflectionMatrix(piece, ctx);
    drawPiece(piece, colour, display, ctx);
  }
}

function getColour(i) {
  // red comes first
  const hue = (i * 45) % 360;
  const lightness = 100 - (40 + 10);
  const alpha = 0.5;
  return `hsla(${hue}, 90%, ${lightness}%, ${alpha})`;
}

function drawPiece(piece, colour, display, ctx) {
  ctx.save();
  tracePiecePath(piece.points, ctx);
  ctx.globalAlpha = 0.65;
  //ctx.clip(); // it's supposed to be clipped, but i unclipped for visualisation, since sometimes the image floats outside of the outline

  ctx.setTransform(canvasTransform.multiply(display));
  ctx.drawImage(image, 0, 0, image.width, image.height);

  ctx.strokeStyle = colour;
  ctx.lineWidth = 3;
  ctx.globalAlpha = 1;
  ctx.stroke();

  ctx.restore();
  ctx.save();
}

function tracePiecePath(points, ctx) {
  ctx.beginPath();
  const firstPoint = points[0];
  ctx.moveTo(firstPoint.x, firstPoint.y);
  points.slice(1).forEach(point => {
    ctx.lineTo(point.x, point.y);
  });
  ctx.closePath();
}

function drawDebugMarker(x, y, colour, ctx) {
  ctx.beginPath();
  ctx.arc(x, y, 5, 0, 2 * Math.PI);
  ctx.fillStyle = colour;
  ctx.fill();
}

// everything below is just assembling test cases etc. and rendering them

function makeCanvasTransform() {
  canvasTransform.scaleSelf(0.6, 0.6);
  canvasTransform.translateSelf(canvasWidth / 2, canvasHeight / 2);
}

function drawDebugImage() {
  const imgCtx = image.getContext("2d");
  imgCtx.fillStyle = "white";
  imgCtx.fillRect(0, 0, image.width, image.height);
  imgCtx.font = "20px arial";
  imgCtx.textAlign = "center";
  imgCtx.fillStyle = "black";
  const segmentWidth = image.width / 12;
  let offsetX = 0;
  for (let i = 0; i < Math.ceil(image.width / segmentWidth); i++) {
    imgCtx.strokeRect(offsetX, 0, segmentWidth, image.height);
    imgCtx.fillText(i + 1, offsetX + segmentWidth / 2, image.height / 2);
    offsetX += segmentWidth;
  }
}

function gatherCtxs() {
  const ctxs = [];
  for (let i = 0; i < pieces.length; i++) {
    const canvas = document.createElement("canvas");
    canvas.width = canvasWidth;
    canvas.height = canvasHeight;
    canvases.appendChild(canvas);
    if (i % 2 == 1) {
      const br = document.createElement("br");
      canvases.appendChild(br);
    }
    ctxs.push(canvas.getContext("2d"));
  }
  return ctxs;
}

const image = document.getElementById("image");
const canvases = document.getElementById("canvases");
const canvasTransform = new DOMMatrix();

drawDebugImage();
makeCanvasTransform();
const ctxs = gatherCtxs();
for (let i = 0; i < pieces.length; i++) {
  loopThroughPieces(pieces[i], ctxs[i], i);
}
canvas {
    border: 1px solid grey;
    margin: 2px;
}
<p><canvas id="image" width="680" height="50"></canvas></p>
<p id="canvases"></p>

Upload multiple images related to hasMany() entity in same create form using BackPack and Laravel 11

I’m building an admin panel using Laravel 11 and Backpack PRO 6.x (Tabler theme).

I have two models with a one-to-many relationship:

ProdutoVariacao (main entity)

ProdutoVariacaoImagem (child entity)

The relationship is as follows:

One ProdutoVariacao has many ProdutoVariacaoImagem (hasMany)

Each ProdutoVariacaoImagem belongs to one ProdutoVariacao (belongsTo)

My goal is to allow users to create a new ProdutoVariacao entry and upload multiple images within the same create form. Each uploaded image should:

Be physically stored on disk (e.g. storage/app/…).

Automatically create a record in the produto_variacao_imagens table, properly linked to the ProdutoVariacao via foreign key.

The database and models are fully set up with the correct relationships.

What I’m looking for:

What is the recommended way to implement this kind of nested form behavior in Backpack PRO 6.x?

Should I use Backpack’s repeatable fields? Or relationship fields? Or handle everything manually inside store() and update() methods?

How can I properly store both the main entity and the related images together in the same request?

Any concrete example, best practice, or recommended Backpack approach would be greatly appreciated.

I’ve already tried several approaches, but none fully solved the problem. The closest I got was being able to store the correct file path in the database, but I couldn’t manage to actually store the image physically inside /storage.

Thank you in advance!

Site domain tranformed as additional URL parameter

I have the same web infrastructure for different sites. In my reality different sites are representation of different content from different databases on the same web infrastructure but I want to keep it hidden from users.

I want that domain name is transferred as additional parameter site in my URL but this has to be hidden from users. For example one domain URL http://www.domain1.com should be transferred into http://www.maindomain.com/?site=domain1, other domain http://www.domain2.com into http://www.maindomain.com/?site=domain2.

Other URL parameters should be preserved as well. For example: http://www.domain3.com/index.php?param1=100&param2=200 should be transferred into http://www.maindomain.com/index.php?site=domain3&param1=100&param2=200

All this should be hidden from user – user should only see:

http://www.domain3.com/index.php?param1=100&param2=200

but in background the following should be processed:

http://www.maindomain.com/index.php?site=domain3&param1=100&param2=200

How to achieve this?

Laravel returns 404 when deployed to public_html subdirectory (`~username` path)

As the final task of my university practice, we need to deploy our Laravel project to the university server.

When I SSH into the machine, I land in my home directory, which only contains a public_html directory (and this root directory is not writable). I’ve placed all the Laravel files inside that directory, so the structure looks like this:

public_html
|- .env
|- .htaccess
|- app
|- bootstrap
|- composer.json
|- public
|- resources
|- routes
|- storage
|- vendor

Since there’s no index.php directly inside public_html, I added a .htaccess file to redirect everything to public/index.php:

RewriteEngine On
RewriteRule ^$ public/index.php [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ public/index.php [L]

With this setup, I’m able to access Laravel by visiting:
https://<university domain>/~dramosac

However, Laravel treats ~dramosac as part of the requested route, which doesn’t exist, so it returns a 404 error.

To debug this, I updated the 404 page to show some request details:

<pre>
Requested URL: {{ request()->fullUrl() }}
Internal path (request()->path()): {{ request()->path() }}
APP_URL: {{ config('app.url') }}
Current route name: {{ Route::currentRouteName() ?? 'None' }}
Current controller: {{ optional(Route::getCurrentRoute())->getActionName() }}
Authenticated?: {{ Auth::check() ? 'Yes' : 'No' }}
HTTP Method: {{ request()->method() }}
</pre>

The output is:

Requested URL: https://<university domain>/~dramosac
Internal path (request()->path()): ~dramosac
APP_URL: https://<university domain>/~dramosac
Current route name: None
Current controller: 
Authenticated?: No
HTTP Method: GET

As you can see, Laravel thinks ~dramosac is the internal path, even though I set the correct APP_URL in the .env file.

Question:
Why does Laravel still treat ~dramosac as part of the route, even though APP_URL is set correctly? How can I configure Laravel to serve the correct routes from this subdirectory?

Thanks in advance!

Most efficient way to handle large-scale array processing in PHP 8.3 without memory exhaustion? [closed]

I’m working with large datasets (100K+ rows from MySQL) in PHP 8.3 and need to optimize memory usage. I’ve experimented with generators using yield, SplFixedArray, and processing data in chunks with array_chunk, but I’m wondering if PHP 8.3’s JIT compiler or other new features offer better solutions.

Specifically, I’d like to know if there are any measurable improvements in memory efficiency when using foreach versus array_reduce for large datasets in PHP 8.3. Does the JIT compiler help reduce memory overhead for data processing tasks? Are there any new PHP 8.3 features specifically designed for handling large datasets more efficiently?

I’m particularly interested in answers supported by benchmarks, official PHP documentation, or detailed profiling results that demonstrate memory usage differences between approaches in PHP 8.3.

(React) Inline HTML leaves detached DOM; React component doesn’t

When we render some nodes conditionally(ex. {expanded && <>...</>}), HTML element leaves detached DOM, but React Components doesn’t.

Example

e.g.

...
return <>
  ...
  {expanded && <div id="inlined">Foo</div>
</> 

If the expanded state goes false -> true -> false, the elements in right side will be inserted and removed from DOM.
After that, <div id="inlined">Foo</div> left as detached DOM.

But, when I make them as seperated component:

function Foo() {
  return <div id="seperated">Foo</div>
}

and, doing something like previous one but using <Foo /> component instead of inline HTML element:

...
return <>
  ...
  {expanded && <Foo />
</> 

It does not leave detached DOM.

detached DOM snapshot from Chrome DevTools

this is detached DOM snapshot from Chrom DevTools

And I wonder that..

What’s difference between using inline <div>(or other HTML elements) and wrapping/seperating into a component?
I would like to know the exact explanation for this phenomenon.

More Examples with CodeSandbox you can see

Visit https://q4g5mg.csb.app/ , click the button twice, to expand/collapse, and then make a snapshot

Full code of example is below:

import { useState } from "react";
import "./App.css";

const dummyArrays = Array.from({ length: 100 });
const Dummy = () => {
  return (
    <ul>
      {dummyArrays.map((_, index) => (
        <li key={index}>{index}</li>
      ))}
    </ul>
  );
};

function WowList() {
  return (
    <ul id="wow-list">
      <li>WOW</li>
      <li>WOW</li>
      <li>WOW</li>
      <li>WOW</li>
      <li>WOW</li>
    </ul>
  );
}


export default function App() {
  const [expanded, setExpanded] = useState(false);

  return (
    <>
      <button
        onClick={() => {
          setExpanded((prev) => !prev);
        }}
      >
        {expanded ? "close" : "open"}
      </button>
      {expanded && (
        <>
          <div id="this-dummy-remains-detached-dom">
            <Dummy />
          </div>
          <div id="this-div-also-remains-attached-dom">
            <p>Detached DOM Elements problem test</p>
          </div>
          <WowList />
        </>
      )}
    </>
  );
}

before

^ Snapshot: before expand/collapse

after

^ Snapshot: after expand/collapse

<WowList /> does not remained detached DOM, but the rest of them (under the <div>, regardless of whether it’s an HTML element or component)

Waiting for a clear answer to this. Thanks!

Drizzle ORM + Postgres, how to specify Postgres database Schema? defaults to public

I am trying to set connection to Postgres from Drizzle, but I cannot set the schema name in the connection string

I tried
postgres://localhost:5432/mydatabase?searchpath=myschema

postgres://localhost:5432/mydatabase?currentSchema=myschema

postgres://localhost:5432/mydatabase.myschema

none of these worked.
Drizzle would still connect to the default public schema, which Postgres documenntation advice not to use
Also, there is no concept of a public schema in the SQL standard. For maximum conformance to the standard, you should not use the public schema.https://www.postgresql.org/docs/current/ddl-schemas.html

Also on Drizzle docs for connection string they don’t specify how to choose schema, using this keyword in general is very confusing in the Drizzle echo system as it usually lead to answers about defining the drizzle typescript schema.
https://orm.drizzle.team/docs/connect-overview

How to retrieve the visible content of multiple `select` elements at once?

I want to retrieve the visible text content of an div element which contains several <select> elements:

However, div.innerText will include text content in all <option> tags, including unselected ones (and to my surprise, even hidden ones are included as well).

let div=document.querySelector("div")
console.log("div.innerText:n"+div.innerText)
select {
  appearance: none;
  border: none
}
<div id="div">
  <select>
    <option selected>Alice</option>
    <option>Bob</option>
    <option hidden>Carol</option>
  <select>
  -
  <span>
    <!-- the dom tree could be complicated -->
    <span>
      <select>
        <option>Alice</option>
        <option selected>Bob</option>
      <select>
    </span>
  </span>
</div>

What I want is simple Alice - Bob.

Is it possible to make it?