From 1d684367ed99f8e4a6c525993d6bc4bc23e4c0b0 Mon Sep 17 00:00:00 2001 From: min-kim42 Date: Sat, 2 Nov 2024 08:53:25 +0000 Subject: [PATCH 001/282] Update .all-contributorsrc --- .all-contributorsrc | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 68bff60a05..ac215303c0 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1797,16 +1797,6 @@ "example" ] }, - { - "login": "mjaything", - "name": "Minjun Kim", - "avatar_url": "https://avatars1.githubusercontent.com/u/13192500?v=4", - "profile": "https://github.com/mjaything", - "contributions": [ - "bug", - "translation" - ] - }, { "login": "fisherdiede", "name": "Fisher Diede", From 5c0da0127ad0f57705099595dc2fa5a121ff1b8e Mon Sep 17 00:00:00 2001 From: Andrew McWhae Date: Fri, 13 Dec 2024 00:03:10 -0700 Subject: [PATCH 002/282] Fixed loop variable in createFileInput() docs (dom.js) --- src/dom/dom.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dom/dom.js b/src/dom/dom.js index 2f04be1ef2..d35fbc4ea3 100644 --- a/src/dom/dom.js +++ b/src/dom/dom.js @@ -2023,7 +2023,7 @@ p5.prototype.createInput = function (value = '', type = 'text') { * let y = i * 20; * * // Draw the image. - * image(img, 0, y, 100, 100); + * image(images[i], 0, y, 100, 100); * } * * describe('A gray square with a file input beneath it. If the user selects multiple image files to load, they are displayed on the square.'); From ef7104d6e757ebfc8e77020a734bec6d18791e66 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 20 Jan 2025 15:48:36 +0000 Subject: [PATCH 003/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c12e63e511..4ad03f2940 100644 --- a/README.md +++ b/README.md @@ -1080,6 +1080,7 @@ We recognize all types of contributions. This project follows the [all-contribut Rajas Samse
Rajas Samse

💻 📖 + Jordan Philyaw
Jordan Philyaw

📖 From 34b40583f513e0c21969e3081d24f6cd5b9a80c4 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 20 Jan 2025 15:48:37 +0000 Subject: [PATCH 004/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 55809f85bd..6658e7cf18 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6445,6 +6445,15 @@ "code", "doc" ] + }, + { + "login": "philyawj", + "name": "Jordan Philyaw", + "avatar_url": "https://avatars.githubusercontent.com/u/37485853?v=4", + "profile": "http://jordanphilyaw.com", + "contributions": [ + "doc" + ] } ], "repoType": "github", From c0b6c97b96b58d6412390be9de05fbaba0991a1b Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 13:14:52 +0000 Subject: [PATCH 005/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c12e63e511..71b943cea0 100644 --- a/README.md +++ b/README.md @@ -1080,6 +1080,7 @@ We recognize all types of contributions. This project follows the [all-contribut Rajas Samse
Rajas Samse

💻 📖 + oliver thurley
oliver thurley

📖 💻 From 8ff83d3d16843507849e91de68b58093e8ce05b4 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 13:14:53 +0000 Subject: [PATCH 006/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 55809f85bd..c82c0bf054 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6445,6 +6445,16 @@ "code", "doc" ] + }, + { + "login": "thrly", + "name": "oliver thurley", + "avatar_url": "https://avatars.githubusercontent.com/u/22343302?v=4", + "profile": "http://oliverthurley.co.uk", + "contributions": [ + "doc", + "code" + ] } ], "repoType": "github", From 65b8a81f39a35f36b038a4244a0b88341a7b0b8a Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 23 Jan 2025 01:59:06 +0000 Subject: [PATCH 007/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 19505fbabc..4e540bef8b 100644 --- a/README.md +++ b/README.md @@ -1080,6 +1080,7 @@ We recognize all types of contributions. This project follows the [all-contribut Rajas Samse
Rajas Samse

💻 📖 + Renjie Li
Renjie Li

📖 💻 From 8b7f6f25249ad587791ab9ec1f969b330b79dbf0 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 23 Jan 2025 01:59:07 +0000 Subject: [PATCH 008/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 55809f85bd..ac4d8bff7b 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6445,6 +6445,16 @@ "code", "doc" ] + }, + { + "login": "lirenjie95", + "name": "Renjie Li", + "avatar_url": "https://avatars.githubusercontent.com/u/17038472?v=4", + "profile": "https://github.com/lirenjie95", + "contributions": [ + "doc", + "code" + ] } ], "repoType": "github", From b052d05292a24a9744e92c84e65df83848774f67 Mon Sep 17 00:00:00 2001 From: kit <1304340+ksen0@users.noreply.github.com> Date: Thu, 23 Jan 2025 18:24:50 -0500 Subject: [PATCH 009/282] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2f6e98fe70..a4ac1f2481 100644 --- a/README.md +++ b/README.md @@ -75,8 +75,8 @@ Current Lead/Mentor * [@limzykenneth](https://github.com/limzykenneth) - p5.js Mentor,2023-present Lead/Mentor Alumni -* [@lmccart](https://github.com/lmccart)- p5.js Creator -* [@qianqianye](https://github.com/qianqianye) - p5.js Lead,2021-2024 +* [@lmccart](https://github.com/lmccart) - p5.js Creator +* [@qianqianye](https://github.com/qianqianye) - p5.js Lead,2021-present (on leave) * [@outofambit](https://github.com/outofambit) - p5.js Co-Lead 2021-22, Mentor 2022-2023 * [@mcturner1995](https://github.com/mcturner1995) - p5.js Lead 2020 From c4d3f6c679c389245294a3ec13364b6957ffeace Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 26 Jan 2025 14:47:12 +0000 Subject: [PATCH 010/282] docs: update README.md [skip ci] --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d0a1aed6c2..e8f9221f4d 100644 --- a/README.md +++ b/README.md @@ -1081,8 +1081,9 @@ We recognize all types of contributions. This project follows the [all-contribut Rajas Samse
Rajas Samse

💻 📖 Jordan Philyaw
Jordan Philyaw

📖 - Renjie Li
Renjie Li

📖 💻 oliver thurley
oliver thurley

📖 💻 + Renjie Li
Renjie Li

📖 💻 + Ashish Karn
Ashish Karn

💻 From bc37994af6150ccedd0396ccb28bba1d47be61df Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 26 Jan 2025 14:47:13 +0000 Subject: [PATCH 011/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 3002b4b6f4..0be22a1b04 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6474,6 +6474,15 @@ "doc", "code" ] + }, + { + "login": "akkarn1689", + "name": "Ashish Karn", + "avatar_url": "https://avatars.githubusercontent.com/u/82334486?v=4", + "profile": "https://karn-ashish-16.onrender.com/", + "contributions": [ + "code" + ] } ], "repoType": "github", From 2939bf050115c662ffa72612d8b8880b9ec91990 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 26 Jan 2025 19:28:22 +0000 Subject: [PATCH 012/282] docs: update README.md [skip ci] --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d0a1aed6c2..80405ea840 100644 --- a/README.md +++ b/README.md @@ -1081,8 +1081,9 @@ We recognize all types of contributions. This project follows the [all-contribut Rajas Samse
Rajas Samse

💻 📖 Jordan Philyaw
Jordan Philyaw

📖 - Renjie Li
Renjie Li

📖 💻 oliver thurley
oliver thurley

📖 💻 + Renjie Li
Renjie Li

📖 💻 + Xin Xin
Xin Xin

📋 📢 🧑‍🏫 🤔 From c2966be28a6648582b126673f228ebdc1c16885b Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 26 Jan 2025 19:28:23 +0000 Subject: [PATCH 013/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 3002b4b6f4..fe6d18eb91 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6474,6 +6474,19 @@ "doc", "code" ] + }, + { + "login": "xinemata", + "name": "Xin Xin", + "avatar_url": "https://avatars.githubusercontent.com/u/9159424?v=4", + "profile": "https://github.com/xinemata", + "contributions": [ + "eventOrganizing", + "tutorial", + "talk", + "mentoring", + "ideas" + ] } ], "repoType": "github", From 07a10826ab235310729402a894aa49385124f23e Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2025 11:02:03 +0000 Subject: [PATCH 014/282] docs: update README.md [skip ci] --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d0a1aed6c2..d26880211d 100644 --- a/README.md +++ b/README.md @@ -1081,8 +1081,9 @@ We recognize all types of contributions. This project follows the [all-contribut Rajas Samse
Rajas Samse

💻 📖 Jordan Philyaw
Jordan Philyaw

📖 - Renjie Li
Renjie Li

📖 💻 oliver thurley
oliver thurley

📖 💻 + Renjie Li
Renjie Li

📖 💻 + Vaivaswat Dubey
Vaivaswat Dubey

💻 From 97894954a51e1315243b990445b5006a3f415eb9 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2025 11:02:04 +0000 Subject: [PATCH 015/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 3002b4b6f4..622d30aa0b 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6474,6 +6474,15 @@ "doc", "code" ] + }, + { + "login": "Vaivaswat2244", + "name": "Vaivaswat Dubey", + "avatar_url": "https://avatars.githubusercontent.com/u/113991324?v=4", + "profile": "https://github.com/Vaivaswat2244", + "contributions": [ + "code" + ] } ], "repoType": "github", From 4f7b652ffccc7d321ef2570bcd9f7fa40836c8c5 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2025 19:20:33 +0000 Subject: [PATCH 016/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 85ea9f2613..c7a05b47e6 100644 --- a/README.md +++ b/README.md @@ -1088,6 +1088,7 @@ We recognize all types of contributions. This project follows the [all-contribut Ashish Karn
Ashish Karn

💻 + Darren Kessner
Darren Kessner

💡 From 0faaa95569a75af7dad82a51e8841f61c266f425 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2025 19:20:33 +0000 Subject: [PATCH 017/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 3b506d5c77..93886d881d 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6505,6 +6505,15 @@ "contributions": [ "code" ] + }, + { + "login": "dkessner", + "name": "Darren Kessner", + "avatar_url": "https://avatars.githubusercontent.com/u/1002034?v=4", + "profile": "https://dkessner.github.io/", + "contributions": [ + "example" + ] } ], "repoType": "github", From c208fdda95b0cee1c2dbeadca90784e391b594ff Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2025 19:31:15 +0000 Subject: [PATCH 018/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c7a05b47e6..0a6713efd5 100644 --- a/README.md +++ b/README.md @@ -1089,6 +1089,7 @@ We recognize all types of contributions. This project follows the [all-contribut Ashish Karn
Ashish Karn

💻 Darren Kessner
Darren Kessner

💡 + Animesh Sinha
Animesh Sinha

💡 From eda36e0fa4435979df5780181604544752358071 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2025 19:31:16 +0000 Subject: [PATCH 019/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 93886d881d..3f8c72dcf5 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6514,6 +6514,15 @@ "contributions": [ "example" ] + }, + { + "login": "AnimeshSinha1309", + "name": "Animesh Sinha", + "avatar_url": "https://avatars.githubusercontent.com/u/9739218?v=4", + "profile": "http://www.facebook.com/AnimeshSinha1309", + "contributions": [ + "example" + ] } ], "repoType": "github", From b56e612f66afce4881d432b594784b2679c4729e Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2025 19:51:48 +0000 Subject: [PATCH 020/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0a6713efd5..8fbe2139a0 100644 --- a/README.md +++ b/README.md @@ -1090,6 +1090,7 @@ We recognize all types of contributions. This project follows the [all-contribut Ashish Karn
Ashish Karn

💻 Darren Kessner
Darren Kessner

💡 Animesh Sinha
Animesh Sinha

💡 + Kathryn Lichlyter
Kathryn Lichlyter

💡 From 7d4c1ebb91954878b3901ffd217f54b9dceb49ba Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2025 19:51:49 +0000 Subject: [PATCH 021/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 3f8c72dcf5..f759d5e629 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6523,6 +6523,15 @@ "contributions": [ "example" ] + }, + { + "login": "katlich112358", + "name": "Kathryn Lichlyter", + "avatar_url": "https://avatars.githubusercontent.com/u/59926191?v=4", + "profile": "https://github.com/katlich112358", + "contributions": [ + "example" + ] } ], "repoType": "github", From b930aa4471da2e809d2debfb6a46aaf8e317e595 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2025 22:51:55 +0000 Subject: [PATCH 022/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8fbe2139a0..1d73be1cea 100644 --- a/README.md +++ b/README.md @@ -1091,6 +1091,7 @@ We recognize all types of contributions. This project follows the [all-contribut Darren Kessner
Darren Kessner

💡 Animesh Sinha
Animesh Sinha

💡 Kathryn Lichlyter
Kathryn Lichlyter

💡 + Greg Albers
Greg Albers

💡 From 6924cd0de7c9be06479580d7bd069795fb981977 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2025 22:51:56 +0000 Subject: [PATCH 023/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index f759d5e629..1500bc9fbe 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6532,6 +6532,15 @@ "contributions": [ "example" ] + }, + { + "login": "geealbers", + "name": "Greg Albers", + "avatar_url": "https://avatars.githubusercontent.com/u/7796401?v=4", + "profile": "https://geealbers.net/", + "contributions": [ + "example" + ] } ], "repoType": "github", From 9b14757ed3d367d8914160e6f461b0749044d83e Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2025 23:07:46 +0000 Subject: [PATCH 024/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1d73be1cea..bb36116fb8 100644 --- a/README.md +++ b/README.md @@ -1092,6 +1092,7 @@ We recognize all types of contributions. This project follows the [all-contribut Animesh Sinha
Animesh Sinha

💡 Kathryn Lichlyter
Kathryn Lichlyter

💡 Greg Albers
Greg Albers

💡 + Marco Macarena
Marco Macarena

💡 From 2636dc1ea5d6ad324f58493cc08db090c5b1ede0 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2025 23:07:47 +0000 Subject: [PATCH 025/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 1500bc9fbe..3b21732aa3 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6541,6 +6541,15 @@ "contributions": [ "example" ] + }, + { + "login": "macarena", + "name": "Marco Macarena", + "avatar_url": "https://avatars.githubusercontent.com/u/79822?v=4", + "profile": "http://macarena.pro.br", + "contributions": [ + "example" + ] } ], "repoType": "github", From 0543d4888cae3bfb1471a28567c203e20c522705 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2025 23:14:55 +0000 Subject: [PATCH 026/282] docs: update README.md [skip ci] --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index bb36116fb8..95447a7bb4 100644 --- a/README.md +++ b/README.md @@ -1094,6 +1094,9 @@ We recognize all types of contributions. This project follows the [all-contribut Greg Albers
Greg Albers

💡 Marco Macarena
Marco Macarena

💡 + + Kristian Hamilton
Kristian Hamilton

💡 + From 4c5bbad806887850e1b3457d7c8627d1c469c59b Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2025 23:14:56 +0000 Subject: [PATCH 027/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 3b21732aa3..203718fe7f 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6550,6 +6550,15 @@ "contributions": [ "example" ] + }, + { + "login": "khamiltonuk", + "name": "Kristian Hamilton", + "avatar_url": "https://avatars.githubusercontent.com/u/4013283?v=4", + "profile": "http://www.khamilton.co.uk", + "contributions": [ + "example" + ] } ], "repoType": "github", From 5d9bb58abaa282c4e8905aee5241548a54c3dcaa Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2025 23:18:00 +0000 Subject: [PATCH 028/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 95447a7bb4..1462c94e55 100644 --- a/README.md +++ b/README.md @@ -1096,6 +1096,7 @@ We recognize all types of contributions. This project follows the [all-contribut Kristian Hamilton
Kristian Hamilton

💡 + Keshav Gupta
Keshav Gupta

💡 From e2a82693fc58e96b2247d868f4e587a274d4f12c Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2025 23:18:01 +0000 Subject: [PATCH 029/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 203718fe7f..87d733c1d1 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6559,6 +6559,15 @@ "contributions": [ "example" ] + }, + { + "login": "keshavg2", + "name": "Keshav Gupta", + "avatar_url": "https://avatars.githubusercontent.com/u/34001173?v=4", + "profile": "https://keshav-portfolio-resume.netlify.app/", + "contributions": [ + "example" + ] } ], "repoType": "github", From e4d2e0588c285f2165e7892e613c492d0b36e647 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 30 Jan 2025 02:10:12 +0000 Subject: [PATCH 030/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1462c94e55..36a75457aa 100644 --- a/README.md +++ b/README.md @@ -1097,6 +1097,7 @@ We recognize all types of contributions. This project follows the [all-contribut Kristian Hamilton
Kristian Hamilton

💡 Keshav Gupta
Keshav Gupta

💡 + Ritesh Patil
Ritesh Patil

💡 From d387b4c7cdf6b8cb16d4ee5936d6c4ffc271898a Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 30 Jan 2025 02:10:14 +0000 Subject: [PATCH 031/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 87d733c1d1..f8a5cdd2a7 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6568,6 +6568,15 @@ "contributions": [ "example" ] + }, + { + "login": "riteshsp2000", + "name": "Ritesh Patil", + "avatar_url": "https://avatars.githubusercontent.com/u/56112399?v=4", + "profile": "http://riteshpatil.com", + "contributions": [ + "example" + ] } ], "repoType": "github", From efa24b992031db978f6b271dc8973d1445d99956 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 30 Jan 2025 02:13:32 +0000 Subject: [PATCH 032/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 36a75457aa..6087d2a659 100644 --- a/README.md +++ b/README.md @@ -1098,6 +1098,7 @@ We recognize all types of contributions. This project follows the [all-contribut Kristian Hamilton
Kristian Hamilton

💡 Keshav Gupta
Keshav Gupta

💡 Ritesh Patil
Ritesh Patil

💡 + Gabriel Sroka
Gabriel Sroka

💡 From cf9b1b958ffe6db6065be6980a9981230349273c Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 30 Jan 2025 02:13:33 +0000 Subject: [PATCH 033/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index f8a5cdd2a7..6cbfbc40d4 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6577,6 +6577,15 @@ "contributions": [ "example" ] + }, + { + "login": "gabrielsroka", + "name": "Gabriel Sroka", + "avatar_url": "https://avatars.githubusercontent.com/u/14354736?v=4", + "profile": "https://gabrielsroka.github.io", + "contributions": [ + "example" + ] } ], "repoType": "github", From 24306a03ec60feaa4d501f2b03d845f094ee7e41 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 30 Jan 2025 02:16:35 +0000 Subject: [PATCH 034/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6087d2a659..e8c3e5e80e 100644 --- a/README.md +++ b/README.md @@ -1099,6 +1099,7 @@ We recognize all types of contributions. This project follows the [all-contribut Keshav Gupta
Keshav Gupta

💡 Ritesh Patil
Ritesh Patil

💡 Gabriel Sroka
Gabriel Sroka

💡 + Casey Conchinha
Casey Conchinha

💡 From 2dd335e2707293a1c89ecea8749b1dcb3da92b8e Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 30 Jan 2025 02:16:36 +0000 Subject: [PATCH 035/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 6cbfbc40d4..32fb8f26e2 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6586,6 +6586,15 @@ "contributions": [ "example" ] + }, + { + "login": "kcconch", + "name": "Casey Conchinha", + "avatar_url": "https://avatars.githubusercontent.com/u/26172283?v=4", + "profile": "http://kccon.ch", + "contributions": [ + "example" + ] } ], "repoType": "github", From b12f1a253ea8d405d7185153976efd7552dbea36 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 30 Jan 2025 02:20:42 +0000 Subject: [PATCH 036/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e8c3e5e80e..e7052eb4a0 100644 --- a/README.md +++ b/README.md @@ -1100,6 +1100,7 @@ We recognize all types of contributions. This project follows the [all-contribut Ritesh Patil
Ritesh Patil

💡 Gabriel Sroka
Gabriel Sroka

💡 Casey Conchinha
Casey Conchinha

💡 + davidblitz
davidblitz

💡 From c836104058eef78bfd3dc47baf6c813db000f488 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 30 Jan 2025 02:20:43 +0000 Subject: [PATCH 037/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 32fb8f26e2..4c88a1fd52 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6595,6 +6595,15 @@ "contributions": [ "example" ] + }, + { + "login": "davidblitz", + "name": "davidblitz", + "avatar_url": "https://avatars.githubusercontent.com/u/13055497?v=4", + "profile": "https://github.com/davidblitz", + "contributions": [ + "example" + ] } ], "repoType": "github", From 385f81b177afdca815a2c434c86e5d7d74835da3 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 30 Jan 2025 02:23:41 +0000 Subject: [PATCH 038/282] docs: update README.md [skip ci] --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index e7052eb4a0..3f66c9d166 100644 --- a/README.md +++ b/README.md @@ -1102,6 +1102,9 @@ We recognize all types of contributions. This project follows the [all-contribut Casey Conchinha
Casey Conchinha

💡 davidblitz
davidblitz

💡 + + crh82
crh82

💡 + From f73cd0d39886290f77d2c4a66398bfeef873486a Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 30 Jan 2025 02:23:42 +0000 Subject: [PATCH 039/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 4c88a1fd52..f902e50435 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6604,6 +6604,15 @@ "contributions": [ "example" ] + }, + { + "login": "crh82", + "name": "crh82", + "avatar_url": "https://avatars.githubusercontent.com/u/103348212?v=4", + "profile": "https://github.com/crh82", + "contributions": [ + "example" + ] } ], "repoType": "github", From 79264676a4838c6112106e20dd1416923908dfaf Mon Sep 17 00:00:00 2001 From: ksen0 Date: Wed, 29 Jan 2025 22:22:57 -0500 Subject: [PATCH 040/282] docs: add Aaron Welles as a contributor for example --- .all-contributorsrc | 9 +++++++++ README.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index f902e50435..daf64684d0 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6613,6 +6613,15 @@ "contributions": [ "example" ] + }, + { + "login": "", + "name": "Aaron Welles", + "avatar_url": "https://hello-assets.p5js.org/placeholder_avatar.png", + "profile": "", + "contributions": [ + "example" + ] } ], "repoType": "github", diff --git a/README.md b/README.md index 3f66c9d166..88159fdc5b 100644 --- a/README.md +++ b/README.md @@ -1104,6 +1104,7 @@ We recognize all types of contributions. This project follows the [all-contribut crh82
crh82

💡 + Aaron Welles
Aaron Welles
💡 From 1c728b56062797aa60451f268392b216b3525fa8 Mon Sep 17 00:00:00 2001 From: ksen0 Date: Thu, 30 Jan 2025 12:11:09 -0500 Subject: [PATCH 041/282] docs: add example emoji to all example contributors using emoji key --- .all-contributorsrc | 42 ++++++++++++++++++++++++++++-------------- README.md | 28 ++++++++++++++-------------- 2 files changed, 42 insertions(+), 28 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index daf64684d0..27f5458293 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1326,7 +1326,8 @@ "profile": "https://aatishb.com", "contributions": [ "doc", - "bug" + "bug", + "example" ] }, { @@ -1391,7 +1392,8 @@ "contributions": [ "bug", "code", - "doc" + "doc", + "example" ] }, { @@ -1400,7 +1402,8 @@ "avatar_url": "https://avatars2.githubusercontent.com/u/9020979?s=460&v=4", "profile": "https://github.com/hydrosquall", "contributions": [ - "doc" + "doc", + "example" ] }, { @@ -1851,7 +1854,8 @@ "avatar_url": "https://avatars1.githubusercontent.com/u/36653440?v=4", "profile": "https://github.com/sm7515", "contributions": [ - "doc" + "doc", + "example" ] }, { @@ -2174,7 +2178,8 @@ "avatar_url": "https://avatars1.githubusercontent.com/u/56646605?v=4", "profile": "https://berkeozgen.me/", "contributions": [ - "bug" + "bug", + "example" ] }, { @@ -2495,7 +2500,8 @@ "avatar_url": "https://avatars.githubusercontent.com/u/43292181?v=4", "profile": "https://github.com/suhascv", "contributions": [ - "doc" + "doc", + "example" ] }, { @@ -2555,7 +2561,8 @@ "profile": "http://www.davepagurek.com", "contributions": [ "code", - "test" + "test", + "example" ] }, { @@ -3323,7 +3330,8 @@ "profile": "https://github.com/Malayvasa", "contributions": [ "design", - "code" + "code", + "example" ] }, { @@ -3659,7 +3667,8 @@ "contributions": [ "ideas", "review", - "plugin" + "plugin", + "example" ] }, { @@ -3767,7 +3776,8 @@ "profile": "http://aceslowman.com", "contributions": [ "code", - "doc" + "doc", + "example" ] }, { @@ -3947,7 +3957,8 @@ "avatar_url": "https://avatars.githubusercontent.com/u/74553433?v=4", "profile": "https://github.com/Acha0203", "contributions": [ - "code" + "code", + "example" ] }, { @@ -4091,7 +4102,8 @@ "avatar_url": "https://avatars.githubusercontent.com/u/92529?v=4", "profile": "http://jareddonovan.com/", "contributions": [ - "code" + "code", + "example" ] }, { @@ -4460,7 +4472,8 @@ "avatar_url": "https://avatars.githubusercontent.com/u/22816171?v=4", "profile": "https://github.com/ihsavru", "contributions": [ - "code" + "code", + "example" ] }, { @@ -4523,7 +4536,8 @@ "avatar_url": "https://avatars.githubusercontent.com/u/19987520?v=4", "profile": "https://jithinks.netlify.app/", "contributions": [ - "code" + "code", + "example" ] }, { diff --git a/README.md b/README.md index 88159fdc5b..dbb11fbc2d 100644 --- a/README.md +++ b/README.md @@ -353,7 +353,7 @@ We recognize all types of contributions. This project follows the [all-contribut Caroline Hermans
Caroline Hermans

💡 📖 Faith Wuyue Yu
Faith Wuyue Yu

- Aatish Bhatia
Aatish Bhatia

📖 🐛 + Aatish Bhatia
Aatish Bhatia

📖 🐛 💡 Mislav Milicevic
Mislav Milicevic

💻 🐛 Yuting Lu
Yuting Lu

📖 Adil Rabbani
Adil Rabbani

💻 🐛 💡 @@ -361,8 +361,8 @@ We recognize all types of contributions. This project follows the [all-contribut Pierre Krafft
Pierre Krafft

🐛 💻 📖 💡 👀 ⚠️ 🔧 Zoë Ingram
Zoë Ingram

📖 - Aidan Nelson
Aidan Nelson

🐛 💻 📖 - Cameron Yick
Cameron Yick

📖 + Aidan Nelson
Aidan Nelson

🐛 💻 📖 💡 + Cameron Yick
Cameron Yick

📖 💡 Tanvi Kumar
Tanvi Kumar

🐛 💻 📖 💡 Katsuya Endoh
Katsuya Endoh

@@ -425,7 +425,7 @@ We recognize all types of contributions. This project follows the [all-contribut Samuel Alarco Cantos
Samuel Alarco Cantos

🌍 DIVYANSHU RAJ
DIVYANSHU RAJ

💻 🐛 📖 - sm7515
sm7515

📖 + sm7515
sm7515

📖 💡 Aditya Rachman Putra
Aditya Rachman Putra

📖 shaharyarshamshi
shaharyarshamshi

🌍 Ayush Jain
Ayush Jain

🌍 @@ -472,7 +472,7 @@ We recognize all types of contributions. This project follows the [all-contribut Keith Tan
Keith Tan

📖 - Berke Özgen
Berke Özgen

🐛 + Berke Özgen
Berke Özgen

🐛 💡 Musab Kılıç
Musab Kılıç

💻 ⚠️ Nicholas Marino
Nicholas Marino

📖 Greg Sadetsky
Greg Sadetsky

💻 @@ -516,7 +516,7 @@ We recognize all types of contributions. This project follows the [all-contribut Kathryn Isabelle Lawrence
Kathryn Isabelle Lawrence

💻 🤔 Joonas Jokinen
Joonas Jokinen

🎨 Ajaya Mati
Ajaya Mati

💻 - Suhas CV
Suhas CV

📖 + Suhas CV
Suhas CV

📖 💡 Sanjay Singh Rajpoot
Sanjay Singh Rajpoot

📖 @@ -524,7 +524,7 @@ We recognize all types of contributions. This project follows the [all-contribut Thomas Herlea
Thomas Herlea

🐛 💻 📖 Simranjeet Singh
Simranjeet Singh

💻 📢 🎨 👀 Rahul Mohata
Rahul Mohata

📖 - Dave Pagurek
Dave Pagurek

💻 ⚠️ + Dave Pagurek
Dave Pagurek

💻 ⚠️ 💡 Leo Kamwathi
Leo Kamwathi

💻 @@ -634,7 +634,7 @@ We recognize all types of contributions. This project follows the [all-contribut UnityOfFairfax
UnityOfFairfax

💻 INARI_DARKFOX
INARI_DARKFOX

💻 James Dunn
James Dunn

🐛 💻 - Malay Vasa
Malay Vasa

🎨 💻 + Malay Vasa
Malay Vasa

🎨 💻 💡 wagedu
wagedu

🐛 Wes Lord
Wes Lord

📖 ⚠️ @@ -681,7 +681,7 @@ We recognize all types of contributions. This project follows the [all-contribut SHIBAHARA Hiroki
SHIBAHARA Hiroki

💻 🌍 siddhant
siddhant

🐛 💻 - Caleb Foss
Caleb Foss

🤔 👀 🔌 + Caleb Foss
Caleb Foss

🤔 👀 🔌 💡 chechenxu
chechenxu

💻 Peter Marsh
Peter Marsh

💻 Ahmet Kaya
Ahmet Kaya

🌍 @@ -696,7 +696,7 @@ We recognize all types of contributions. This project follows the [all-contribut J Wong
J Wong

💻 📖 - Austin Lee Slominski
Austin Lee Slominski

💻 📖 + Austin Lee Slominski
Austin Lee Slominski

💻 📖 💡 Nick Briz
Nick Briz

👀 Ayush Shankar
Ayush Shankar

💻 zelf0
zelf0

📖 @@ -721,7 +721,7 @@ We recognize all types of contributions. This project follows the [all-contribut Aaron Casanova
Aaron Casanova

💻 Adam Smith
Adam Smith

💻 - Acha
Acha

💻 + Acha
Acha

💻 💡 Aditya Siddheshwar
Aditya Siddheshwar

💻 Adwaith D
Adwaith D

💻 æmon
æmon

💻 @@ -743,7 +743,7 @@ We recognize all types of contributions. This project follows the [all-contribut AsukaMinato
AsukaMinato

💻 - Jared Donovan
Jared Donovan

💻 + Jared Donovan
Jared Donovan

💻 💡 beau-muylle
beau-muylle

💻 Yana Agun Siswanto
Yana Agun Siswanto

💻 Benjamin Davies
Benjamin Davies

💻 @@ -796,7 +796,7 @@ We recognize all types of contributions. This project follows the [all-contribut Half Scheidl
Half Scheidl

💻 Ashris
Ashris

💻 Arijit
Arijit

💻 - Urvashi
Urvashi

💻 + Urvashi
Urvashi

💻 💡 José Miguel Tajuelo Garrigós
José Miguel Tajuelo Garrigós

💻 @@ -807,7 +807,7 @@ We recognize all types of contributions. This project follows the [all-contribut Joseph Hong
Joseph Hong

💻 - Jithin KS
Jithin KS

💻 + Jithin KS
Jithin KS

💻 💡 Jason Mandel
Jason Mandel

💻 JoeCastor
JoeCastor

💻 Juan Irache
Juan Irache

💻 From 3d1140b5bfd6055f54df0a2449789dfc73b1d693 Mon Sep 17 00:00:00 2001 From: limzykenneth Date: Thu, 30 Jan 2025 22:10:16 +0000 Subject: [PATCH 042/282] Bulk fix reference links --- .../es/contributing_to_the_p5js_reference.md | 4 ++-- contributor_docs/fes_contribution_guide.md | 12 ++++++------ .../hi/contributing_to_the_p5js_reference.md | 4 ++-- .../how-to-add-friendly-error-messages.md | 12 ++++++------ .../ja/contributing_to_the_p5.js_reference.md | 6 +++--- contributor_docs/ja/creating_libraries.md | 2 +- contributor_docs/ja/fes_reference_dev_notes.md | 12 ++++++------ .../ko/contributing_to_the_p5js_reference.md | 4 ++-- contributor_docs/ko/creating_libraries.md | 2 +- .../project_wrapups/orenshoham_gsoc_2019.md | 6 +++--- contributor_docs/project_wrapups/sanket_gsoc_2019.md | 2 +- contributor_docs/project_wrapups/wong_gsoc_2023.md | 6 +++--- .../zh-Hans/contributing_to_the_p5js_reference.md | 4 ++-- contributor_docs/zh-Hans/creating_libraries.md | 2 +- contributor_docs/zh-Hans/fes_reference_dev_notes.md | 12 ++++++------ src/core/constants.js | 4 ++-- 16 files changed, 47 insertions(+), 47 deletions(-) diff --git a/contributor_docs/es/contributing_to_the_p5js_reference.md b/contributor_docs/es/contributing_to_the_p5js_reference.md index c70557d84c..22489b7f6f 100644 --- a/contributor_docs/es/contributing_to_the_p5js_reference.md +++ b/contributor_docs/es/contributing_to_the_p5js_reference.md @@ -71,7 +71,7 @@ Cualquier cosa en un bloque de estos se interpretará como documentación de ref ## Bloque de comentarios de referencia -Desglosemos el bloque de comentarios de referencia anterior para la función `sin()` y veamos qué hace cada sección. Puedes comparar lo que vez en estos comentarios con el contenido de la página de referencia para [`sin()`](https://p5js.org/reference/#/p5/sin). +Desglosemos el bloque de comentarios de referencia anterior para la función `sin()` y veamos qué hace cada sección. Puedes comparar lo que vez en estos comentarios con el contenido de la página de referencia para [`sin()`](https://p5js.org/reference/p5/sin). ``` /** @@ -262,7 +262,7 @@ Si no quieres que el ejemplo se ejecute como parte de las pruebas automatizadas * ``` -Si tu ejemplo utiliza archivos externos como recursos, colócalos en la carpeta [/docs/yuidoc-p5-theme/assets](https://github.com/processing/p5.js/tree/main/docs/yuidoc-p5-theme/assets) (o reutiliza uno que ya esté allí) y luego enlázalos con "assets/nombrearchivo.ext" en el código. Consulta la referencia de [tint()](http://p5js.org/reference/#/p5/tint) como ejemplo. +Si tu ejemplo utiliza archivos externos como recursos, colócalos en la carpeta [/docs/yuidoc-p5-theme/assets](https://github.com/processing/p5.js/tree/main/docs/yuidoc-p5-theme/assets) (o reutiliza uno que ya esté allí) y luego enlázalos con "assets/nombrearchivo.ext" en el código. Consulta la referencia de [tint()](http://p5js.org/reference/p5/tint) como ejemplo. ### Agregar descripción a un lienzo usando `describe()` diff --git a/contributor_docs/fes_contribution_guide.md b/contributor_docs/fes_contribution_guide.md index 8796ab9102..e94bdc1371 100644 --- a/contributor_docs/fes_contribution_guide.md +++ b/contributor_docs/fes_contribution_guide.md @@ -245,7 +245,7 @@ arc(1, 1, 10.5, 10); FES will generate the following message in the console: ``` -🌸 p5.js says: [sketch.js, line 13] arc() was expecting at least 6 arguments, but received only 4. (http://p5js.org/reference/#/p5/arc) +🌸 p5.js says: [sketch.js, line 13] arc() was expecting at least 6 arguments, but received only 4. (http://p5js.org/reference/p5/arc) ``` Example of a type mismatch @@ -257,7 +257,7 @@ arc(1, ',1', 10.5, 10, 0, Math.PI); FES will generate the following message in the console: ``` -🌸 p5.js says: [sketch.js, line 14] arc() was expecting Number for the first parameter, received string instead. (http://p5js.org/reference/#/p5/arc) +🌸 p5.js says: [sketch.js, line 14] arc() was expecting Number for the first parameter, received string instead. (http://p5js.org/reference/p5/arc) ``` @@ -336,7 +336,7 @@ function preload() { FES will generate the following message in the console: ``` -🌸 p5.js says: [sketch.js, line 8] An error with message "Cannot read properties of undefined (reading 'background')" occurred inside the p5js library when "background" was called. If not stated otherwise, it might be due to "background" being called from preload. Nothing besides load calls (loadImage, loadJSON, loadFont, loadStrings, etc.) should be inside the preload function. (http://p5js.org/reference/#/p5/preload) +🌸 p5.js says: [sketch.js, line 8] An error with message "Cannot read properties of undefined (reading 'background')" occurred inside the p5js library when "background" was called. If not stated otherwise, it might be due to "background" being called from preload. Nothing besides load calls (loadImage, loadJSON, loadFont, loadStrings, etc.) should be inside the preload function. (http://p5js.org/reference/p5/preload) ``` Internal Error Example 2: @@ -351,7 +351,7 @@ function setup() { FES will generate the following message in the console: ```js -🌸 p5.js says: [sketch.js, line 12] An error with message "Cannot read properties of undefined (reading 'bind')" occurred inside the p5js library when mouseClicked was called. If not stated otherwise, it might be an issue with the arguments passed to mouseClicked. (http://p5js.org/reference/#/p5/mouseClicked) +🌸 p5.js says: [sketch.js, line 12] An error with message "Cannot read properties of undefined (reading 'bind')" occurred inside the p5js library when mouseClicked was called. If not stated otherwise, it might be an issue with the arguments passed to mouseClicked. (http://p5js.org/reference/p5/mouseClicked) ``` Example of an Error (Scope): @@ -386,7 +386,7 @@ function setup() { FES will generate the following message in the console: ``` -🌸 p5.js says: [sketch.js, line 2] It seems that you may have accidentally written "xolor" instead of "color". Please correct it to color if you wish to use the function from p5.js. (http://p5js.org/reference/#/p5/color) +🌸 p5.js says: [sketch.js, line 2] It seems that you may have accidentally written "xolor" instead of "color". Please correct it to color if you wish to use the function from p5.js. (http://p5js.org/reference/p5/color) ``` @@ -431,7 +431,7 @@ function preload() { FES will generate the following message in the console: ``` -🌸 p5.js says: It seems that you may have accidentally written preLoad instead of preload. Please correct it if it's not intentional. (http://p5js.org/reference/#/p5/preload) +🌸 p5.js says: It seems that you may have accidentally written preLoad instead of preload. Please correct it if it's not intentional. (http://p5js.org/reference/p5/preload) ``` diff --git a/contributor_docs/hi/contributing_to_the_p5js_reference.md b/contributor_docs/hi/contributing_to_the_p5js_reference.md index 3a9efa1beb..8ed3d78664 100644 --- a/contributor_docs/hi/contributing_to_the_p5js_reference.md +++ b/contributor_docs/hi/contributing_to_the_p5js_reference.md @@ -73,7 +73,7 @@ p5.js के स्रोत कोड को देखने पर, आपक ## संदर्भ टिप्पणी ब्लॉक -ऊपर दिए गए `sin()` फ़ंक्शन के लिए संदर्भ टिप्पणियों ब्लॉक को विश्लेषित करें और देखें कि प्रत्येक खंड का क्या काम है। आप यहाँ टिप्पणियों में दिखने वाली जानकारी और `sin()` के संदर्भ पृष्ठ पर जो दिखता है, उनकी तुलना कर सकते हैं। ([`sin()`](https://p5js.org/reference/#/p5/sin)) +ऊपर दिए गए `sin()` फ़ंक्शन के लिए संदर्भ टिप्पणियों ब्लॉक को विश्लेषित करें और देखें कि प्रत्येक खंड का क्या काम है। आप यहाँ टिप्पणियों में दिखने वाली जानकारी और `sin()` के संदर्भ पृष्ठ पर जो दिखता है, उनकी तुलना कर सकते हैं। ([`sin()`](https://p5js.org/reference/p5/sin)) ``` /** @@ -270,7 +270,7 @@ p5.js के स्रोत कोड को देखने पर, आपक * ``` -यदि आपका उदाहरण बाहरी संसाधन फ़ाइलों का उपयोग करता है, तो उन्हें [/docs/yuidoc-p5-theme/assets](https://github.com/processing/p5.js/tree/main/docs/yuidoc-p5-theme/assets) फ़ोल्डर में रखें (या पहले से वहां मौजूद कोई उपयोग करें) फिर उन्हें कोड में "assets/filename.ext" के साथ लिंक करें। उदाहरण के लिए [tint()](http://p5js.org/reference/#/p5/tint) संदर्भ देखें। +यदि आपका उदाहरण बाहरी संसाधन फ़ाइलों का उपयोग करता है, तो उन्हें [/docs/yuidoc-p5-theme/assets](https://github.com/processing/p5.js/tree/main/docs/yuidoc-p5-theme/assets) फ़ोल्डर में रखें (या पहले से वहां मौजूद कोई उपयोग करें) फिर उन्हें कोड में "assets/filename.ext" के साथ लिंक करें। उदाहरण के लिए [tint()](http://p5js.org/reference/p5/tint) संदर्भ देखें। ### `describe()` का उपयोग करके कैनवास का विवरण जोड़ें diff --git a/contributor_docs/how-to-add-friendly-error-messages.md b/contributor_docs/how-to-add-friendly-error-messages.md index 46976705c9..f9b3a951ee 100644 --- a/contributor_docs/how-to-add-friendly-error-messages.md +++ b/contributor_docs/how-to-add-friendly-error-messages.md @@ -122,9 +122,9 @@ circle(100, 100, 'hello'); The code above should generate the following FE messages: ``` -🌸 p5.js says: [sketch.js, line 9] circle() was expecting at least 3 arguments, but received only 1. (http://p5js.org/reference/#/p5/circle) -🌸 p5.js says: [sketch.js, line 14] circle() was expecting no more than 3 arguments, but received 4. (http://p5js.org/reference/#/p5/circle) -🌸 p5.js says: [sketch.js, line 12] circle() was expecting Number for the third parameter, received string instead. (http://p5js.org/reference/#/p5/circle) +🌸 p5.js says: [sketch.js, line 9] circle() was expecting at least 3 arguments, but received only 1. (http://p5js.org/reference/p5/circle) +🌸 p5.js says: [sketch.js, line 14] circle() was expecting no more than 3 arguments, but received 4. (http://p5js.org/reference/p5/circle) +🌸 p5.js says: [sketch.js, line 12] circle() was expecting Number for the third parameter, received string instead. (http://p5js.org/reference/p5/circle) ``` Congratulations 🎈! You are now done adding parameter validation for your new method. @@ -247,7 +247,7 @@ p5._friendlyError( This should generate the following FE messages: ``` -🌸 p5.js says: [sketch.js, line 19] An error with the message "vertex() must be used once before calling bezierVertex()" occurred inside the p5js library when bezierVertex was called. If not stated otherwise, it might be an issue with the arguments passed to bezierVertex. (http://p5js.org/reference/#/p5/bezierVertex)  +🌸 p5.js says: [sketch.js, line 19] An error with the message "vertex() must be used once before calling bezierVertex()" occurred inside the p5js library when bezierVertex was called. If not stated otherwise, it might be an issue with the arguments passed to bezierVertex. (http://p5js.org/reference/p5/bezierVertex)  ``` Congratulations 🎈! You are now done adding library error messages for your method. @@ -258,13 +258,13 @@ Congratulations 🎈! You are now done adding library error messages for your me FES message writers should prioritize lowering the barrier of understanding error messages and increasing the accessibility of the debugging process. Here is one example: ``` -🌸 p5.js says: [sketch.js, line 7] circle() was expecting at least 3 arguments, but received only 1. (http://p5js.org/reference/#/p5/circle)  +🌸 p5.js says: [sketch.js, line 7] circle() was expecting at least 3 arguments, but received only 1. (http://p5js.org/reference/p5/circle)  ``` The above parameter validation message will be shown in Korean if the browser is set to `ko-KR` (Korean) locale: ``` -🌸 p5.js says: [sketch.js, 줄7] 최소 3개의 인수(argument)를 받는 함수 circle()에 인수가 1개만 입력되었습니다. (http://p5js.org/reference/#/p5/circle)  +🌸 p5.js says: [sketch.js, 줄7] 최소 3개의 인수(argument)를 받는 함수 circle()에 인수가 1개만 입력되었습니다. (http://p5js.org/reference/p5/circle)  ``` [Friendly Errors i18n Book](https://almchung.github.io/p5-fes-i18n-book/) discusses challenges and best practices for writing Friendly Error messages within the cross-cultural i18n context. Here are the main points from the book: diff --git a/contributor_docs/ja/contributing_to_the_p5.js_reference.md b/contributor_docs/ja/contributing_to_the_p5.js_reference.md index 741c39d63c..066c221552 100644 --- a/contributor_docs/ja/contributing_to_the_p5.js_reference.md +++ b/contributor_docs/ja/contributing_to_the_p5.js_reference.md @@ -68,11 +68,11 @@ p5.jsのソースコードを見るとき、ライブラリ内の多くの行が 実際のJavaScriptコードで関数が定義されているのは、そのコメントの直後です。参考コメントは常に `/**` で始まり、`*/` で終わります。その間の各行は `*` で始まります。 -この形式のコードブロックに含まれるすべての内容は参考文献として解釈されます。あなたはおそらく [JSDoc](https://jsdoc.app/) を通じてこのスタイルのコードコメントに慣れているでしょう。p5.jsはJSDocを使用していませんが、非常に似たツールである [YUIDoc](https://yui.github.io/yuidoc/) を使用しており、参照構文も非常に似ています。このスタイルの参考コメントブロックでは、各コメントブロックがさらに個々の要素に分かれています。以下では、`sin()` 関数の参考コメントブロックを解析し、各部分の役割について見ていきます。参照ページの [`sin()`](https://p5js.org/reference/#/p5/sin) と比較することができます。 +この形式のコードブロックに含まれるすべての内容は参考文献として解釈されます。あなたはおそらく [JSDoc](https://jsdoc.app/) を通じてこのスタイルのコードコメントに慣れているでしょう。p5.jsはJSDocを使用していませんが、非常に似たツールである [YUIDoc](https://yui.github.io/yuidoc/) を使用しており、参照構文も非常に似ています。このスタイルの参考コメントブロックでは、各コメントブロックがさらに個々の要素に分かれています。以下では、`sin()` 関数の参考コメントブロックを解析し、各部分の役割について見ていきます。参照ページの [`sin()`](https://p5js.org/reference/p5/sin) と比較することができます。 ## 参考コメントブロック -上記の `sin()` 関数の参考コメントブロックを解析し、各部分の役割を見ていきましょう。このコメントを参照ページ上の [`sin()`](https://p5js.org/reference/#/p5/sin) と比較することができます。 +上記の `sin()` 関数の参考コメントブロックを解析し、各部分の役割を見ていきましょう。このコメントを参照ページ上の [`sin()`](https://p5js.org/reference/p5/sin) と比較することができます。 ``` /** @@ -270,7 +270,7 @@ p5.jsのソースコードを見るとき、ライブラリ内の多くの行が * ``` -サンプルで外部アセット ファイルを使用する場合は、それらを [/docs/yuidoc-p5-theme/assets](https://github.com/processing/p5.js/tree/main/docs/yuidoc-p5 -theme/assets) に配置してください。 フォルダー (またはそこにある既存のファイルを再利用) を作成し、「assets/filename.ext」を使用してコード内でそれらにリンクします。 参考例については、[tint()](http://p5js.org/reference/#/p5/tint) を参照してください。 +サンプルで外部アセット ファイルを使用する場合は、それらを [/docs/yuidoc-p5-theme/assets](https://github.com/processing/p5.js/tree/main/docs/yuidoc-p5 -theme/assets) に配置してください。 フォルダー (またはそこにある既存のファイルを再利用) を作成し、「assets/filename.ext」を使用してコード内でそれらにリンクします。 参考例については、[tint()](http://p5js.org/reference/p5/tint) を参照してください。 ### `describe()` を使用してキャンバスの説明を追加します diff --git a/contributor_docs/ja/creating_libraries.md b/contributor_docs/ja/creating_libraries.md index 3935fd9693..41ee9713c2 100644 --- a/contributor_docs/ja/creating_libraries.md +++ b/contributor_docs/ja/creating_libraries.md @@ -120,7 +120,7 @@ https://github.com/processing/processing/wiki/Library-Basics#library-methods * **貢献ライブラリは、作成者によってホスト、文書化、およびメンテナンスされます。** これはGitHub、個別のウェブサイト、またはその他の場所で行われる可能性があります。 -* **ドキュメントは非常に重要です!** ライブラリのドキュメントは、ダウンロードしてライブラリを使用するユーザーが簡単に見つけられる場所に配置してください。貢献ライブラリのドキュメントは、p5.jsの主要なリファレンスドキュメントには含まれませんが、類似の形式に従うことを検討してください。以下の例を参照してください:[ライブラリ概要ページ](http://p5js.org/reference/#/libraries/p5.sound)、[クラス概要ページ](http://p5js.org/reference/#/p5.Vector)、[メソッドページ](http://p5js.org/reference/#/p5/arc)。 +* **ドキュメントは非常に重要です!** ライブラリのドキュメントは、ダウンロードしてライブラリを使用するユーザーが簡単に見つけられる場所に配置してください。貢献ライブラリのドキュメントは、p5.jsの主要なリファレンスドキュメントには含まれませんが、類似の形式に従うことを検討してください。以下の例を参照してください:[ライブラリ概要ページ](http://p5js.org/reference/libraries/p5.sound)、[クラス概要ページ](http://p5js.org/reference/p5.Vector)、[メソッドページ](http://p5js.org/reference/p5/arc)。 * **例も素晴らしいです!** それらは人々にあなたのライブラリが何ができるかを示します。これはすべてJavaScriptなので、ダウンロードする前にオンラインで実行することができます。[jsfiddle](http://jsfiddle.net/)と[codepen](http://codepen.io)は、例をホストするための2つの良いシンプルなオプションです。 diff --git a/contributor_docs/ja/fes_reference_dev_notes.md b/contributor_docs/ja/fes_reference_dev_notes.md index 8b77378e1f..c0493abfd6 100644 --- a/contributor_docs/ja/fes_reference_dev_notes.md +++ b/contributor_docs/ja/fes_reference_dev_notes.md @@ -222,7 +222,7 @@ FESはコンソールに以下のメッセージを生成します: arc('1', 1, 10.5, 10, 0, Math.PI, 'pie'); ``` FESはコンソールに以下のメッセージを生成します: -> 🌸 p5.jsが言うには、arc()はパラメータ#0(ゼロベースのインデックス)でNumberを期待していましたが、文字列を受け取りました。[http://p5js.org/reference/#/p5/arc] +> 🌸 p5.jsが言うには、arc()はパラメータ#0(ゼロベースのインデックス)でNumberを期待していましたが、文字列を受け取りました。[http://p5js.org/reference/p5/arc] ##### 位置 core/friendly_errors/validate_params.js @@ -276,7 +276,7 @@ function preload() { } ``` FES将在控制台中生成以下消息: -> 🌸 p5.jsが言うには、backgroundを呼び出したとき(sketch.jsの4行目[http://localhost:8000/lib/empty-example/sketch.js:4:3])、p5jsライブラリ内部でエラーが発生しました。エラーメッセージは「未定義のプロパティ'background'を読み取れません」です。(特に説明がない限り、これはpreloadからbackgroundが呼び出されたためかもしれません。preload関数内にはload関数(loadImage、loadJSON、loadFont、loadStringsなど)以外は含まれていないべきです。)(http://p5js.org/reference/#/p5/preload) +> 🌸 p5.jsが言うには、backgroundを呼び出したとき(sketch.jsの4行目[http://localhost:8000/lib/empty-example/sketch.js:4:3])、p5jsライブラリ内部でエラーが発生しました。エラーメッセージは「未定義のプロパティ'background'を読み取れません」です。(特に説明がない限り、これはpreloadからbackgroundが呼び出されたためかもしれません。preload関数内にはload関数(loadImage、loadJSON、loadFont、loadStringsなど)以外は含まれていないべきです。)(http://p5js.org/reference/p5/preload) 内部エラーの例 2 ```javascript @@ -286,7 +286,7 @@ function setup() { } ``` FES将在控制台中生成以下消息: -> 🌸 p5.jsが言うには、mouseClickedを呼び出したとき(sketch.jsの3行目[http://localhost:8000/lib/empty-example/sketch.js:3:7])、p5jsライブラリ内部でエラーが発生しました。エラーメッセージは「未定義のプロパティ'bind'を読み取れません」です。(特に説明がない限り、これはmouseClickedへの引数に問題がある可能性があります。)(http://p5js.org/reference/#/p5/mouseClicked) +> 🌸 p5.jsが言うには、mouseClickedを呼び出したとき(sketch.jsの3行目[http://localhost:8000/lib/empty-example/sketch.js:3:7])、p5jsライブラリ内部でエラーが発生しました。エラーメッセージは「未定義のプロパティ'bind'を読み取れません」です。(特に説明がない限り、これはmouseClickedへの引数に問題がある可能性があります。)(http://p5js.org/reference/p5/mouseClicked) ユーザー例のスコープエラーの例 ```javascript @@ -306,7 +306,7 @@ function setup() { } ``` FESはコンソールに以下のメッセージを生成します: -> 🌸 p5.jsが言うには、「colour」を誤って「color」と書いてしまった可能性があります(sketch.jsの2行目[http://localhost:8000/lib/empty-example/sketch.js:2:3])。p5.jsの関数を使用する場合は、それをcolorに修正してください(http://p5js.org/reference/#/p5/color)。 +> 🌸 p5.jsが言うには、「colour」を誤って「color」と書いてしまった可能性があります(sketch.jsの2行目[http://localhost:8000/lib/empty-example/sketch.js:2:3])。p5.jsの関数を使用する場合は、それをcolorに修正してください(http://p5js.org/reference/p5/color)。 ##### 位置 core/friendly_errors/fes_core.js @@ -334,7 +334,7 @@ function setup() { } ``` FESはコンソールに以下のメッセージを生成します: -> 🌸 p5.jsのヒント:p5.jsの予約された変数「PI」を使用しています。変数名を他の名前に変更してください。(https://p5js.org/reference/#/p5/PI) +> 🌸 p5.jsのヒント:p5.jsの予約された変数「PI」を使用しています。変数名を他の名前に変更してください。(https://p5js.org/reference/p5/PI) p5.j​​sの予約関数の再定義例 ```javascript @@ -372,7 +372,7 @@ function preLoad() { } ``` FESはコンソールに以下のメッセージを生成します: -> 🌸 p5.jsのヒント:preLoadと書くべきところをpreloadと誤って書いているようです。これが意図していない場合は、訂正してください。(http://p5js.org/reference/#/p5/preload) +> 🌸 p5.jsのヒント:preLoadと書くべきところをpreloadと誤って書いているようです。これが意図していない場合は、訂正してください。(http://p5js.org/reference/p5/preload) ##### 位置 core/friendly_errors/fes_core.js diff --git a/contributor_docs/ko/contributing_to_the_p5js_reference.md b/contributor_docs/ko/contributing_to_the_p5js_reference.md index 139492a247..9fe526d86d 100644 --- a/contributor_docs/ko/contributing_to_the_p5js_reference.md +++ b/contributor_docs/ko/contributing_to_the_p5js_reference.md @@ -71,7 +71,7 @@ p5.js 소스 코드를 보면 많은 라인이 레퍼런스 주석으로 작성 ## 레퍼런스 주석 블록 -앞서 보았던 `sin()` 함수의 레퍼런스 주석 블록을 조금 더 자세히 살펴보고, 각 섹션이 어떤 역할을 하는지 알아봅시다. 주석으로 작성한 내용이 실제 [`sin()`](https://p5js.org/reference/#/p5/sin) 레퍼런스 페이지에서는 어떻게 보여지는지 비교해보세요. +앞서 보았던 `sin()` 함수의 레퍼런스 주석 블록을 조금 더 자세히 살펴보고, 각 섹션이 어떤 역할을 하는지 알아봅시다. 주석으로 작성한 내용이 실제 [`sin()`](https://p5js.org/reference/p5/sin) 레퍼런스 페이지에서는 어떻게 보여지는지 비교해보세요. ``` /** @@ -262,7 +262,7 @@ p5.js 소스 코드를 보면 많은 라인이 레퍼런스 주석으로 작성 * ``` -만약, 예제 코드가 외부 애셋 파일을 사용해야 한다면, 필요한 파일들을 [/docs/yuidoc-p5-theme/assets](https://github.com/processing/p5.js/tree/main/docs/yuidoc-p5-theme/assets) 폴더에 넣어두세요(이미 해당 폴더에 존재하는 파일을 재사용해도 됩니다). 그리고 코드에서 "assets/filename.ext" 경로로 파일을 불러와 사용하면 됩니다. [tint()](http://p5js.org/reference/#/p5/tint) 레퍼런스를 참고하세요. +만약, 예제 코드가 외부 애셋 파일을 사용해야 한다면, 필요한 파일들을 [/docs/yuidoc-p5-theme/assets](https://github.com/processing/p5.js/tree/main/docs/yuidoc-p5-theme/assets) 폴더에 넣어두세요(이미 해당 폴더에 존재하는 파일을 재사용해도 됩니다). 그리고 코드에서 "assets/filename.ext" 경로로 파일을 불러와 사용하면 됩니다. [tint()](http://p5js.org/reference/p5/tint) 레퍼런스를 참고하세요. ### `describe()`로 캔버스 설명 추가하기 diff --git a/contributor_docs/ko/creating_libraries.md b/contributor_docs/ko/creating_libraries.md index b9229f7767..edda2ccb7b 100644 --- a/contributor_docs/ko/creating_libraries.md +++ b/contributor_docs/ko/creating_libraries.md @@ -124,7 +124,7 @@ https://GitHub.com/processing/processing/wiki/Library-Basics#library-methods * **기여된 라이브러리는 제작자가 호스팅, 문서화 및 유지 관리합니다.** 라이브러리들은 GitHub, 별도의 웹 사이트 또는 어딘가에 있을 수 있습니다. -* **문서가 핵심입니다!** 라이브러리 문서는 사용자가 쉽게 찾아보고 다운로드 하여 사용할 수 있는 곳에 있어야 합니다. 기여된 라이브러리에 대한 문서는 기본 p5.js 레퍼런스에 포함되지 않지만 여러분이 유사한 형식을 따르고 싶을 수도 있습니다. [라이브러리 개요 페이지](http://p5js.org/reference/#/libraries/p5.sound), [클래스 개요 페이지](http://p5js.org/reference/#/p5.Vector) 및 [메소드 페이지](http://p5js.org/reference/#/p5/arc) 의 예제를 참조하세요. +* **문서가 핵심입니다!** 라이브러리 문서는 사용자가 쉽게 찾아보고 다운로드 하여 사용할 수 있는 곳에 있어야 합니다. 기여된 라이브러리에 대한 문서는 기본 p5.js 레퍼런스에 포함되지 않지만 여러분이 유사한 형식을 따르고 싶을 수도 있습니다. [라이브러리 개요 페이지](http://p5js.org/reference/libraries/p5.sound), [클래스 개요 페이지](http://p5js.org/reference/p5.Vector) 및 [메소드 페이지](http://p5js.org/reference/p5/arc) 의 예제를 참조하세요. * **예제가 좋습니다!** 사람들에게 라이브러리가 할 수 있는 일을 보여주세요. 모두 자바스크립트이므로 사람들은 라이브러리를 다운로드하기 전 온라인에서 실행 되는 것을 볼 수 있습니다. 예제들을 호스팅하기 쉬운 [jsfiddle](http://jsfiddle.net/) 및 [codepen](http://codepen.io)이라는 두가지 좋은 옵션이 있습니다. diff --git a/contributor_docs/project_wrapups/orenshoham_gsoc_2019.md b/contributor_docs/project_wrapups/orenshoham_gsoc_2019.md index c9332e44a2..a5008a83d5 100644 --- a/contributor_docs/project_wrapups/orenshoham_gsoc_2019.md +++ b/contributor_docs/project_wrapups/orenshoham_gsoc_2019.md @@ -8,9 +8,9 @@ The AudioWorklet API consists of two classes: [AudioWorkletProcessor](https://de AudioWorklet replaces [ScriptProcessorNode](https://developer.mozilla.org/en-US/docs/Web/API/ScriptProcessorNode), a now-deprecated Web Audio node that runs audio code in the browser's main thread. p5.js-sound used ScriptProcessorNode internally in three classes: -- [p5.SoundFile](https://p5js.org/reference/#/p5.SoundFile), which used a ScriptProcessorNode to keep track of a SoundFile's current playback position. -- [p5.Amplitude](https://p5js.org/reference/#/p5.Amplitude), which used a ScriptProcessorNode to perform amplitude analysis. -- [p5.SoundRecorder](https://p5js.org/reference/#/p5.SoundRecorder), which used a ScriptProcessorNode to concatenate audio buffers together during the recording process. +- [p5.SoundFile](https://p5js.org/reference/p5.SoundFile), which used a ScriptProcessorNode to keep track of a SoundFile's current playback position. +- [p5.Amplitude](https://p5js.org/reference/p5.Amplitude), which used a ScriptProcessorNode to perform amplitude analysis. +- [p5.SoundRecorder](https://p5js.org/reference/p5.SoundRecorder), which used a ScriptProcessorNode to concatenate audio buffers together during the recording process. For each of these classes, I created new AudioWorkletProcessors for [p5.SoundFile](https://github.com/processing/p5.js-sound/blob/4d3a3833de4d30f6770740052a82586444a4482a/src/audioWorklet/soundFileProcessor.js), [p5.Amplitude](https://github.com/processing/p5.js-sound/blob/4d3a3833de4d30f6770740052a82586444a4482a/src/audioWorklet/amplitudeProcessor.js), and [p5.SoundRecorder](https://github.com/processing/p5.js-sound/blob/4d3a3833de4d30f6770740052a82586444a4482a/src/audioWorklet/recorderProcessor.js) that replicated the corresponding ScriptProcessorNode's [onaudioprocess](https://developer.mozilla.org/en-US/docs/Web/API/ScriptProcessorNode/onaudioprocess) function. diff --git a/contributor_docs/project_wrapups/sanket_gsoc_2019.md b/contributor_docs/project_wrapups/sanket_gsoc_2019.md index 5dab51a5b9..f90e435b76 100644 --- a/contributor_docs/project_wrapups/sanket_gsoc_2019.md +++ b/contributor_docs/project_wrapups/sanket_gsoc_2019.md @@ -18,7 +18,7 @@ Apart from implementing these functions, I also added unit tests, manual tests, Before and during the Summer of Code, I fixed minor bugs unrelated to my project, which helped me immensely to understand and get around the codebase and the workflow of p5.js. They are listed [here](https://github.com/processing/p5.js/pulls?utf8=%E2%9C%93&q=is%3Apr+author%3Asanketsingh24). -### [lightFalloff()](https://p5js.org/reference/#/p5/lightFalloff) +### [lightFalloff()](https://p5js.org/reference/p5/lightFalloff) This function allows the user to set the attenuation values, which are used in shaders to restrict the spread of light. Earlier, this was a constant value. Now, the artists can use this function to set the value themselves. Implementing this function required me to add three new uniforms, as well as modifying the light shader and light.js. The default was set to 1. ### [emissiveMaterial()](https://github.com/processing/p5.js/pull/3820) diff --git a/contributor_docs/project_wrapups/wong_gsoc_2023.md b/contributor_docs/project_wrapups/wong_gsoc_2023.md index 248e27b5c0..def485d24a 100644 --- a/contributor_docs/project_wrapups/wong_gsoc_2023.md +++ b/contributor_docs/project_wrapups/wong_gsoc_2023.md @@ -31,9 +31,9 @@ Many thanks to my mentors for all their support: Adam Ferriss, Austin Slominski, - [Third pull request](https://github.com/processing/p5.js/pull/6324), replacing the old filters with new shader filters. Status: merged ### Public documentation pages: -- [WEBGL](https://p5js.org/reference/#/p5/WEBGL) - Status: merged, page created -- [filter()](https://p5js.org/reference/#/p5/filter) - Status: merged, page not updated yet -- [createFilterShader()](https://p5js.org/reference/#/p5/createFilterShader) - Status: merged, page not created yet +- [WEBGL](https://p5js.org/reference/p5/WEBGL) - Status: merged, page created +- [filter()](https://p5js.org/reference/p5/filter) - Status: merged, page not updated yet +- [createFilterShader()](https://p5js.org/reference/p5/createFilterShader) - Status: merged, page not created yet ### Performance measuring helpers: diff --git a/contributor_docs/zh-Hans/contributing_to_the_p5js_reference.md b/contributor_docs/zh-Hans/contributing_to_the_p5js_reference.md index 73933f0d75..242efe1d33 100644 --- a/contributor_docs/zh-Hans/contributing_to_the_p5js_reference.md +++ b/contributor_docs/zh-Hans/contributing_to_the_p5js_reference.md @@ -72,7 +72,7 @@ ## 参考注释块 -让我们解析上面 `sin()` 函数的参考注释块,并查看每个部分的作用。你可以将此处的注释与参考页面上的[`sin()`](https://p5js.org/reference/#/p5/sin)进行比较。 +让我们解析上面 `sin()` 函数的参考注释块,并查看每个部分的作用。你可以将此处的注释与参考页面上的[`sin()`](https://p5js.org/reference/p5/sin)进行比较。 ``` /** @@ -269,7 +269,7 @@ * ``` -如果你的示例使用外部素材文件,请将它们放入 [/docs/yuidoc-p5-theme/assets](https://github.com/processing/p5.js/tree/main/docs/yuidoc-p5-theme/assets) 文件夹中(或者重用其中已有的文件),然后在代码中使用 "assets/filename.ext" 链接到它们。请参阅 [tint()](http://p5js.org/reference/#/p5/tint) 参考示例。 +如果你的示例使用外部素材文件,请将它们放入 [/docs/yuidoc-p5-theme/assets](https://github.com/processing/p5.js/tree/main/docs/yuidoc-p5-theme/assets) 文件夹中(或者重用其中已有的文件),然后在代码中使用 "assets/filename.ext" 链接到它们。请参阅 [tint()](http://p5js.org/reference/p5/tint) 参考示例。 ### 使用 `describe()` 添加画布描述 diff --git a/contributor_docs/zh-Hans/creating_libraries.md b/contributor_docs/zh-Hans/creating_libraries.md index 173eb7a176..3e8ea1bcf3 100644 --- a/contributor_docs/zh-Hans/creating_libraries.md +++ b/contributor_docs/zh-Hans/creating_libraries.md @@ -118,7 +118,7 @@ https://github.com/processing/processing/wiki/Library-Basics#library-methods * **贡献的库由创建者托管、文档化和维护。** 这可以在GitHub、一个单独的网站或其他地方进行。 -* **文档至关重要!** 您的库的文档应该放在某个易于找到的位置,供下载和使用您的库的用户使用。贡献的库的文档将不会包含在主要的p5.js参考文档中,但您可能希望遵循类似的格式。请参阅这些示例:[库概述页面](http://p5js.org/reference/#/libraries/p5.sound)、[类概述页面](http://p5js.org/reference/#/p5.Vector)和[方法页面](http://p5js.org/reference/#/p5/arc)。 +* **文档至关重要!** 您的库的文档应该放在某个易于找到的位置,供下载和使用您的库的用户使用。贡献的库的文档将不会包含在主要的p5.js参考文档中,但您可能希望遵循类似的格式。请参阅这些示例:[库概述页面](http://p5js.org/reference/libraries/p5.sound)、[类概述页面](http://p5js.org/reference/p5.Vector)和[方法页面](http://p5js.org/reference/p5/arc)。 * **示例也很棒!** 它们向人们展示了您的库能做什么。由于这全部是JavaScript,人们可以在下载之前在线运行它们。[jsfiddle](http://jsfiddle.net/)和[codepen](http://codepen.io)是两个很好的简单选项,可以用来托管示例。 diff --git a/contributor_docs/zh-Hans/fes_reference_dev_notes.md b/contributor_docs/zh-Hans/fes_reference_dev_notes.md index 5ec46036b9..ea3c77130b 100644 --- a/contributor_docs/zh-Hans/fes_reference_dev_notes.md +++ b/contributor_docs/zh-Hans/fes_reference_dev_notes.md @@ -218,7 +218,7 @@ FES将在控制台生成以下消息: arc('1', 1, 10.5, 10, 0, Math.PI, 'pie'); ``` FES将在控制台生成以下消息: -> 🌸 p5.js 说:arc()在参数#0(从零开始的索引)处期望接收Number,但收到了字符串。[http://p5js.org/reference/#/p5/arc] +> 🌸 p5.js 说:arc()在参数#0(从零开始的索引)处期望接收Number,但收到了字符串。[http://p5js.org/reference/p5/arc] ##### 位置 core/friendly_errors/validate_params.js @@ -272,7 +272,7 @@ function preload() { } ``` FES将在控制台中生成以下消息: -> 🌸 p5.js说:当调用background时(位于sketch.js的第4行[http://localhost:8000/lib/empty-example/sketch.js:4:3]),在p5js库内部发生了一个错误,错误消息为“无法读取未定义的属性'background'”。(如果没有另外说明,这可能是由于从preload中调用了background。preload函数中除了load函数(loadImage、loadJSON、loadFont、loadStrings等)之外不应该有其他内容。)(http://p5js.org/reference/#/p5/preload) +> 🌸 p5.js说:当调用background时(位于sketch.js的第4行[http://localhost:8000/lib/empty-example/sketch.js:4:3]),在p5js库内部发生了一个错误,错误消息为“无法读取未定义的属性'background'”。(如果没有另外说明,这可能是由于从preload中调用了background。preload函数中除了load函数(loadImage、loadJSON、loadFont、loadStrings等)之外不应该有其他内容。)(http://p5js.org/reference/p5/preload) 内部错误示例 2 ```javascript @@ -282,7 +282,7 @@ function setup() { } ``` FES将在控制台中生成以下消息: -> 🌸 p5.js说:当调用mouseClicked时(位于sketch.js的第3行[http://localhost:8000/lib/empty-example/sketch.js:3:7]),在p5js库内部发生了一个错误,错误消息为“无法读取未定义的属性'bind'”。(如果没有另外说明,这可能是由于传递给mouseClicked的参数存在问题。)(http://p5js.org/reference/#/p5/mouseClicked) +> 🌸 p5.js说:当调用mouseClicked时(位于sketch.js的第3行[http://localhost:8000/lib/empty-example/sketch.js:3:7]),在p5js库内部发生了一个错误,错误消息为“无法读取未定义的属性'bind'”。(如果没有另外说明,这可能是由于传递给mouseClicked的参数存在问题。)(http://p5js.org/reference/p5/mouseClicked) 用户示例中的作用域错误示例 ```javascript @@ -303,7 +303,7 @@ function setup() { } ``` FES将在控制台中生成以下消息: -> 🌸 p5.js说:您可能错误地将“colour”写成了“color”(位于sketch.js的第2行[http://localhost:8000/lib/empty-example/sketch.js:2:3])。如果希望使用p5.js中的函数,请将其更正为color(http://p5js.org/reference/#/p5/color)。 +> 🌸 p5.js说:您可能错误地将“colour”写成了“color”(位于sketch.js的第2行[http://localhost:8000/lib/empty-example/sketch.js:2:3])。如果希望使用p5.js中的函数,请将其更正为color(http://p5js.org/reference/p5/color)。 ##### 位置 core/friendly_errors/fes_core.js @@ -331,7 +331,7 @@ function setup() { } ``` FES 将在控制台生成以下消息: -> 🌸 p5.js 提示:您使用了 p5.js 的保留变量 "PI",请确保将变量名更改为其他名称。(https://p5js.org/reference/#/p5/PI) +> 🌸 p5.js 提示:您使用了 p5.js 的保留变量 "PI",请确保将变量名更改为其他名称。(https://p5js.org/reference/p5/PI) 重新定义 p5.js 保留函数的示例 ```javascript @@ -369,7 +369,7 @@ function preLoad() { } ``` FES 将在控制台生成以下消息: -> 🌸 p5.js 提示:似乎您可能误写了 preLoad,应该是 preload。如果这不是您的意图,请进行更正。(http://p5js.org/reference/#/p5/preload) +> 🌸 p5.js 提示:似乎您可能误写了 preLoad,应该是 preload。如果这不是您的意图,请进行更正。(http://p5js.org/reference/p5/preload) ##### 位置 core/friendly_errors/fes_core.js diff --git a/src/core/constants.js b/src/core/constants.js index bf28b50164..ece1333037 100644 --- a/src/core/constants.js +++ b/src/core/constants.js @@ -24,7 +24,7 @@ export const P2D = 'p2d'; /** * One of the two render modes in p5.js, used for computationally intensive tasks like 3D rendering and shaders. * - * `WEBGL` differs from the default `P2D` renderer in the following ways: + * `WEBGL` differs from the default `P2D` renderer in the following ways: * * - **Coordinate System** - When drawing in `WEBGL` mode, the origin point (0,0,0) is located at the center of the screen, not the top-left corner. See the tutorial page about coordinates and transformations. * - **3D Shapes** - `WEBGL` mode can be used to draw 3-dimensional shapes like box(), sphere(), cone(), and more. See the tutorial page about custom geometry to make more complex objects. @@ -810,7 +810,7 @@ export const HSL = 'hsl'; /** * AUTO allows us to automatically set the width or height of an element (but not both), * based on the current height and width of the element. Only one parameter can - * be passed to the size function as AUTO, at a time. + * be passed to the size function as AUTO, at a time. * * @property {String} AUTO * @final From c2b770374301b127c1c7a088533348ce7426ec07 Mon Sep 17 00:00:00 2001 From: limzykenneth Date: Fri, 31 Jan 2025 18:05:48 +0000 Subject: [PATCH 043/282] Bulk fix links --- .../es/contributing_to_the_p5js_reference.md | 4 ++-- contributor_docs/fes_contribution_guide.md | 12 ++++++------ contributor_docs/hi/README.md | 4 ++-- .../hi/contributing_to_the_p5js_reference.md | 4 ++-- .../how-to-add-friendly-error-messages.md | 12 ++++++------ contributor_docs/ja/README.md | 4 ++-- .../ja/contributing_to_the_p5.js_reference.md | 4 ++-- contributor_docs/ja/creating_libraries.md | 4 ++-- contributor_docs/ja/fes_reference_dev_notes.md | 14 +++++++------- contributor_docs/ko/README.md | 4 ++-- .../ko/contributing_to_the_p5js_reference.md | 4 ++-- contributor_docs/ko/creating_libraries.md | 4 ++-- contributor_docs/ko/friendly_error_system.md | 6 +++--- contributor_docs/pt-br/README.md | 2 +- contributor_docs/sk/README.md | 4 ++-- contributor_docs/zh-Hans/README.md | 4 ++-- .../zh-Hans/contributing_to_the_p5js_reference.md | 4 ++-- contributor_docs/zh-Hans/creating_libraries.md | 4 ++-- .../zh-Hans/fes_reference_dev_notes.md | 14 +++++++------- src/core/environment.js | 2 +- src/core/friendly_errors/fes_core.js | 4 ++-- src/dom/dom.js | 4 ++-- src/io/files.js | 2 +- 23 files changed, 62 insertions(+), 62 deletions(-) diff --git a/contributor_docs/es/contributing_to_the_p5js_reference.md b/contributor_docs/es/contributing_to_the_p5js_reference.md index 22489b7f6f..714cc4cc4c 100644 --- a/contributor_docs/es/contributing_to_the_p5js_reference.md +++ b/contributor_docs/es/contributing_to_the_p5js_reference.md @@ -138,7 +138,7 @@ Si el método devuelve el objeto de la superclase, puedes omitir la etiqueta `@r ## Firmas adicionales -Si una función tiene múltiples opciones de parámetros posibles, puedes especificar cada una individualmente. Por ejemplo, la función [`background()`](http://p5js.org/reference/#p5/background) toma una serie de opciones de parámetros diferentes (ver la sección "Sintaxis" en la página de referencia). Elige una versión para incluirla como la primera firma usando la plantilla anterior. Al final del primer bloque de comentarios de referencia puedes agregar firmas adicionales, cada una en su propio bloque, como en el siguiente ejemplo. +Si una función tiene múltiples opciones de parámetros posibles, puedes especificar cada una individualmente. Por ejemplo, la función [`background()`](https://p5js.org/reference/#p5/background) toma una serie de opciones de parámetros diferentes (ver la sección "Sintaxis" en la página de referencia). Elige una versión para incluirla como la primera firma usando la plantilla anterior. Al final del primer bloque de comentarios de referencia puedes agregar firmas adicionales, cada una en su propio bloque, como en el siguiente ejemplo. ``` /** @@ -262,7 +262,7 @@ Si no quieres que el ejemplo se ejecute como parte de las pruebas automatizadas * ``` -Si tu ejemplo utiliza archivos externos como recursos, colócalos en la carpeta [/docs/yuidoc-p5-theme/assets](https://github.com/processing/p5.js/tree/main/docs/yuidoc-p5-theme/assets) (o reutiliza uno que ya esté allí) y luego enlázalos con "assets/nombrearchivo.ext" en el código. Consulta la referencia de [tint()](http://p5js.org/reference/p5/tint) como ejemplo. +Si tu ejemplo utiliza archivos externos como recursos, colócalos en la carpeta [/docs/yuidoc-p5-theme/assets](https://github.com/processing/p5.js/tree/main/docs/yuidoc-p5-theme/assets) (o reutiliza uno que ya esté allí) y luego enlázalos con "assets/nombrearchivo.ext" en el código. Consulta la referencia de [tint()](https://p5js.org/reference/p5/tint) como ejemplo. ### Agregar descripción a un lienzo usando `describe()` diff --git a/contributor_docs/fes_contribution_guide.md b/contributor_docs/fes_contribution_guide.md index e94bdc1371..99911707e1 100644 --- a/contributor_docs/fes_contribution_guide.md +++ b/contributor_docs/fes_contribution_guide.md @@ -245,7 +245,7 @@ arc(1, 1, 10.5, 10); FES will generate the following message in the console: ``` -🌸 p5.js says: [sketch.js, line 13] arc() was expecting at least 6 arguments, but received only 4. (http://p5js.org/reference/p5/arc) +🌸 p5.js says: [sketch.js, line 13] arc() was expecting at least 6 arguments, but received only 4. (https://p5js.org/reference/p5/arc) ``` Example of a type mismatch @@ -257,7 +257,7 @@ arc(1, ',1', 10.5, 10, 0, Math.PI); FES will generate the following message in the console: ``` -🌸 p5.js says: [sketch.js, line 14] arc() was expecting Number for the first parameter, received string instead. (http://p5js.org/reference/p5/arc) +🌸 p5.js says: [sketch.js, line 14] arc() was expecting Number for the first parameter, received string instead. (https://p5js.org/reference/p5/arc) ``` @@ -336,7 +336,7 @@ function preload() { FES will generate the following message in the console: ``` -🌸 p5.js says: [sketch.js, line 8] An error with message "Cannot read properties of undefined (reading 'background')" occurred inside the p5js library when "background" was called. If not stated otherwise, it might be due to "background" being called from preload. Nothing besides load calls (loadImage, loadJSON, loadFont, loadStrings, etc.) should be inside the preload function. (http://p5js.org/reference/p5/preload) +🌸 p5.js says: [sketch.js, line 8] An error with message "Cannot read properties of undefined (reading 'background')" occurred inside the p5js library when "background" was called. If not stated otherwise, it might be due to "background" being called from preload. Nothing besides load calls (loadImage, loadJSON, loadFont, loadStrings, etc.) should be inside the preload function. (https://p5js.org/reference/p5/preload) ``` Internal Error Example 2: @@ -351,7 +351,7 @@ function setup() { FES will generate the following message in the console: ```js -🌸 p5.js says: [sketch.js, line 12] An error with message "Cannot read properties of undefined (reading 'bind')" occurred inside the p5js library when mouseClicked was called. If not stated otherwise, it might be an issue with the arguments passed to mouseClicked. (http://p5js.org/reference/p5/mouseClicked) +🌸 p5.js says: [sketch.js, line 12] An error with message "Cannot read properties of undefined (reading 'bind')" occurred inside the p5js library when mouseClicked was called. If not stated otherwise, it might be an issue with the arguments passed to mouseClicked. (https://p5js.org/reference/p5/mouseClicked) ``` Example of an Error (Scope): @@ -386,7 +386,7 @@ function setup() { FES will generate the following message in the console: ``` -🌸 p5.js says: [sketch.js, line 2] It seems that you may have accidentally written "xolor" instead of "color". Please correct it to color if you wish to use the function from p5.js. (http://p5js.org/reference/p5/color) +🌸 p5.js says: [sketch.js, line 2] It seems that you may have accidentally written "xolor" instead of "color". Please correct it to color if you wish to use the function from p5.js. (https://p5js.org/reference/p5/color) ``` @@ -431,7 +431,7 @@ function preload() { FES will generate the following message in the console: ``` -🌸 p5.js says: It seems that you may have accidentally written preLoad instead of preload. Please correct it if it's not intentional. (http://p5js.org/reference/p5/preload) +🌸 p5.js says: It seems that you may have accidentally written preLoad instead of preload. Please correct it if it's not intentional. (https://p5js.org/reference/p5/preload) ``` diff --git a/contributor_docs/hi/README.md b/contributor_docs/hi/README.md index ff65b5214c..d6a109063f 100644 --- a/contributor_docs/hi/README.md +++ b/contributor_docs/hi/README.md @@ -13,7 +13,7 @@ p5.js में योगदान देने में आपकी रुच व्यापक p5.js परियोजना में इस के अलावा कुछ रिपॉजिटरी शामिल हैं- - [p5.js](https://github.com/processing/p5.js): इस रिपॉजिटरी में p5.js लाइब्रेरी का स्रोत कोड है। [p5.js संदर्भ मैनुअल](https://p5js.org/reference/) भी इस स्रोत कोड में शामिल [JSDoc](http://usejsdoc.org/) टिप्पणियों से उत्पन्न होता है। इसका अनुरक्षण [Moira Turner](https://github.com/mcturner1995) के द्वारा किया जा रहा है। -- [p5.js-website](https://github.com/processing/p5.js-website) इस रिपॉजिटरी में [p5.js वेबसाइट](http://p5js.org) का अधिकांश कोड हैं, संदर्भ मैनुअल के अपवाद के साथ। इसका अनुरक्षण [Moira Turner](https://github.com/mcturner1995) के द्वारा किया जा रहा है। +- [p5.js-website](https://github.com/processing/p5.js-website) इस रिपॉजिटरी में [p5.js वेबसाइट](https://p5js.org) का अधिकांश कोड हैं, संदर्भ मैनुअल के अपवाद के साथ। इसका अनुरक्षण [Moira Turner](https://github.com/mcturner1995) के द्वारा किया जा रहा है। - [p5.js-sound](https://github.com/processing/p5.js-sound) इस भंडार में p5.sound.js लाइब्रेरी है। इसका अनुरक्षण [Jason Sigal](https://github.com/therewasaguy) के द्वारा किया जा रहा है। - [p5.js-web-editor](https://github.com/processing/p5.js-web-editor) इस रिपॉजिटरी में [p5.js वेब एडिटर](https://editor.p5js.org) के लिए स्रोत कोड है। इसका अनुरक्षण [Cassie Tarakajian](https://github.com/catarak) के द्वारा किया जा रहा है। ध्यान दें कि पुराना [p5.js संपादक](https://github.com/processing/p5.js-editor) अब पदावनत हो गया है। @@ -34,7 +34,7 @@ p5.js में योगदान देने में आपकी रुच हमें एहसास है कि प्रलेखन इस परियोजना का सबसे महत्वपूर्ण हिस्सा है। खराब प्रलेखन नए उपयोगकर्ताओं और योगदानकर्ताओं के लिए उपयोग करने के लिए मुख्य बाधाओं में से एक है, जिससे परियोजना कम समावेशी हो जाती है। [contributing_documentation.md](./contributing_documentation.md) पृष्ठ प्रलेखन के साथ आरंभ करने का एक गहन अवलोकन देता है। p5.js के लिए प्रलेखन कुछ मुख्य स्थानों में पाया जा सकता है: - [p5js.org संदर्भ](https://p5js.org/reference/) स्रोत कोड में ही [इनलाइन प्रलेखन](./inline_documentation.md) से उत्पन्न होता है। इसमें पाठ विवरण और पैरामीटर के साथ-साथ कोड स्निपेट उदाहरण भी शामिल हैं। हम कोड और प्रलेखन को निकटता से रखने के लिए यह सब इनलाइन रखते हैं, और इस विचार को सुदृढ़ करने के लिए कि कोड में योगदान देने की तुलना में प्रलेखन में योगदान करना अधिक महत्वपूर्ण है (यदि अधिक नहीं)। जब लाइब्रेरी निर्मित हो जाता है, तो यह इनलाइन प्रलेखन और उदाहरणों की जांच करता है ताकि यह सुनिश्चित हो सके कि वे कोड के व्यवहार के तरीके से मेल खाते हैं। योगदान करने के लिए, आप [inline_documentation.md](./inline_documentation.md) पृष्ठ को देखकर शुरू कर सकते हैं। -- The [p5js.org उदाहरण](http://p5js.org/examples) पृष्ठ में लंबे उदाहरण हैं जो p5.js. सीखने के लिए उपयोगी हो सकते हैं। योगदान करने के लिए, आप [add_examples.md](https://github.com/processing/p5.js-website/blob/main/contributor_docs/Adding_examples.md) पृष्ठ को देखकर शुरू कर सकते हैं। +- The [p5js.org उदाहरण](https://p5js.org/examples) पृष्ठ में लंबे उदाहरण हैं जो p5.js. सीखने के लिए उपयोगी हो सकते हैं। योगदान करने के लिए, आप [add_examples.md](https://github.com/processing/p5.js-website/blob/main/contributor_docs/Adding_examples.md) पृष्ठ को देखकर शुरू कर सकते हैं। - The [p5js.org सीखिए](https://p5js.org/tutorials) पृष्ठ में p5.js और प्रोग्रामिंग की अवधारणाओं को सीखने में मदद करने के लिए ट्यूटोरियल हैं। योगदान करने के लिए, आप [p5.js ट्यूटोरियल में योगदान करने के लिए गाइड](https://p5js.org/learn/tutorial-guide.html) देखकर शुरू कर सकते हैं। - आप देखेंगे कि वर्तमान में p5.js वेबसाइट कुछ अलग भाषाओं का समर्थन करती है। इसे अंतर्राष्ट्रीयकरण (या संक्षेप में i18n) कहा जाता है। आप इस दस्तावेज़ के बारे में [i18n_contribution](https://github.com/processing/p5.js-website/blob/main/contributor_docs/i18n_contention.md) पृष्ठ पर अधिक पढ़ सकते हैं। diff --git a/contributor_docs/hi/contributing_to_the_p5js_reference.md b/contributor_docs/hi/contributing_to_the_p5js_reference.md index 8ed3d78664..07d86d503c 100644 --- a/contributor_docs/hi/contributing_to_the_p5js_reference.md +++ b/contributor_docs/hi/contributing_to_the_p5js_reference.md @@ -143,7 +143,7 @@ p5.js के स्रोत कोड को देखने पर, आपक ## अतिरिक्त चिन्ह -यदि किसी फ़ंक्शन के पास कई संभावित पैरामीटर विकल्प हैं, तो आप प्रत्येक को व्यक्तिगत रूप से निर्दिष्ट कर सकते हैं। उदाहरण के लिए, [`background()`](http://p5js.org/reference/#p5/background) फ़ंक्शन कई विभिन्न पैरामीटर विकल्प लेता है (संदर्भ पृष्ठ पर "सिंटैक्स" खण्ड देखें)। पहले हस्ताक्षर के रूप में एक संस्करण को चुनें और उसे पहले संदर्भ टिप्पणी ब्लॉक के अंत में जोड़ें, निम्नलिखित उदाहरण का पालन करें। पहले संदर्भ टिप्पणी ब्लॉक के अंत में, आप अतिरिक्त हस्ताक्षर जोड़ सकते हैं, प्रत्येक अपने ब्लॉक में, केवल `@method` और `@param` टैग का पालन करते हुए, निम्नलिखित उदाहरण का पालन करें। +यदि किसी फ़ंक्शन के पास कई संभावित पैरामीटर विकल्प हैं, तो आप प्रत्येक को व्यक्तिगत रूप से निर्दिष्ट कर सकते हैं। उदाहरण के लिए, [`background()`](https://p5js.org/reference/#p5/background) फ़ंक्शन कई विभिन्न पैरामीटर विकल्प लेता है (संदर्भ पृष्ठ पर "सिंटैक्स" खण्ड देखें)। पहले हस्ताक्षर के रूप में एक संस्करण को चुनें और उसे पहले संदर्भ टिप्पणी ब्लॉक के अंत में जोड़ें, निम्नलिखित उदाहरण का पालन करें। पहले संदर्भ टिप्पणी ब्लॉक के अंत में, आप अतिरिक्त हस्ताक्षर जोड़ सकते हैं, प्रत्येक अपने ब्लॉक में, केवल `@method` और `@param` टैग का पालन करते हुए, निम्नलिखित उदाहरण का पालन करें। ``` /** @@ -270,7 +270,7 @@ p5.js के स्रोत कोड को देखने पर, आपक * ``` -यदि आपका उदाहरण बाहरी संसाधन फ़ाइलों का उपयोग करता है, तो उन्हें [/docs/yuidoc-p5-theme/assets](https://github.com/processing/p5.js/tree/main/docs/yuidoc-p5-theme/assets) फ़ोल्डर में रखें (या पहले से वहां मौजूद कोई उपयोग करें) फिर उन्हें कोड में "assets/filename.ext" के साथ लिंक करें। उदाहरण के लिए [tint()](http://p5js.org/reference/p5/tint) संदर्भ देखें। +यदि आपका उदाहरण बाहरी संसाधन फ़ाइलों का उपयोग करता है, तो उन्हें [/docs/yuidoc-p5-theme/assets](https://github.com/processing/p5.js/tree/main/docs/yuidoc-p5-theme/assets) फ़ोल्डर में रखें (या पहले से वहां मौजूद कोई उपयोग करें) फिर उन्हें कोड में "assets/filename.ext" के साथ लिंक करें। उदाहरण के लिए [tint()](https://p5js.org/reference/p5/tint) संदर्भ देखें। ### `describe()` का उपयोग करके कैनवास का विवरण जोड़ें diff --git a/contributor_docs/how-to-add-friendly-error-messages.md b/contributor_docs/how-to-add-friendly-error-messages.md index f9b3a951ee..4b945c899d 100644 --- a/contributor_docs/how-to-add-friendly-error-messages.md +++ b/contributor_docs/how-to-add-friendly-error-messages.md @@ -122,9 +122,9 @@ circle(100, 100, 'hello'); The code above should generate the following FE messages: ``` -🌸 p5.js says: [sketch.js, line 9] circle() was expecting at least 3 arguments, but received only 1. (http://p5js.org/reference/p5/circle) -🌸 p5.js says: [sketch.js, line 14] circle() was expecting no more than 3 arguments, but received 4. (http://p5js.org/reference/p5/circle) -🌸 p5.js says: [sketch.js, line 12] circle() was expecting Number for the third parameter, received string instead. (http://p5js.org/reference/p5/circle) +🌸 p5.js says: [sketch.js, line 9] circle() was expecting at least 3 arguments, but received only 1. (https://p5js.org/reference/p5/circle) +🌸 p5.js says: [sketch.js, line 14] circle() was expecting no more than 3 arguments, but received 4. (https://p5js.org/reference/p5/circle) +🌸 p5.js says: [sketch.js, line 12] circle() was expecting Number for the third parameter, received string instead. (https://p5js.org/reference/p5/circle) ``` Congratulations 🎈! You are now done adding parameter validation for your new method. @@ -247,7 +247,7 @@ p5._friendlyError( This should generate the following FE messages: ``` -🌸 p5.js says: [sketch.js, line 19] An error with the message "vertex() must be used once before calling bezierVertex()" occurred inside the p5js library when bezierVertex was called. If not stated otherwise, it might be an issue with the arguments passed to bezierVertex. (http://p5js.org/reference/p5/bezierVertex)  +🌸 p5.js says: [sketch.js, line 19] An error with the message "vertex() must be used once before calling bezierVertex()" occurred inside the p5js library when bezierVertex was called. If not stated otherwise, it might be an issue with the arguments passed to bezierVertex. (https://p5js.org/reference/p5/bezierVertex)  ``` Congratulations 🎈! You are now done adding library error messages for your method. @@ -258,13 +258,13 @@ Congratulations 🎈! You are now done adding library error messages for your me FES message writers should prioritize lowering the barrier of understanding error messages and increasing the accessibility of the debugging process. Here is one example: ``` -🌸 p5.js says: [sketch.js, line 7] circle() was expecting at least 3 arguments, but received only 1. (http://p5js.org/reference/p5/circle)  +🌸 p5.js says: [sketch.js, line 7] circle() was expecting at least 3 arguments, but received only 1. (https://p5js.org/reference/p5/circle)  ``` The above parameter validation message will be shown in Korean if the browser is set to `ko-KR` (Korean) locale: ``` -🌸 p5.js says: [sketch.js, 줄7] 최소 3개의 인수(argument)를 받는 함수 circle()에 인수가 1개만 입력되었습니다. (http://p5js.org/reference/p5/circle)  +🌸 p5.js says: [sketch.js, 줄7] 최소 3개의 인수(argument)를 받는 함수 circle()에 인수가 1개만 입력되었습니다. (https://p5js.org/reference/p5/circle)  ``` [Friendly Errors i18n Book](https://almchung.github.io/p5-fes-i18n-book/) discusses challenges and best practices for writing Friendly Error messages within the cross-cultural i18n context. Here are the main points from the book: diff --git a/contributor_docs/ja/README.md b/contributor_docs/ja/README.md index 0859e93c1b..cd3a874808 100644 --- a/contributor_docs/ja/README.md +++ b/contributor_docs/ja/README.md @@ -11,7 +11,7 @@ p5.jsに貢献することに興味を持ってくれてありがとうござい p5.jsプロジェクトには、このコードリポジトリ以外にもいくつかの他のコードリポジトリがあります: - [p5.js](https://github.com/processing/p5.js):p5.jsのソースコードを含みます。[ユーザー向けのp5.js参照文献](https://p5js.org/reference/)も、このソースコード内の[JSDoc](http://usejsdoc.org/)コメントから生成されます。[Lauren Lee McCarthy](https://github.com/lmccart)がメンテナーです。 -- [p5.js-website](https://github.com/processing/p5.js-website):このソースコードは、[p5.jsウェブサイト](http://p5js.org)の大部分のコードを含んでいます(参照文献を除く)。[Lauren Lee McCarthy](https://github.com/lmccart)がメンテナーです。 +- [p5.js-website](https://github.com/processing/p5.js-website):このソースコードは、[p5.jsウェブサイト](https://p5js.org)の大部分のコードを含んでいます(参照文献を除く)。[Lauren Lee McCarthy](https://github.com/lmccart)がメンテナーです。 - [p5.js-sound](https://github.com/processing/p5.js-sound):p5.sound.jsライブラリを含みます。[Jason Sigal](https://github.com/therewasaguy)がメンテナーです。 - [p5.js-web-editor](https://github.com/processing/p5.js-web-editor):[p5.jsウェブエディタ](https://editor.p5js.org)のソースコードを含みます。[Cassie Tarakajian](https://github.com/catarak)がメンテナーです。旧版の[p5.jsエディタ](https://github.com/processing/p5.js-editor)はもはやサポートされていませんのでご注意ください。 - [p5.accessibility](https://github.com/processing/p5.accessibility):盲人や視覚障害者がp5.jsをより使いやすくするためのライブラリです。 @@ -34,7 +34,7 @@ p5.jsプロジェクトには、このコードリポジトリ以外にもいく 私たちは、参照文献がこのプロジェクトの最も重要な部分であることを認識しています。不十分な参照文献は、新規ユーザーや新規貢献者にとって最大の障壁であり、プロジェクトの包括性を損ないます。[contributing_documentation.md](./contributing_documentation.md)ページでは、参照文献の修正を開始するための詳細なガイドを提供しています。p5.jsの参照文献は、以下の場所で見つけることができます: - [p5js.org/reference](https://p5js.org/reference/):[inline documentation](./inline_documentation.md)のソースコードから生成されます。それには、テキストの説明とパラメータ、添付されたコードスニペットの例が含まれています。コードと参照文献を密接に連携させるために、これらすべてのインラインドキュメントとコードを一緒に配置し、参照文献への貢献がコードへの貢献と少なくとも同じくらい重要であるという考えを強化しています。ライブラリをビルドすると、インライン参照文献と例がコードの動作と一致するかどうかをチェックします。貢献するには、まず[inline_documentation.md](./inline_documentation.md)ページをチェックしてください。 -- [p5js.org/examples](http://p5js.org/examples)ページには、p5.jsを学ぶのに役立つより長い例が含まれています。貢献するには、まず[adding_examples.md](https://github.com/processing/p5.js-website/blob/main/contributor_docs/Adding_examples.md)をチェックしてください。 +- [p5js.org/examples](https://p5js.org/examples)ページには、p5.jsを学ぶのに役立つより長い例が含まれています。貢献するには、まず[adding_examples.md](https://github.com/processing/p5.js-website/blob/main/contributor_docs/Adding_examples.md)をチェックしてください。 - [p5js.org/tutorials](https://p5js.org/tutorials)ページには、p5.jsやプログラミングの概念を学ぶのに役立つチュートリアルが含まれています。貢献するには、まず[p5.js tutorial guide](https://p5js.org/learn/tutorial-guide.html)をチェックしてください。 - p5.jsウェブサイトが現在いくつかの異なる言語をサポートしていることに気付くかもしれません。これは国際化(i18n)と呼ばれます。[i18n_contribution](https://github.com/processing/p5.js-website/blob/main/contributor_docs/i18n_contribution.md)ページで詳細を学ぶことができます。 diff --git a/contributor_docs/ja/contributing_to_the_p5.js_reference.md b/contributor_docs/ja/contributing_to_the_p5.js_reference.md index 066c221552..8e606b1b96 100644 --- a/contributor_docs/ja/contributing_to_the_p5.js_reference.md +++ b/contributor_docs/ja/contributing_to_the_p5.js_reference.md @@ -143,7 +143,7 @@ p5.jsのソースコードを見るとき、ライブラリ内の多くの行が ## 其他签名 -如果一个函数有多个可能的参数选项,则可以分别指定每个参数。例如,[`background()`](http://p5js.org/reference/#p5/background) 函数有许多不同的参数选项(请参阅参考页面上的“语法”部分)。选择一个版本以使用上面的模板列出作为第一个签名。在第一个参考注释块的末尾,你可以添加额外的签名,每个签名都在自己的块中,仅使用以下示例中的 `@method` 和 `@param` 标签。 +如果一个函数有多个可能的参数选项,则可以分别指定每个参数。例如,[`background()`](https://p5js.org/reference/#p5/background) 函数有许多不同的参数选项(请参阅参考页面上的“语法”部分)。选择一个版本以使用上面的模板列出作为第一个签名。在第一个参考注释块的末尾,你可以添加额外的签名,每个签名都在自己的块中,仅使用以下示例中的 `@method` 和 `@param` 标签。 ``` /** @@ -270,7 +270,7 @@ p5.jsのソースコードを見るとき、ライブラリ内の多くの行が * ``` -サンプルで外部アセット ファイルを使用する場合は、それらを [/docs/yuidoc-p5-theme/assets](https://github.com/processing/p5.js/tree/main/docs/yuidoc-p5 -theme/assets) に配置してください。 フォルダー (またはそこにある既存のファイルを再利用) を作成し、「assets/filename.ext」を使用してコード内でそれらにリンクします。 参考例については、[tint()](http://p5js.org/reference/p5/tint) を参照してください。 +サンプルで外部アセット ファイルを使用する場合は、それらを [/docs/yuidoc-p5-theme/assets](https://github.com/processing/p5.js/tree/main/docs/yuidoc-p5 -theme/assets) に配置してください。 フォルダー (またはそこにある既存のファイルを再利用) を作成し、「assets/filename.ext」を使用してコード内でそれらにリンクします。 参考例については、[tint()](https://p5js.org/reference/p5/tint) を参照してください。 ### `describe()` を使用してキャンバスの説明を追加します diff --git a/contributor_docs/ja/creating_libraries.md b/contributor_docs/ja/creating_libraries.md index 41ee9713c2..fad4b085cc 100644 --- a/contributor_docs/ja/creating_libraries.md +++ b/contributor_docs/ja/creating_libraries.md @@ -120,8 +120,8 @@ https://github.com/processing/processing/wiki/Library-Basics#library-methods * **貢献ライブラリは、作成者によってホスト、文書化、およびメンテナンスされます。** これはGitHub、個別のウェブサイト、またはその他の場所で行われる可能性があります。 -* **ドキュメントは非常に重要です!** ライブラリのドキュメントは、ダウンロードしてライブラリを使用するユーザーが簡単に見つけられる場所に配置してください。貢献ライブラリのドキュメントは、p5.jsの主要なリファレンスドキュメントには含まれませんが、類似の形式に従うことを検討してください。以下の例を参照してください:[ライブラリ概要ページ](http://p5js.org/reference/libraries/p5.sound)、[クラス概要ページ](http://p5js.org/reference/p5.Vector)、[メソッドページ](http://p5js.org/reference/p5/arc)。 +* **ドキュメントは非常に重要です!** ライブラリのドキュメントは、ダウンロードしてライブラリを使用するユーザーが簡単に見つけられる場所に配置してください。貢献ライブラリのドキュメントは、p5.jsの主要なリファレンスドキュメントには含まれませんが、類似の形式に従うことを検討してください。以下の例を参照してください:[ライブラリ概要ページ](https://p5js.org/reference/libraries/p5.sound)、[クラス概要ページ](https://p5js.org/reference/p5.Vector)、[メソッドページ](https://p5js.org/reference/p5/arc)。 * **例も素晴らしいです!** それらは人々にあなたのライブラリが何ができるかを示します。これはすべてJavaScriptなので、ダウンロードする前にオンラインで実行することができます。[jsfiddle](http://jsfiddle.net/)と[codepen](http://codepen.io)は、例をホストするための2つの良いシンプルなオプションです。 -* **お知らせください!** ライブラリがリリース準備が整ったら、[hello@p5js.org](mailto:hello@p5js.org)にリンクといくつかの情報を添えてメールを送ってください。[ライブラリページ](http://p5js.org/libraries/)に掲載されます! +* **お知らせください!** ライブラリがリリース準備が整ったら、[hello@p5js.org](mailto:hello@p5js.org)にリンクといくつかの情報を添えてメールを送ってください。[ライブラリページ](https://p5js.org/libraries/)に掲載されます! diff --git a/contributor_docs/ja/fes_reference_dev_notes.md b/contributor_docs/ja/fes_reference_dev_notes.md index c0493abfd6..60ebdbcfef 100644 --- a/contributor_docs/ja/fes_reference_dev_notes.md +++ b/contributor_docs/ja/fes_reference_dev_notes.md @@ -213,16 +213,16 @@ _validateParameters(func, args) arc(1, 1, 10.5, 10); ``` FESはコンソールに以下のメッセージを生成します: -> 🌸 p5.jsが言うには、arc()は位置#4(ゼロベースのインデックス)で空の変数を受け取ったようです。これが意図的でない場合、通常はスコープの問題です:[https://p5js.org/examples/data-variable-scope.html]。[http://p5js.org/reference/#p5/arc] +> 🌸 p5.jsが言うには、arc()は位置#4(ゼロベースのインデックス)で空の変数を受け取ったようです。これが意図的でない場合、通常はスコープの問題です:[https://p5js.org/examples/data-variable-scope.html]。[https://p5js.org/reference/#p5/arc] -> 🌸 p5.jsが言うには、arc()は位置#5(ゼロベースのインデックス)で空の変数を受け取ったようです。これが意図的でない場合、通常はスコープの問題です:[https://p5js.org/examples/data-variable-scope.html]。[http://p5js.org/reference/#p5/arc] +> 🌸 p5.jsが言うには、arc()は位置#5(ゼロベースのインデックス)で空の変数を受け取ったようです。これが意図的でない場合、通常はスコープの問題です:[https://p5js.org/examples/data-variable-scope.html]。[https://p5js.org/reference/#p5/arc] 型の不一致の例 ```javascript arc('1', 1, 10.5, 10, 0, Math.PI, 'pie'); ``` FESはコンソールに以下のメッセージを生成します: -> 🌸 p5.jsが言うには、arc()はパラメータ#0(ゼロベースのインデックス)でNumberを期待していましたが、文字列を受け取りました。[http://p5js.org/reference/p5/arc] +> 🌸 p5.jsが言うには、arc()はパラメータ#0(ゼロベースのインデックス)でNumberを期待していましたが、文字列を受け取りました。[https://p5js.org/reference/p5/arc] ##### 位置 core/friendly_errors/validate_params.js @@ -276,7 +276,7 @@ function preload() { } ``` FES将在控制台中生成以下消息: -> 🌸 p5.jsが言うには、backgroundを呼び出したとき(sketch.jsの4行目[http://localhost:8000/lib/empty-example/sketch.js:4:3])、p5jsライブラリ内部でエラーが発生しました。エラーメッセージは「未定義のプロパティ'background'を読み取れません」です。(特に説明がない限り、これはpreloadからbackgroundが呼び出されたためかもしれません。preload関数内にはload関数(loadImage、loadJSON、loadFont、loadStringsなど)以外は含まれていないべきです。)(http://p5js.org/reference/p5/preload) +> 🌸 p5.jsが言うには、backgroundを呼び出したとき(sketch.jsの4行目[http://localhost:8000/lib/empty-example/sketch.js:4:3])、p5jsライブラリ内部でエラーが発生しました。エラーメッセージは「未定義のプロパティ'background'を読み取れません」です。(特に説明がない限り、これはpreloadからbackgroundが呼び出されたためかもしれません。preload関数内にはload関数(loadImage、loadJSON、loadFont、loadStringsなど)以外は含まれていないべきです。)(https://p5js.org/reference/p5/preload) 内部エラーの例 2 ```javascript @@ -286,7 +286,7 @@ function setup() { } ``` FES将在控制台中生成以下消息: -> 🌸 p5.jsが言うには、mouseClickedを呼び出したとき(sketch.jsの3行目[http://localhost:8000/lib/empty-example/sketch.js:3:7])、p5jsライブラリ内部でエラーが発生しました。エラーメッセージは「未定義のプロパティ'bind'を読み取れません」です。(特に説明がない限り、これはmouseClickedへの引数に問題がある可能性があります。)(http://p5js.org/reference/p5/mouseClicked) +> 🌸 p5.jsが言うには、mouseClickedを呼び出したとき(sketch.jsの3行目[http://localhost:8000/lib/empty-example/sketch.js:3:7])、p5jsライブラリ内部でエラーが発生しました。エラーメッセージは「未定義のプロパティ'bind'を読み取れません」です。(特に説明がない限り、これはmouseClickedへの引数に問題がある可能性があります。)(https://p5js.org/reference/p5/mouseClicked) ユーザー例のスコープエラーの例 ```javascript @@ -306,7 +306,7 @@ function setup() { } ``` FESはコンソールに以下のメッセージを生成します: -> 🌸 p5.jsが言うには、「colour」を誤って「color」と書いてしまった可能性があります(sketch.jsの2行目[http://localhost:8000/lib/empty-example/sketch.js:2:3])。p5.jsの関数を使用する場合は、それをcolorに修正してください(http://p5js.org/reference/p5/color)。 +> 🌸 p5.jsが言うには、「colour」を誤って「color」と書いてしまった可能性があります(sketch.jsの2行目[http://localhost:8000/lib/empty-example/sketch.js:2:3])。p5.jsの関数を使用する場合は、それをcolorに修正してください(https://p5js.org/reference/p5/color)。 ##### 位置 core/friendly_errors/fes_core.js @@ -372,7 +372,7 @@ function preLoad() { } ``` FESはコンソールに以下のメッセージを生成します: -> 🌸 p5.jsのヒント:preLoadと書くべきところをpreloadと誤って書いているようです。これが意図していない場合は、訂正してください。(http://p5js.org/reference/p5/preload) +> 🌸 p5.jsのヒント:preLoadと書くべきところをpreloadと誤って書いているようです。これが意図していない場合は、訂正してください。(https://p5js.org/reference/p5/preload) ##### 位置 core/friendly_errors/fes_core.js diff --git a/contributor_docs/ko/README.md b/contributor_docs/ko/README.md index bf770b4736..90ff0c357a 100644 --- a/contributor_docs/ko/README.md +++ b/contributor_docs/ko/README.md @@ -13,7 +13,7 @@ p5.js에 기여하는데에 관심을 가져주셔서 감사합니다! 우리 p5.js 프로젝트의 핵심적인 저장소들은 아래와 같습니다: - [p5.js](https://github.com/processing/p5.js): 본 저장소에는 p5.js 라이브러리의 소스 코드가 보관되어 있습니다. [유저들이 보게 되는 p5.js의 레퍼런스 매뉴얼](https://p5js.org/reference/) 또한 이 소스 코드에 포함되어 있는 [JSDoc](http://usejsdoc.org/) 각주에서 생성됩니다. 본 저장소는 [로렌 리 맥카시(Lauren Lee McCarthy)](https://github.com/lmccart)가 관리합니다. -- [p5.js-website](https://github.com/processing/p5.js-website): 본 저장소에는 레퍼런스 매뉴얼을 제외한 [p5.js 웹사이트](http://p5js.org)의 코드가 전부 보관되어 있습니다. 본 저장소는 [로렌 리 맥카시(Lauren Lee McCarthy)](https://github.com/lmccart)가 관리합니다. +- [p5.js-website](https://github.com/processing/p5.js-website): 본 저장소에는 레퍼런스 매뉴얼을 제외한 [p5.js 웹사이트](https://p5js.org)의 코드가 전부 보관되어 있습니다. 본 저장소는 [로렌 리 맥카시(Lauren Lee McCarthy)](https://github.com/lmccart)가 관리합니다. - [p5.js-sound](https://github.com/processing/p5.js-sound): 본 저장소에는 p5.sound.js 라이브러리가 보관되어 있습니다. 본 저장소는 [제이슨 시갈(Jason Sigal)](https://github.com/therewasaguy)이 관리합니다. - [p5.js-web-editor](https://github.com/processing/p5.js-web-editor): 본 저장소에는 [p5.js 웹 에디터](https://editor.p5js.org)의 소스 코드가 보관되어 있습니다. 본 저장소는 [캐시 타라케지언(Cassie Tarakajian)](https://github.com/catarak)이 관리합니다. 예전의 [p5.js 에디터](https://github.com/processing/p5.js-editor)는 이제 더 이상 사용되지 않다는 점을 참고하십시오. - [p5.accessibility](https://github.com/processing/p5.accessibility): 맹인 및 시각 장애인들이 조금 더 쉽게 p5 캔버스를 사용할 수 있도록 하는 라이브러리입니다. @@ -39,7 +39,7 @@ p5.js 프로젝트의 핵심적인 저장소들은 아래와 같습니다: 문서화는 본 프로젝트의 가장 중요한 부분입니다. 낮은 품질의 문서화는 새로운 이용자와 컨트리뷰터들의 진입 장벽을 높여 프로젝트 참여도를 저하시킵니다. [contributing_documentation.md](./contributing_documentation.md) 페이지는 문서화를 시작하는 데에 깊이 있는 개요를 제시합니다. p5.js를 위한 문서화는 아래와 같은 곳들에서 주로 찾아볼 수 있습니다: - [p5js.org/reference](https://p5js.org/reference/)는 소스 코드의 [인라인 도큐멘테이션](./inline_documentation.md)으로부터 생성됩니다. 이는 텍스트 설명, 파라미터, 코드 스니펫 예시 등을 포함합니다. 우리는 코드와 인라인 도큐멘테이션을 긴밀히 연결시키고, 문서화에 기여하는 게 코드에 기여하는 것 만큼이나 중요하다는 생각을 강화하기 위해 인라인 도큐멘테이션을 활용하는 것입니다. 라이브러리가 빌드 되면 라이브러리와 코드가 작동하는 방식 사이에 문제가 없음을 확실히 하기 위해 인라인 도큐멘테이션과 예시를 확인합니다. 이에 기여하기 위해선 [inline_documentation.md](./inline_documentation.md) 페이지를 살펴보는 걸로 시작하시기 바랍니다. -- [p5js.org/examples](http://p5js.org/examples)페이지는 p5.js를 학습하는 데에 유용할 수 있는 길이가 긴 예시들을 담고 있습니다. 컨트리뷰션을 위해서는 [adding_examples.md](https://github.com/processing/p5.js-website/blob/main/contributor_docs/Adding_examples.md) 페이지를 살펴보시기 바랍니다. +- [p5js.org/examples](https://p5js.org/examples)페이지는 p5.js를 학습하는 데에 유용할 수 있는 길이가 긴 예시들을 담고 있습니다. 컨트리뷰션을 위해서는 [adding_examples.md](https://github.com/processing/p5.js-website/blob/main/contributor_docs/Adding_examples.md) 페이지를 살펴보시기 바랍니다. - [p5js.org/tutorials](https://p5js.org/tutorials)페이지는 p5.js와 프로그래밍의 개념을 배울 수 있도록 도와주는 튜토리얼들을 담고 있습니다. 기여하기 위해서는 [p5.js 웹사이트의 튜토리얼에 대한 튜토리얼](https://p5js.org/learn/tutorial-guide.html)을 살펴보시기 바랍니다! - p5.js 웹사이트는 현재 몇 가지 다른 언어들을 지원하고 있음을 확인하실 수 있습니다. 이는 국제화(혹은 줄여서 i18n)라고 불립니다. 이에 대한 문서는 [i18n_contribution](https://github.com/processing/p5.js-website/blob/main/contributor_docs/i18n_contribution.md) 페이지에서 더 자세히 보실 수 있습니다. diff --git a/contributor_docs/ko/contributing_to_the_p5js_reference.md b/contributor_docs/ko/contributing_to_the_p5js_reference.md index 9fe526d86d..3648254c45 100644 --- a/contributor_docs/ko/contributing_to_the_p5js_reference.md +++ b/contributor_docs/ko/contributing_to_the_p5js_reference.md @@ -138,7 +138,7 @@ p5.js 소스 코드를 보면 많은 라인이 레퍼런스 주석으로 작성 ## 추가 시그니처 -만약 함수가 여러 개의 매개변수 옵션을 가지고 있다면, 각각을 개별적으로 명시할 수 있습니다. 예를 들어, [`background()`](http://p5js.org/reference/#p5/background) 함수는 다양한 매개변수 옵션을 지원하고 있습니다(background() 레퍼런스 페이지에서 "문법" 섹션을 확인해 보세요). 먼저 여러 옵션 중 하나를 선택하여, 앞서 살펴본 형식에 따라 첫 번째 시그니처에 관한 주석을 작성합니다. 첫 번째 주석 블록이 끝나면, 뒤이어 다른 시그니처를 추가 작성할 수 있습니다. 각각의 추가 시그니처는 ’@method’와 ‘@param’ 태그만 사용하여 작성할 수 있으며, 각자의 블록 범위 내에 작성되어야 합니다. 아래 예시를 참고해 주세요. +만약 함수가 여러 개의 매개변수 옵션을 가지고 있다면, 각각을 개별적으로 명시할 수 있습니다. 예를 들어, [`background()`](https://p5js.org/reference/#p5/background) 함수는 다양한 매개변수 옵션을 지원하고 있습니다(background() 레퍼런스 페이지에서 "문법" 섹션을 확인해 보세요). 먼저 여러 옵션 중 하나를 선택하여, 앞서 살펴본 형식에 따라 첫 번째 시그니처에 관한 주석을 작성합니다. 첫 번째 주석 블록이 끝나면, 뒤이어 다른 시그니처를 추가 작성할 수 있습니다. 각각의 추가 시그니처는 ’@method’와 ‘@param’ 태그만 사용하여 작성할 수 있으며, 각자의 블록 범위 내에 작성되어야 합니다. 아래 예시를 참고해 주세요. ``` /** @@ -262,7 +262,7 @@ p5.js 소스 코드를 보면 많은 라인이 레퍼런스 주석으로 작성 * ``` -만약, 예제 코드가 외부 애셋 파일을 사용해야 한다면, 필요한 파일들을 [/docs/yuidoc-p5-theme/assets](https://github.com/processing/p5.js/tree/main/docs/yuidoc-p5-theme/assets) 폴더에 넣어두세요(이미 해당 폴더에 존재하는 파일을 재사용해도 됩니다). 그리고 코드에서 "assets/filename.ext" 경로로 파일을 불러와 사용하면 됩니다. [tint()](http://p5js.org/reference/p5/tint) 레퍼런스를 참고하세요. +만약, 예제 코드가 외부 애셋 파일을 사용해야 한다면, 필요한 파일들을 [/docs/yuidoc-p5-theme/assets](https://github.com/processing/p5.js/tree/main/docs/yuidoc-p5-theme/assets) 폴더에 넣어두세요(이미 해당 폴더에 존재하는 파일을 재사용해도 됩니다). 그리고 코드에서 "assets/filename.ext" 경로로 파일을 불러와 사용하면 됩니다. [tint()](https://p5js.org/reference/p5/tint) 레퍼런스를 참고하세요. ### `describe()`로 캔버스 설명 추가하기 diff --git a/contributor_docs/ko/creating_libraries.md b/contributor_docs/ko/creating_libraries.md index edda2ccb7b..fb94963e0b 100644 --- a/contributor_docs/ko/creating_libraries.md +++ b/contributor_docs/ko/creating_libraries.md @@ -124,9 +124,9 @@ https://GitHub.com/processing/processing/wiki/Library-Basics#library-methods * **기여된 라이브러리는 제작자가 호스팅, 문서화 및 유지 관리합니다.** 라이브러리들은 GitHub, 별도의 웹 사이트 또는 어딘가에 있을 수 있습니다. -* **문서가 핵심입니다!** 라이브러리 문서는 사용자가 쉽게 찾아보고 다운로드 하여 사용할 수 있는 곳에 있어야 합니다. 기여된 라이브러리에 대한 문서는 기본 p5.js 레퍼런스에 포함되지 않지만 여러분이 유사한 형식을 따르고 싶을 수도 있습니다. [라이브러리 개요 페이지](http://p5js.org/reference/libraries/p5.sound), [클래스 개요 페이지](http://p5js.org/reference/p5.Vector) 및 [메소드 페이지](http://p5js.org/reference/p5/arc) 의 예제를 참조하세요. +* **문서가 핵심입니다!** 라이브러리 문서는 사용자가 쉽게 찾아보고 다운로드 하여 사용할 수 있는 곳에 있어야 합니다. 기여된 라이브러리에 대한 문서는 기본 p5.js 레퍼런스에 포함되지 않지만 여러분이 유사한 형식을 따르고 싶을 수도 있습니다. [라이브러리 개요 페이지](https://p5js.org/reference/libraries/p5.sound), [클래스 개요 페이지](https://p5js.org/reference/p5.Vector) 및 [메소드 페이지](https://p5js.org/reference/p5/arc) 의 예제를 참조하세요. * **예제가 좋습니다!** 사람들에게 라이브러리가 할 수 있는 일을 보여주세요. 모두 자바스크립트이므로 사람들은 라이브러리를 다운로드하기 전 온라인에서 실행 되는 것을 볼 수 있습니다. 예제들을 호스팅하기 쉬운 [jsfiddle](http://jsfiddle.net/) 및 [codepen](http://codepen.io)이라는 두가지 좋은 옵션이 있습니다. -* **알려주세요!** 라이브러리를 배포 할 준비가 되면 [hello@p5js.org](mailto:hello@p5js.org)로 링크와 몇 가지 정보와 함께 보내주세요. [라이브러리 페이지](http://p5js.org/libraries/)에 추가 할 것입니다. +* **알려주세요!** 라이브러리를 배포 할 준비가 되면 [hello@p5js.org](mailto:hello@p5js.org)로 링크와 몇 가지 정보와 함께 보내주세요. [라이브러리 페이지](https://p5js.org/libraries/)에 추가 할 것입니다. diff --git a/contributor_docs/ko/friendly_error_system.md b/contributor_docs/ko/friendly_error_system.md index 2f8a06ba6d..eaef49262e 100644 --- a/contributor_docs/ko/friendly_error_system.md +++ b/contributor_docs/ko/friendly_error_system.md @@ -54,15 +54,15 @@ function draw() {}; ```javascript arc(1, 1, 10.5, 10); /// 콘솔에 다음의 메시지가 생성됩니다.: -/// > pt.js: arc() 함수의 입력 파라미터 중 4번째 자리(인덱스는 0부터 시작)에 빈 값이 들어온 것 같습니다. 의도한 것이 아니라면, 이것은 종종 범위의 문제입니다.: [https://p5js.org/examples/data-variable-scope.html]. [http://p5js.org/reference/#p5/arc] -/// > pt.js: arc() 함수의 입력 파라미터 중 5번째 자리(인덱스는 0부터 시작)에 빈 값이 들어온 것 같습니다. 의도한 것이 아니라면, 이것은 종종 범위의 문제입니다.: [https://p5js.org/examples/data-variable-scope.html]. [http://p5js.org/reference/#p5/arc] +/// > pt.js: arc() 함수의 입력 파라미터 중 4번째 자리(인덱스는 0부터 시작)에 빈 값이 들어온 것 같습니다. 의도한 것이 아니라면, 이것은 종종 범위의 문제입니다.: [https://p5js.org/examples/data-variable-scope.html]. [https://p5js.org/reference/#p5/arc] +/// > pt.js: arc() 함수의 입력 파라미터 중 5번째 자리(인덱스는 0부터 시작)에 빈 값이 들어온 것 같습니다. 의도한 것이 아니라면, 이것은 종종 범위의 문제입니다.: [https://p5js.org/examples/data-variable-scope.html]. [https://p5js.org/reference/#p5/arc] ``` * 자료형 오류 예시: ```javascript arc('1', 1, 10.5, 10, 0, Math.PI, 'pie'); /// 콘솔에 다음의 메시지가 생성됩니다.: -/// > p5.js:arc() 함수의 입력 파라미터 중 0번째 자리에는(인덱스는 0부터 시작)에는 숫자가 들어와야 하는데 문자열이 들어왔습니다. [http://p5js.org/reference/#p5/arc] +/// > p5.js:arc() 함수의 입력 파라미터 중 0번째 자리에는(인덱스는 0부터 시작)에는 숫자가 들어와야 하는데 문자열이 들어왔습니다. [https://p5js.org/reference/#p5/arc] ``` * 이것은 다음과 같이 호출할 수 있습니다.: `p5._validateParameters(FUNCT_NAME, ARGUMENTS)` 또는 `p5.prototype._validateParameters(FUNCT_NAME, ARGUMENTS)` 는 파라미터 검증이 필요한 함수 내부에서 씁니다. 일반적인 목적으로는 `p5._validateParameters` 를 사용하는 것이 좋습니다. `p5.prototype._validateParameters(FUNCT_NAME, ARGUMENTS)` 은 주로 디버깅이나 단위 테스트 목적으로 사용합니다. * `color/creating_reading`, `core/2d_primitives`, `core/curves`, 그리고 `utilities/string_functions` 의 함수로 구현되어 있습니다. diff --git a/contributor_docs/pt-br/README.md b/contributor_docs/pt-br/README.md index acadbccc4d..b57af5778b 100644 --- a/contributor_docs/pt-br/README.md +++ b/contributor_docs/pt-br/README.md @@ -29,7 +29,7 @@ Além do código em si, também pode ser necessário fornecer alguma combinaçã ## Exemplos -O site p5.js. inclui [exemplos integrados](http://p5js.org/examples/). Você pode [adicionar mais](https://github.com/processing/p5.js-website/blob/main/contributor_docs/Adding_examples.md) e há uma issue que lista alguns [exemplos desejados](https://github.com/processing/p5.js/issues/1954). +O site p5.js. inclui [exemplos integrados](https://p5js.org/examples/). Você pode [adicionar mais](https://github.com/processing/p5.js-website/blob/main/contributor_docs/Adding_examples.md) e há uma issue que lista alguns [exemplos desejados](https://github.com/processing/p5.js/issues/1954). ## ES6 diff --git a/contributor_docs/sk/README.md b/contributor_docs/sk/README.md index 76e92d8396..b3bc16aedb 100644 --- a/contributor_docs/sk/README.md +++ b/contributor_docs/sk/README.md @@ -29,7 +29,7 @@ Mimo samotného kódu je potrebné aby si dodal aj kombináciu z nasledovných. ## Príklady -Stránka p5.js obsahujé [integrované príklady](http://p5js.org/examples/). Môžeš [pridať ďalšie](https://github.com/processing/p5.js-website/blob/main/contributor_docs/Adding_examples.md) a zároveň si pozrieť problém, ktorý obsahuje list [požadovaných príkladov](https://github.com/processing/p5.js/issues/1954). +Stránka p5.js obsahujé [integrované príklady](https://p5js.org/examples/). Môžeš [pridať ďalšie](https://github.com/processing/p5.js-website/blob/main/contributor_docs/Adding_examples.md) a zároveň si pozrieť problém, ktorý obsahuje list [požadovaných príkladov](https://github.com/processing/p5.js/issues/1954). ## ES6 p5.js nedávno migrovalo na [ES6](https://en.wikipedia.org/wiki/ECMAScript#6th_Edition_-_ECMAScript_2015). Ak chceš vidieť ako táto zmena ovplyňuje tvoj príspevok, navštív prosím stránku [adaptácia ES6](./es6-adoption.md). @@ -154,7 +154,7 @@ $ npm run docs:dev Zastršujúci projekt p5.js zahŕňa aj iné repozitáre ako tento. - [p5.js](https://github.com/processing/p5.js): Tento repozitár obsahuje zdrojový kód knižnice p5.js. [Používateľská referečná príručka p5.js](https://p5js.org/reference/) je generovaná z [JSDoc](http://usejsdoc.org/) komentárov zahrnutých v tomto zdrojovom kóde. Spravuje ho [Lauren McCarthy](https://github.com/lmccart). -- [website](https://github.com/processing/p5.js-website) Tento repozitár obsahuje väčšinu kódu [stránky p5.js](http://p5js.org) s výnimkou referenčnej príručky. Spravuje ho [Lauren McCarthy](https://github.com/lmccart). +- [website](https://github.com/processing/p5.js-website) Tento repozitár obsahuje väčšinu kódu [stránky p5.js](https://p5js.org) s výnimkou referenčnej príručky. Spravuje ho [Lauren McCarthy](https://github.com/lmccart). - [sound](https://github.com/processing/p5.js-sound) Tento repozitár obsahuje knižnicu p5.sound.js. Spravuje ho [Jason Sigal](https://github.com/therewasaguy). - [web editor](https://github.com/processing/p5.js-web-editor): Tento repozitár obsahuje zdrojový kód pre [p5.js web editor](https://editor.p5js.org). Spravuje ho [Cassie Tarakajian](https://github.com/catarak). Všimni si však, že [p5.js editor](https://github.com/processing/p5.js-editor) je už zastaraný. diff --git a/contributor_docs/zh-Hans/README.md b/contributor_docs/zh-Hans/README.md index 1e5661d141..0df766e81b 100644 --- a/contributor_docs/zh-Hans/README.md +++ b/contributor_docs/zh-Hans/README.md @@ -11,7 +11,7 @@ p5.js 项目除了这个代码库外还包括了以下几个其他的代码库: - [p5.js](https://github.com/processing/p5.js):包括了 p5.js 源代码。[面向用户的 p5.js 参考文献](https://p5js.org/reference/)也是由包含在此源代码中的 [JSDoc](http://usejsdoc.org/) 注解生成的。[Lauren Lee McCarthy](https://github.com/lmccart) 为维持者。 -- [p5.js-website](https://github.com/processing/p5.js-website):此源代码包含了 [p5.js website](http://p5js.org )的大多数代码(除参考文献外)。[Lauren Lee McCarthy](https://github.com/lmccart) 为维持者。 +- [p5.js-website](https://github.com/processing/p5.js-website):此源代码包含了 [p5.js website](https://p5js.org )的大多数代码(除参考文献外)。[Lauren Lee McCarthy](https://github.com/lmccart) 为维持者。 - [p5.js-sound](https://github.com/processing/p5.js-sound):包括了 p5.sound.js 程式库。[Jason Sigal](https://github.com/therewasaguy) 为维持者。 - [p5.js-web-editor](https://github.com/processing/p5.js-web-editor):包含了 [p5.js web editor](https://editor.p5js.org) 的源代码。[Cassie Tarakajian](https://github.com/catarak) 为维持者。请注意,旧版 [p5.js editor](https://github.com/processing/p5.js-editor) 已不再受支持。 - [p5.accessibility](https://github.com/processing/p5.accessibility):使 p5.js 更适合盲人和视障人士使用的程式库。 @@ -34,7 +34,7 @@ p5.js 项目除了这个代码库外还包括了以下几个其他的代码库 我们意识到参考文献是这个项目中最重要的部分。不好的参考文献是新用户与新贡献者的最大屏障,让项目不具有包容性。[contributing_documentation.md](./contributing_documentation.md) 页面为开始修改参考文献给出了一个深入的导览。p5.js 的参考文献可以在以下几个地方找到: - [p5js.org/reference](https://p5js.org/reference/):由 [inline documentation](./inline_documentation.md) 的源代码生成。它包括了文本描述和参数以及随附的代码片段示例。我们将所有这些内联文献和代码放在一起,以使代码和参考文献保持紧密的联系,并强化这样的思想,贡献参考文献与贡献代码至少同等重要。构建库后,它将检查内联参考文献和示例,以确保它们与代码的行为方式匹配。 要做出贡献,您可以先查看 [inline_documentation.md](./inline_documentation.md) 页面。 -- [p5js.org/examples](http://p5js.org/examples) 页面包含更长的示例,这些示例对于学习 p5.js 可能有用。要做出贡献,您可以先查看 [adding_examples.md](https://github.com/processing/p5.js-website/blob/main/contributor_docs/Adding_examples.md)。 +- [p5js.org/examples](https://p5js.org/examples) 页面包含更长的示例,这些示例对于学习 p5.js 可能有用。要做出贡献,您可以先查看 [adding_examples.md](https://github.com/processing/p5.js-website/blob/main/contributor_docs/Adding_examples.md)。 - [p5js.org/tutorials](https://p5js.org/tutorials) 页面包含可帮助您学习 p5.js 和编程概念的教程。 要做出贡献,您可以先查看 [p5.js guide to contributing to tutorials](https://p5js.org/learn/tutorial-guide.html)。 - 您可能会注意到 p5.js 网站目前支持几种不同的语言。这称为国际化(i18n)。您可以在 [i18n_contribution](https://github.com/processing/p5.js-website/blob/main/contributor_docs/i18n_contribution.md)页面了解更多。 diff --git a/contributor_docs/zh-Hans/contributing_to_the_p5js_reference.md b/contributor_docs/zh-Hans/contributing_to_the_p5js_reference.md index 242efe1d33..612fd0ab7e 100644 --- a/contributor_docs/zh-Hans/contributing_to_the_p5js_reference.md +++ b/contributor_docs/zh-Hans/contributing_to_the_p5js_reference.md @@ -142,7 +142,7 @@ ## 其他签名 -如果一个函数有多个可能的参数选项,则可以分别指定每个参数。例如,[`background()`](http://p5js.org/reference/#p5/background) 函数有许多不同的参数选项(请参阅参考页面上的“语法”部分)。选择一个版本以使用上面的模板列出作为第一个签名。在第一个参考注释块的末尾,你可以添加额外的签名,每个签名都在自己的块中,仅使用以下示例中的 `@method` 和 `@param` 标签。 +如果一个函数有多个可能的参数选项,则可以分别指定每个参数。例如,[`background()`](https://p5js.org/reference/#p5/background) 函数有许多不同的参数选项(请参阅参考页面上的“语法”部分)。选择一个版本以使用上面的模板列出作为第一个签名。在第一个参考注释块的末尾,你可以添加额外的签名,每个签名都在自己的块中,仅使用以下示例中的 `@method` 和 `@param` 标签。 ``` /** @@ -269,7 +269,7 @@ * ``` -如果你的示例使用外部素材文件,请将它们放入 [/docs/yuidoc-p5-theme/assets](https://github.com/processing/p5.js/tree/main/docs/yuidoc-p5-theme/assets) 文件夹中(或者重用其中已有的文件),然后在代码中使用 "assets/filename.ext" 链接到它们。请参阅 [tint()](http://p5js.org/reference/p5/tint) 参考示例。 +如果你的示例使用外部素材文件,请将它们放入 [/docs/yuidoc-p5-theme/assets](https://github.com/processing/p5.js/tree/main/docs/yuidoc-p5-theme/assets) 文件夹中(或者重用其中已有的文件),然后在代码中使用 "assets/filename.ext" 链接到它们。请参阅 [tint()](https://p5js.org/reference/p5/tint) 参考示例。 ### 使用 `describe()` 添加画布描述 diff --git a/contributor_docs/zh-Hans/creating_libraries.md b/contributor_docs/zh-Hans/creating_libraries.md index 3e8ea1bcf3..8e3479aedb 100644 --- a/contributor_docs/zh-Hans/creating_libraries.md +++ b/contributor_docs/zh-Hans/creating_libraries.md @@ -118,8 +118,8 @@ https://github.com/processing/processing/wiki/Library-Basics#library-methods * **贡献的库由创建者托管、文档化和维护。** 这可以在GitHub、一个单独的网站或其他地方进行。 -* **文档至关重要!** 您的库的文档应该放在某个易于找到的位置,供下载和使用您的库的用户使用。贡献的库的文档将不会包含在主要的p5.js参考文档中,但您可能希望遵循类似的格式。请参阅这些示例:[库概述页面](http://p5js.org/reference/libraries/p5.sound)、[类概述页面](http://p5js.org/reference/p5.Vector)和[方法页面](http://p5js.org/reference/p5/arc)。 +* **文档至关重要!** 您的库的文档应该放在某个易于找到的位置,供下载和使用您的库的用户使用。贡献的库的文档将不会包含在主要的p5.js参考文档中,但您可能希望遵循类似的格式。请参阅这些示例:[库概述页面](https://p5js.org/reference/libraries/p5.sound)、[类概述页面](https://p5js.org/reference/p5.Vector)和[方法页面](https://p5js.org/reference/p5/arc)。 * **示例也很棒!** 它们向人们展示了您的库能做什么。由于这全部是JavaScript,人们可以在下载之前在线运行它们。[jsfiddle](http://jsfiddle.net/)和[codepen](http://codepen.io)是两个很好的简单选项,可以用来托管示例。 -* **告诉我们吧!** 一旦您的库准备好发布,发送一封电子邮件至[hello@p5js.org](mailto:hello@p5js.org),附上链接和一些信息。我们将在[libraries page](http://p5js.org/libraries/)上包含它! +* **告诉我们吧!** 一旦您的库准备好发布,发送一封电子邮件至[hello@p5js.org](mailto:hello@p5js.org),附上链接和一些信息。我们将在[libraries page](https://p5js.org/libraries/)上包含它! diff --git a/contributor_docs/zh-Hans/fes_reference_dev_notes.md b/contributor_docs/zh-Hans/fes_reference_dev_notes.md index ea3c77130b..8dd1e6af92 100644 --- a/contributor_docs/zh-Hans/fes_reference_dev_notes.md +++ b/contributor_docs/zh-Hans/fes_reference_dev_notes.md @@ -209,16 +209,16 @@ _validateParameters(func, args) arc(1, 1, 10.5, 10); ``` FES将在控制台生成以下消息: -> 🌸 p5.js 说:看起来arc()在位置#4(从零开始的索引)收到了一个空变量。如果不是故意的,这通常是作用域问题:[https://p5js.org/examples/data-variable-scope.html]。[http://p5js.org/reference/#p5/arc] +> 🌸 p5.js 说:看起来arc()在位置#4(从零开始的索引)收到了一个空变量。如果不是故意的,这通常是作用域问题:[https://p5js.org/examples/data-variable-scope.html]。[https://p5js.org/reference/#p5/arc] -> 🌸 p5.js 说:看起来arc()在位置#5(从零开始的索引)收到了一个空变量。如果不是故意的,这通常是作用域问题:[https://p5js.org/examples/data-variable-scope.html]。[http://p5js.org/reference/#p5/arc] +> 🌸 p5.js 说:看起来arc()在位置#5(从零开始的索引)收到了一个空变量。如果不是故意的,这通常是作用域问题:[https://p5js.org/examples/data-variable-scope.html]。[https://p5js.org/reference/#p5/arc] 类型不匹配的示例 ```javascript arc('1', 1, 10.5, 10, 0, Math.PI, 'pie'); ``` FES将在控制台生成以下消息: -> 🌸 p5.js 说:arc()在参数#0(从零开始的索引)处期望接收Number,但收到了字符串。[http://p5js.org/reference/p5/arc] +> 🌸 p5.js 说:arc()在参数#0(从零开始的索引)处期望接收Number,但收到了字符串。[https://p5js.org/reference/p5/arc] ##### 位置 core/friendly_errors/validate_params.js @@ -272,7 +272,7 @@ function preload() { } ``` FES将在控制台中生成以下消息: -> 🌸 p5.js说:当调用background时(位于sketch.js的第4行[http://localhost:8000/lib/empty-example/sketch.js:4:3]),在p5js库内部发生了一个错误,错误消息为“无法读取未定义的属性'background'”。(如果没有另外说明,这可能是由于从preload中调用了background。preload函数中除了load函数(loadImage、loadJSON、loadFont、loadStrings等)之外不应该有其他内容。)(http://p5js.org/reference/p5/preload) +> 🌸 p5.js说:当调用background时(位于sketch.js的第4行[http://localhost:8000/lib/empty-example/sketch.js:4:3]),在p5js库内部发生了一个错误,错误消息为“无法读取未定义的属性'background'”。(如果没有另外说明,这可能是由于从preload中调用了background。preload函数中除了load函数(loadImage、loadJSON、loadFont、loadStrings等)之外不应该有其他内容。)(https://p5js.org/reference/p5/preload) 内部错误示例 2 ```javascript @@ -282,7 +282,7 @@ function setup() { } ``` FES将在控制台中生成以下消息: -> 🌸 p5.js说:当调用mouseClicked时(位于sketch.js的第3行[http://localhost:8000/lib/empty-example/sketch.js:3:7]),在p5js库内部发生了一个错误,错误消息为“无法读取未定义的属性'bind'”。(如果没有另外说明,这可能是由于传递给mouseClicked的参数存在问题。)(http://p5js.org/reference/p5/mouseClicked) +> 🌸 p5.js说:当调用mouseClicked时(位于sketch.js的第3行[http://localhost:8000/lib/empty-example/sketch.js:3:7]),在p5js库内部发生了一个错误,错误消息为“无法读取未定义的属性'bind'”。(如果没有另外说明,这可能是由于传递给mouseClicked的参数存在问题。)(https://p5js.org/reference/p5/mouseClicked) 用户示例中的作用域错误示例 ```javascript @@ -303,7 +303,7 @@ function setup() { } ``` FES将在控制台中生成以下消息: -> 🌸 p5.js说:您可能错误地将“colour”写成了“color”(位于sketch.js的第2行[http://localhost:8000/lib/empty-example/sketch.js:2:3])。如果希望使用p5.js中的函数,请将其更正为color(http://p5js.org/reference/p5/color)。 +> 🌸 p5.js说:您可能错误地将“colour”写成了“color”(位于sketch.js的第2行[http://localhost:8000/lib/empty-example/sketch.js:2:3])。如果希望使用p5.js中的函数,请将其更正为color(https://p5js.org/reference/p5/color)。 ##### 位置 core/friendly_errors/fes_core.js @@ -369,7 +369,7 @@ function preLoad() { } ``` FES 将在控制台生成以下消息: -> 🌸 p5.js 提示:似乎您可能误写了 preLoad,应该是 preload。如果这不是您的意图,请进行更正。(http://p5js.org/reference/p5/preload) +> 🌸 p5.js 提示:似乎您可能误写了 preLoad,应该是 preload。如果这不是您的意图,请进行更正。(https://p5js.org/reference/p5/preload) ##### 位置 core/friendly_errors/fes_core.js diff --git a/src/core/environment.js b/src/core/environment.js index 4d15491948..d6efe67841 100644 --- a/src/core/environment.js +++ b/src/core/environment.js @@ -1211,7 +1211,7 @@ p5.prototype.getURLPath = () => * in an `Object`. * * For example, calling `getURLParams()` in a sketch hosted at the URL - * `http://p5js.org?year=2014&month=May&day=15` returns + * `https://p5js.org?year=2014&month=May&day=15` returns * `{ year: 2014, month: 'May', day: 15 }`. * * @method getURLParams diff --git a/src/core/friendly_errors/fes_core.js b/src/core/friendly_errors/fes_core.js index f78fd957ce..caf08772b8 100644 --- a/src/core/friendly_errors/fes_core.js +++ b/src/core/friendly_errors/fes_core.js @@ -145,8 +145,8 @@ if (typeof IS_MINIFIED !== 'undefined') { //Whenever func having p5.[Class] is encountered, we need to have the error link as mentioned below else different link funcName.startsWith('p5.') ? - msgWithReference = `${message} (http://p5js.org/reference/${referenceSection}.${funcName})` : - msgWithReference = `${message} (http://p5js.org/reference/${referenceSection}/${funcName})`; + msgWithReference = `${message} (https://p5js.org/reference/${referenceSection}.${funcName})` : + msgWithReference = `${message} (https://p5js.org/reference/${referenceSection}/${funcName})`; } return msgWithReference; }; diff --git a/src/dom/dom.js b/src/dom/dom.js index 2f04be1ef2..99d05281af 100644 --- a/src/dom/dom.js +++ b/src/dom/dom.js @@ -752,7 +752,7 @@ p5.prototype.createImg = function () { * background(200); * * // Create an anchor element that links to p5js.org. - * let a = createA('http://p5js.org/', 'p5*js'); + * let a = createA('https://p5js.org/', 'p5*js'); * a.position(25, 35); * * describe('The text "p5*js" written at the center of a gray square.'); @@ -767,7 +767,7 @@ p5.prototype.createImg = function () { * * // Create an anchor tag that links to p5js.org. * // Open the link in a new tab. - * let a = createA('http://p5js.org/', 'p5*js', '_blank'); + * let a = createA('https://p5js.org/', 'p5*js', '_blank'); * a.position(25, 35); * * describe('The text "p5*js" written at the center of a gray square.'); diff --git a/src/io/files.js b/src/io/files.js index 64c82d3171..88d627b25a 100644 --- a/src/io/files.js +++ b/src/io/files.js @@ -549,7 +549,7 @@ p5.prototype.loadStrings = function(...args) { * //and has a header specifying the columns labels * table = loadTable('assets/mammals.csv', 'csv', 'header'); * //the file can be remote - * //table = loadTable("http://p5js.org/reference/assets/mammals.csv", + * //table = loadTable("https://p5js.org/reference/assets/mammals.csv", * // "csv", "header"); * } * From fd335996b7d5df801bee8ca026a79fdb4e3b7cad Mon Sep 17 00:00:00 2001 From: limzykenneth Date: Fri, 31 Jan 2025 18:06:24 +0000 Subject: [PATCH 044/282] Change reference to avoid parsing problem on website --- src/dom/dom.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dom/dom.js b/src/dom/dom.js index 99d05281af..6bafb5bae4 100644 --- a/src/dom/dom.js +++ b/src/dom/dom.js @@ -541,7 +541,7 @@ p5.prototype.createDiv = function (html = '') { }; /** - * Creates a `<p></p>` element. + * Creates a paragraph element. * * `<p></p>` elements are commonly used for paragraph-length text. * From bc888f2bf9edb2c1ffdc948ab5ac3f92710cbbee Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 4 Feb 2025 15:59:49 +0000 Subject: [PATCH 045/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index dbb11fbc2d..554ba3c5cf 100644 --- a/README.md +++ b/README.md @@ -1105,6 +1105,7 @@ We recognize all types of contributions. This project follows the [all-contribut crh82
crh82

💡 Aaron Welles
Aaron Welles
💡 + Seyko
Seyko

💻 From 217d56c32cd619ab8793fa79a1e10392eb3667e0 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 4 Feb 2025 15:59:50 +0000 Subject: [PATCH 046/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 27f5458293..7c38f18ebc 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6636,6 +6636,15 @@ "contributions": [ "example" ] + }, + { + "login": "seyko1", + "name": "Seyko", + "avatar_url": "https://avatars.githubusercontent.com/u/26870879?v=4", + "profile": "https://github.com/seyko1", + "contributions": [ + "code" + ] } ], "repoType": "github", From 596466af514396658e614842226c8b3a62184f51 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2025 21:17:15 +0000 Subject: [PATCH 047/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 554ba3c5cf..72088f2c64 100644 --- a/README.md +++ b/README.md @@ -1106,6 +1106,7 @@ We recognize all types of contributions. This project follows the [all-contribut crh82
crh82

💡 Aaron Welles
Aaron Welles
💡 Seyko
Seyko

💻 + Xevi H. Aqeel
Xevi H. Aqeel

💡 🎨 From ebe7a1e4397f4bb0fbe53dcf09d85277ef90bdba Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2025 21:17:16 +0000 Subject: [PATCH 048/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 7c38f18ebc..1afd5d8896 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6645,6 +6645,16 @@ "contributions": [ "code" ] + }, + { + "login": "thekinardist", + "name": "Xevi H. Aqeel", + "avatar_url": "https://avatars.githubusercontent.com/u/21345916?v=4", + "profile": "http://kinardist.media", + "contributions": [ + "example", + "design" + ] } ], "repoType": "github", From bba9ed737f39458892c865cb5dde434af5c3025e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 15 Feb 2025 08:58:36 +0000 Subject: [PATCH 049/282] Bump serialize-javascript and mocha Bumps [serialize-javascript](https://github.com/yahoo/serialize-javascript) to 6.0.2 and updates ancestor dependency [mocha](https://github.com/mochajs/mocha). These dependencies need to be updated together. Updates `serialize-javascript` from 6.0.0 to 6.0.2 - [Release notes](https://github.com/yahoo/serialize-javascript/releases) - [Commits](https://github.com/yahoo/serialize-javascript/compare/v6.0.0...v6.0.2) Updates `mocha` from 10.2.0 to 10.8.2 - [Release notes](https://github.com/mochajs/mocha/releases) - [Changelog](https://github.com/mochajs/mocha/blob/main/CHANGELOG.md) - [Commits](https://github.com/mochajs/mocha/compare/v10.2.0...v10.8.2) --- updated-dependencies: - dependency-name: serialize-javascript dependency-type: indirect - dependency-name: mocha dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- package-lock.json | 169 ++++++++++++++++++++-------------------------- 1 file changed, 72 insertions(+), 97 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7040c18256..c938cfe98c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2590,10 +2590,11 @@ } }, "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -5236,10 +5237,11 @@ "dev": true }, "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } @@ -11098,32 +11100,32 @@ "dev": true }, "node_modules/mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", + "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^8.1.0", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" }, "bin": { "_mocha": "bin/_mocha", @@ -11131,10 +11133,6 @@ }, "engines": { "node": ">= 14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" } }, "node_modules/mocha/node_modules/ansi-regex": { @@ -11167,6 +11165,16 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/mocha/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -11219,12 +11227,13 @@ } }, "node_modules/mocha/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -11235,12 +11244,6 @@ } } }, - "node_modules/mocha/node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/mocha/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -11276,37 +11279,26 @@ } }, "node_modules/mocha/node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^5.0.1", + "once": "^1.3.0" }, "engines": { - "node": "*" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/mocha/node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/mocha/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -11369,10 +11361,11 @@ } }, "node_modules/mocha/node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -11380,15 +11373,6 @@ "node": ">=10" } }, - "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/mocha/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -11523,10 +11507,11 @@ } }, "node_modules/mocha/node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } @@ -11597,18 +11582,6 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, - "node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -15807,10 +15780,11 @@ } }, "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" } @@ -17536,10 +17510,11 @@ } }, "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", + "dev": true, + "license": "Apache-2.0" }, "node_modules/wrap-ansi": { "version": "6.2.0", From 1291d3903991e6e3bb031a3857080c1638d2e3b3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 15 Feb 2025 08:58:41 +0000 Subject: [PATCH 050/282] Bump elliptic from 6.6.0 to 6.6.1 Bumps [elliptic](https://github.com/indutny/elliptic) from 6.6.0 to 6.6.1. - [Commits](https://github.com/indutny/elliptic/compare/v6.6.0...v6.6.1) --- updated-dependencies: - dependency-name: elliptic dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7040c18256..1f6c73416f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5365,10 +5365,11 @@ } }, "node_modules/elliptic": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.0.tgz", - "integrity": "sha512-dpwoQcLc/2WLQvJvLRHKZ+f9FgOdjnq11rurqwekGQygGPsYSK29OMMD2WalatiqQ+XGFDglTNixpPfI+lpaAA==", + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", "dev": true, + "license": "MIT", "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", From f921125078326c1f0a24c359657a4672eeda5a75 Mon Sep 17 00:00:00 2001 From: probablynotval <162844653+probablynotval@users.noreply.github.com> Date: Mon, 17 Feb 2025 00:15:00 +0000 Subject: [PATCH 051/282] fix typo --- src/typography/attributes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/typography/attributes.js b/src/typography/attributes.js index 3960ad53bc..d6a5eb8d5e 100644 --- a/src/typography/attributes.js +++ b/src/typography/attributes.js @@ -154,7 +154,7 @@ p5.prototype.textLeading = function(theLeading) { * * Note: Font size is measured in pixels. * - * Calling `textSize()` without an arugment returns the current size. + * Calling `textSize()` without an argument returns the current size. * * @method textSize * @param {Number} size size of the letters in units of pixels. From a6ae3428716431197cf48ce20be5b41169f6cdbc Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 17 Feb 2025 15:43:08 +0000 Subject: [PATCH 052/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 72088f2c64..efcdacf92a 100644 --- a/README.md +++ b/README.md @@ -1107,6 +1107,7 @@ We recognize all types of contributions. This project follows the [all-contribut Aaron Welles
Aaron Welles
💡 Seyko
Seyko

💻 Xevi H. Aqeel
Xevi H. Aqeel

💡 🎨 + Greg Stanton
Greg Stanton

🐛 💻 📖 💡 🤔 🔌 📆 📣 💬 🔬 From d2e76b8858fbb720040ce102c8b8ae58415e8fe0 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 17 Feb 2025 15:43:09 +0000 Subject: [PATCH 053/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 1afd5d8896..d24e0afe21 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6655,6 +6655,24 @@ "example", "design" ] + }, + { + "login": "GregStanton", + "name": "Greg Stanton", + "avatar_url": "https://avatars.githubusercontent.com/u/51820777?v=4", + "profile": "https://www.youtube.com/c/HigherMathNotes", + "contributions": [ + "bug", + "code", + "doc", + "example", + "ideas", + "plugin", + "projectManagement", + "promotion", + "question", + "research" + ] } ], "repoType": "github", From 1cfb0837ef0ab08f3cff8642773b2b8344728950 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 17 Feb 2025 16:00:56 +0000 Subject: [PATCH 054/282] docs: update README.md [skip ci] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 72088f2c64..5387490d5d 100644 --- a/README.md +++ b/README.md @@ -921,7 +921,7 @@ We recognize all types of contributions. This project follows the [all-contribut Garima
Garima

💻 Lakshay Joshi
Lakshay Joshi

💻 - perminder-17
perminder-17

💻 + perminder-17
perminder-17

💻 🐛 📖 💡 🤔 🔌 📆 📣 💬 🔬 Yash Pandey
Yash Pandey

🐛 💻 Aditya Deshpande
Aditya Deshpande

🐛 📖 Alejandro
Alejandro

🐛 💻 From 1222acaeb638b87d8acb3a46f69db86063beb031 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 17 Feb 2025 16:00:57 +0000 Subject: [PATCH 055/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 1afd5d8896..6467135168 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -5344,7 +5344,16 @@ "avatar_url": "https://avatars.githubusercontent.com/u/127239756?v=4", "profile": "https://github.com/perminder-17", "contributions": [ - "code" + "code", + "bug", + "doc", + "example", + "ideas", + "plugin", + "projectManagement", + "promotion", + "question", + "research" ] }, { From 8668be816119e97de3c9de5d8770045b699c329d Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 19 Feb 2025 20:05:50 +0000 Subject: [PATCH 056/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6a476d32e0..cd05598fc4 100644 --- a/README.md +++ b/README.md @@ -1108,6 +1108,7 @@ We recognize all types of contributions. This project follows the [all-contribut Seyko
Seyko

💻 Xevi H. Aqeel
Xevi H. Aqeel

💡 🎨 Greg Stanton
Greg Stanton

🐛 💻 📖 💡 🤔 🔌 📆 📣 💬 🔬 + Bojidar Marinov
Bojidar Marinov

💻 ⚠️ From d4da26f1fa8e9afbac082c3d6fd60b5e582a3aa2 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 19 Feb 2025 20:05:51 +0000 Subject: [PATCH 057/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 71f363e103..09d746fc96 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6682,6 +6682,16 @@ "question", "research" ] + }, + { + "login": "bojidar-bg", + "name": "Bojidar Marinov", + "avatar_url": "https://avatars.githubusercontent.com/u/5276727?v=4", + "profile": "https://bojidar-bg.dev/", + "contributions": [ + "code", + "test" + ] } ], "repoType": "github", From 2239c8173eb7ba9305aa8a3032960e4a759a59ec Mon Sep 17 00:00:00 2001 From: Bairui Su Date: Thu, 20 Feb 2025 22:43:13 -0500 Subject: [PATCH 058/282] Fix typos in color_namer.js --- src/accessibility/color_namer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/accessibility/color_namer.js b/src/accessibility/color_namer.js index 4509280e5b..3443c109ae 100644 --- a/src/accessibility/color_namer.js +++ b/src/accessibility/color_namer.js @@ -702,9 +702,9 @@ function _calculateColor(hsb) { return colortext; } -//gets rgba and returs a color name +//gets rgba and returns a color name p5.prototype._rgbColorName = function(arg) { - //conversts rgba to hsb + //converts rgba to hsb let hsb = color_conversion._rgbaToHSBA(arg); //stores hsb in global variable originalHSB = hsb; From 140cbdba533ef117400de3e0334bbdcca2d8c96d Mon Sep 17 00:00:00 2001 From: Chloe Yan Date: Thu, 20 Feb 2025 22:43:13 -0500 Subject: [PATCH 059/282] Fix typos in gridOutput.js --- src/accessibility/gridOutput.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/accessibility/gridOutput.js b/src/accessibility/gridOutput.js index 5b52a23eb8..f5b4936cd5 100644 --- a/src/accessibility/gridOutput.js +++ b/src/accessibility/gridOutput.js @@ -117,7 +117,7 @@ function _gridShapeDetails(idT, ingredients) { let shapeDetails = ''; let shapes = ''; let totalShapes = 0; - //goes trhough every shape type in ingredients + //goes through every shape type in ingredients for (let x in ingredients) { let shapeNum = 0; for (let y in ingredients[x]) { From cf54b159a90d99df9c1550ba1210e12a85515ed6 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Fri, 21 Feb 2025 19:37:37 +0000 Subject: [PATCH 060/282] docs: update README.md [skip ci] --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index cd05598fc4..0722296576 100644 --- a/README.md +++ b/README.md @@ -1110,6 +1110,9 @@ We recognize all types of contributions. This project follows the [all-contribut Greg Stanton
Greg Stanton

🐛 💻 📖 💡 🤔 🔌 📆 📣 💬 🔬 Bojidar Marinov
Bojidar Marinov

💻 ⚠️ + + Chloe Yan
Chloe Yan

📖 + From 0a4c3ca466b297bae656161cf200cb1d61e2b9ca Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Fri, 21 Feb 2025 19:37:38 +0000 Subject: [PATCH 061/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 09d746fc96..933d1d5f58 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6692,6 +6692,15 @@ "code", "test" ] + }, + { + "login": "ChloeYanYan", + "name": "Chloe Yan", + "avatar_url": "https://avatars.githubusercontent.com/u/181019103?v=4", + "profile": "https://github.com/ChloeYanYan", + "contributions": [ + "doc" + ] } ], "repoType": "github", From b5901a60c6fb4912e5d2f11db4e766eadc838ef3 Mon Sep 17 00:00:00 2001 From: FORCHA PEARL Date: Fri, 28 Feb 2025 05:19:05 +0100 Subject: [PATCH 062/282] Fix endShape() to Properly Close Paths and Prevent Shape Merging --- src/core/p5.Renderer2D.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/p5.Renderer2D.js b/src/core/p5.Renderer2D.js index ac41b13411..91944eaf07 100644 --- a/src/core/p5.Renderer2D.js +++ b/src/core/p5.Renderer2D.js @@ -855,6 +855,7 @@ class Renderer2D extends p5.Renderer { this.drawingContext.lineTo(vertices[i + 1][0], vertices[i + 1][1]); } this._doFillStrokeClose(closeShape); + this.drawingContext.closePath(); } } else if ( isBezier && From 6729d0942e30a2f9521a86c29256251495520345 Mon Sep 17 00:00:00 2001 From: Soubhagya Mohapatra Date: Fri, 28 Feb 2025 20:27:18 +0530 Subject: [PATCH 063/282] added instance of video in callback --- src/dom/dom.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/dom/dom.js b/src/dom/dom.js index 6bafb5bae4..0e1b211026 100644 --- a/src/dom/dom.js +++ b/src/dom/dom.js @@ -2082,15 +2082,6 @@ function createMedia(pInst, type, src, callback) { elt.appendChild(sourceEl); } - // If callback is provided, attach to element - if (typeof callback === 'function') { - const callbackHandler = () => { - callback(); - elt.removeEventListener('canplaythrough', callbackHandler); - }; - elt.addEventListener('canplaythrough', callbackHandler); - } - const mediaEl = addElement(elt, pInst, true); mediaEl.loadedmetadata = false; @@ -2109,6 +2100,15 @@ function createMedia(pInst, type, src, callback) { mediaEl.loadedmetadata = true; }); + // If callback is provided, attach to element + if (typeof callback === 'function') { + const callbackHandler = () => { + callback(mediaEl); + elt.removeEventListener('canplaythrough', callbackHandler); + }; + elt.addEventListener('canplaythrough', callbackHandler); + } + return mediaEl; } From d342533b14a282ff46733113f48e70d313b6c4f5 Mon Sep 17 00:00:00 2001 From: swastikCommits Date: Sat, 1 Mar 2025 15:17:00 +0530 Subject: [PATCH 064/282] fix: push() ignoring the ColorMode #7402 --- src/core/p5.Renderer.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/p5.Renderer.js b/src/core/p5.Renderer.js index 21ce3bd64b..41417b3606 100644 --- a/src/core/p5.Renderer.js +++ b/src/core/p5.Renderer.js @@ -86,7 +86,9 @@ class Renderer extends p5.Element { _textAlign: this._textAlign, _textBaseline: this._textBaseline, _textStyle: this._textStyle, - _textWrap: this._textWrap + _textWrap: this._textWrap, + _colorMode: this._colorMode, + _colorMaxes: this._colorMaxes.slice() } }; } From 9f2b1229dc352b343dd05984fb3ca10f8be41da9 Mon Sep 17 00:00:00 2001 From: omahs <73983677+omahs@users.noreply.github.com> Date: Mon, 3 Mar 2025 15:46:32 +0100 Subject: [PATCH 065/282] Fix typo --- contributor_docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contributor_docs/README.md b/contributor_docs/README.md index 670c00f91f..f48328af37 100644 --- a/contributor_docs/README.md +++ b/contributor_docs/README.md @@ -36,7 +36,7 @@ Head over to [this link](./contributor_guidelines.md) where you will be guided o Most of the time we will stick with this workflow quite strictly and, especially if you have contributed to other projects before, it may feel like there are too many hoops to jump through for what may be a simple contribution. However, the steps above are aimed to make it easy for you as a contributor and for stewards/maintainers to contribute meaningfully, while also making sure that you won't be spending time working on things that may not be accepted for various reasons. The steps above will help ensure that any proposals or fixes are adequately discussed and considered before any work begin, and often this will actually save you (and the steward/maintainer) time because the PR that would need additional fixing after review, or outright not accepted, would happen less often as a result. -**We see contributing to p5.js as a learning opportunity** and we don't measure sucess by only looking at the volume of contributions we received. There is no time limit on how long it takes you to complete a contribution, so take your time and work at your own pace (we may check in after a long period of inactivity). Ask for help from any of the stewards or maintainers if you need them and we'll try our best to support you. For information related to area stewards or general maintenance of p5.js GitHub repository, please check out the [steward guidelines](./steward_guidelines.md). +**We see contributing to p5.js as a learning opportunity** and we don't measure success by only looking at the volume of contributions we received. There is no time limit on how long it takes you to complete a contribution, so take your time and work at your own pace (we may check in after a long period of inactivity). Ask for help from any of the stewards or maintainers if you need them and we'll try our best to support you. For information related to area stewards or general maintenance of p5.js GitHub repository, please check out the [steward guidelines](./steward_guidelines.md). ## Non-source code contribution There are many more ways to contribute to p5.js through non-source code contribution than can be exhaustively listed here. Some of the ways may also involve working with some of the p5.js repositories (such as adding examples, writing tutorials for the website, etc.). Depending on what the planned contribution is, we may be able to support you in different ways so do reach out to us via any channel available to you (email, social media, [Discourse forum](https://discourse.processing.org/c/p5js/10), Discord, etc). Here are just some ways you can contribute: From 2bb956c731de61eb3460a51a2fe3af77a9d77383 Mon Sep 17 00:00:00 2001 From: omahs <73983677+omahs@users.noreply.github.com> Date: Mon, 3 Mar 2025 15:48:22 +0100 Subject: [PATCH 066/282] Fix typos --- contributor_docs/contributing_to_the_p5js_reference.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contributor_docs/contributing_to_the_p5js_reference.md b/contributor_docs/contributing_to_the_p5js_reference.md index 849bfef6bf..770188b8b6 100644 --- a/contributor_docs/contributing_to_the_p5js_reference.md +++ b/contributor_docs/contributing_to_the_p5js_reference.md @@ -117,7 +117,7 @@ If the parameter is optional, add square brackets around the name: ### Additional info: Constants -If the parameter takes one or more values defined in [`constants.js`](https://github.com/processing/p5.js/blob/main/src/core/constants.js) , then the type should be specified as `{Constant}` and the valid values should be enumerated in the comment following the `either` keyword, e.g.: +If the parameter takes one or more values defined in [`constants.js`](https://github.com/processing/p5.js/blob/main/src/core/constants.js), then the type should be specified as `{Constant}` and the valid values should be enumerated in the comment following the `either` keyword, e.g.: ``` @param {Constant} horizAlign horizontal alignment, either LEFT, CENTER, or RIGHT @@ -227,7 +227,7 @@ The relevant `@example` tag to create the above is as follows: After the `@example` tag, you should start an HTML `
` tag followed by a `` tag. In between the opening and closing `` tag, you will insert the relevant example code. The basic principle of writing good example code for the reference is to keep things simple and minimal. The example should be meaningful and explain how the feature works without being too complicated. The example’s canvas should be 100x100 pixels and if the `setup()` function is not included, such as in the example above, the code will be automatically wrapped in a `setup()` function with a default 100x100 pixels gray background canvas created. We won’t go through the details about best practices and code style for the example code here; please see the reference style guide instead. -You can have multiple examples for one feature.To do so, add an additional `
` and `` HTML block right after the first closed, separated by a blank line. +You can have multiple examples for one feature. To do so, add an additional `
` and `` HTML block right after the first closed, separated by a blank line. ``` * @example From 97a6f32960f1a84d3f8d627102d49ef5c180f40c Mon Sep 17 00:00:00 2001 From: omahs <73983677+omahs@users.noreply.github.com> Date: Mon, 3 Mar 2025 15:49:47 +0100 Subject: [PATCH 067/282] Fix typos --- contributor_docs/contributor_guidelines.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contributor_docs/contributor_guidelines.md b/contributor_docs/contributor_guidelines.md index a75a4101f4..84685141db 100644 --- a/contributor_docs/contributor_guidelines.md +++ b/contributor_docs/contributor_guidelines.md @@ -422,7 +422,7 @@ p5.js' code standard or code style is enforced by [ESLlint](https://eslint.org/) While working on any features of p5.js, it is important to keep in mind the design principles of p5.js. Our priorities may differ from the priorities of other projects, so if you are coming from a different project, we recommend that you familiarize yourself with p5.js' design principles. -- **Access** We prioritize accessibility first and foremost, and decisions we make must take into account how it increases access to historically marginalized groups. Read more about this in our access statement. +- **Access** We prioritize accessibility first and foremost, and decisions we make must take into account how they increase access to historically marginalized groups. Read more about this in our access statement. - **Beginner Friendly** The p5.js API aims to be friendly to beginner coders, offering a low barrier to creating interactive and visual web content with cutting-edge HTML5/Canvas/DOM APIs. - **Educational** p5.js is focused on an API and curriculum that supports educational use, including a complete reference to the API with supporting examples, as well as tutorials and sample class curricula that introduce core creative coding principles in a clear and engaging order. - **JavaScript and its community** p5.js aims to make web development practices more accessible to beginners by modeling proper JavaScript design patterns and usage while abstracting them where necessary. As an open-source library, p5.js also includes the wider JavaScript community in its creation, documentation, and dissemination. From 9503662b58fe7017cded2f9e87ec9f8ccc2a58ad Mon Sep 17 00:00:00 2001 From: omahs <73983677+omahs@users.noreply.github.com> Date: Mon, 3 Mar 2025 15:50:38 +0100 Subject: [PATCH 068/282] Fix typo --- contributor_docs/creating_libraries.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contributor_docs/creating_libraries.md b/contributor_docs/creating_libraries.md index 0ee2c04539..a7f2caa2ae 100644 --- a/contributor_docs/creating_libraries.md +++ b/contributor_docs/creating_libraries.md @@ -279,7 +279,7 @@ Your addon library may not extend p5 or p5 classes at all, but instead just offe **p5.js has two modes, global mode and instance mode.** In global mode, all p5 properties and methods are bound to the `window` object, allowing users to call methods like `background()` without having to prefix them with anything. However, this means you need to be careful not to overwrite native JavaScript functionality. For example “`Math`” and “`console`” are both native Javascript functionalities so you shouldn’t have methods named “`Math`” or “`console`”. -**Class names should use** `PascalCase`**, while methods and properties should use** `camelCase`**.** Classes in p5 are prefixed with p5. We would like to keep this namespace for p5 core classes only, so when you create your own namespace, **do not include the** `p5.` **prefix for class names**. You are welcomed to create your own prefix, or just give them non-prefixed names. +**Class names should use** `PascalCase`**, while methods and properties should use** `camelCase`**.** Classes in p5 are prefixed with p5. We would like to keep this namespace for p5 core classes only, so when you create your own namespace, **do not include the** `p5.` **prefix for class names**. You are welcome to create your own prefix, or just give them non-prefixed names. ```js // Do not do this @@ -307,4 +307,4 @@ p5.prototype.myMethod = function(){ **Examples are great, too!** They show people what your library can do. Because this is all JavaScript, people can see them running online before they download anything.[ ](http://jsfiddle.net/) You can create a collection of examples on the p5.js web editor to showcase how your library works. -**Submit your library!** Once your library is ready for distribution and you’d like it included on the [p5js.org/libraries](https://p5js.org/libraries) page, please submit a pull request on the p5.js website GitHub repository following [this intruction](https://github.com/processing/p5.js-website/blob/main/docs/contributing_libraries.md)! \ No newline at end of file +**Submit your library!** Once your library is ready for distribution and you’d like it included on the [p5js.org/libraries](https://p5js.org/libraries) page, please submit a pull request on the p5.js website GitHub repository following [this intruction](https://github.com/processing/p5.js-website/blob/main/docs/contributing_libraries.md)! From 42c48db4c28841e44a32516fc4b99c32b7429f9c Mon Sep 17 00:00:00 2001 From: omahs <73983677+omahs@users.noreply.github.com> Date: Mon, 3 Mar 2025 15:51:57 +0100 Subject: [PATCH 069/282] Fix typos --- contributor_docs/documentation_style_guide.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contributor_docs/documentation_style_guide.md b/contributor_docs/documentation_style_guide.md index 8e42b45116..be6a48ddda 100644 --- a/contributor_docs/documentation_style_guide.md +++ b/contributor_docs/documentation_style_guide.md @@ -140,7 +140,7 @@ Always use `let` to declare variables. **Accessibility terminology** -The following terminiology is adapted from the WordPress documentation guidelines for [Writing inclusive documentation](https://make.wordpress.org/docs/style-guide/general-guidelines/inclusivity/#accessibility-terminology). For more background on people-first language, see the CDC's guide on [Communicating With and About People with Disabilities](https://www.cdc.gov/ncbddd/disabilityandhealth/materials/factsheets/fs-communicating-with-people.html). +The following terminology is adapted from the WordPress documentation guidelines for [Writing inclusive documentation](https://make.wordpress.org/docs/style-guide/general-guidelines/inclusivity/#accessibility-terminology). For more background on people-first language, see the CDC's guide on [Communicating With and About People with Disabilities](https://www.cdc.gov/ncbddd/disabilityandhealth/materials/factsheets/fs-communicating-with-people.html). | Recommended | Not Recommended | | -- | -- | @@ -713,7 +713,7 @@ if ( ## Iteration -- Don’t use a `while` or `do-while` loops unless it's necessary. Use `for` loops to iterate a fixed number of times. +- Don’t use `while` or `do-while` loops unless it's necessary. Use `for` loops to iterate a fixed number of times. ```javascript let numPetals = 7; @@ -896,7 +896,7 @@ for (let i = 0; i < numbers.length; i += 1) { let numbersCopy = numbers.slice(); ``` -- Write arrays on multiple lines when it improves readibility. Use line breaks after the opening bracket and before the closing bracket. Add a trailing comma. +- Write arrays on multiple lines when it improves readability. Use line breaks after the opening bracket and before the closing bracket. Add a trailing comma. ```javascript // Bad. From 0b268374a31a57943a76c0838aa8fd61ed6795c5 Mon Sep 17 00:00:00 2001 From: omahs <73983677+omahs@users.noreply.github.com> Date: Mon, 3 Mar 2025 15:52:58 +0100 Subject: [PATCH 070/282] Fix typo --- contributor_docs/friendly_error_system.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contributor_docs/friendly_error_system.md b/contributor_docs/friendly_error_system.md index c237cbcf40..185f9f1448 100644 --- a/contributor_docs/friendly_error_system.md +++ b/contributor_docs/friendly_error_system.md @@ -74,7 +74,7 @@ The basic format of a translation file's item has a key and a value (message) in ```json { "key": "value" } ``` -For example, we have a ASCII logo saved in this format: +For example, we have an ASCII logo saved in this format: ```json "logo": " _ \n /\\| |/\\ \n \\ ` ' / \n / , . \\ \n \\/|_|\\/ \n\n" ``` From 5ec80a3af57e0b7be666d4f733b6ee5c79c6da9a Mon Sep 17 00:00:00 2001 From: omahs <73983677+omahs@users.noreply.github.com> Date: Mon, 3 Mar 2025 15:54:21 +0100 Subject: [PATCH 071/282] Fix typos --- contributor_docs/method.example.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contributor_docs/method.example.js b/contributor_docs/method.example.js index fcc6c82583..67c4e0fb96 100644 --- a/contributor_docs/method.example.js +++ b/contributor_docs/method.example.js @@ -2,7 +2,7 @@ * "This is a template for inline documentation of a method. Remove all text * between double quotes for using this template. Some description about the * method goes here. Explain in simple words, what the function does and what - * would be good/bad use cases for it. If there are any corners cases or warnings, + * would be good/bad use cases for it. If there are any corner cases or warnings, * do explain them over here." * * By default, the background is transparent. @@ -32,8 +32,8 @@ * "A single line precisely describing the second example" */ -// "If your method has more than one signatures, they can be documentated each -// in their own block with description about their parameters as follows." +// "If your method has more than one signature, they can be documented each +// in their own block with description of their parameters as follows." /** * @method "methodName" * @param {"dataType"} "paramName" "Description of the param" From 7586e5c56cbca04c013fcff5ff37ad334a3bf1f1 Mon Sep 17 00:00:00 2001 From: omahs <73983677+omahs@users.noreply.github.com> Date: Mon, 3 Mar 2025 15:55:22 +0100 Subject: [PATCH 072/282] Fix typo --- contributor_docs/release_process.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contributor_docs/release_process.md b/contributor_docs/release_process.md index b2490e6c75..6c42a5575d 100644 --- a/contributor_docs/release_process.md +++ b/contributor_docs/release_process.md @@ -62,7 +62,7 @@ Once triggered, it will run the following steps: In principle, we try to concentrate as many steps as possible to be run in one place, ie. in the CI environment. If a new step that is only run on release is required, it should probably be defined in the CI workflow and not as part of the build configuration. ## Testing -As the release steps are run in CI, testing them can be difficult. Using [act](https://github.com/nektos/act) to test running of the steps locally is possible (and was how they were tested while being developed) but require some temporary modifications to the workflow definition, we'll roughly document here as the precise steps will likely change over time. +As the release steps are run in CI, testing them can be difficult. Using [act](https://github.com/nektos/act) to test running of the steps locally is possible (and was how they were tested while being developed) but requires some temporary modifications to the workflow definition, we'll roughly document here as the precise steps will likely change over time. The test steps will not run because not all system requirements are present to run the mocha Chrome tests. Some system dependencies will likely be needed to be installed with `apt` before setting up the rest of the environment. Keep an eye on the error messages which should give some information on what packages are missing. From 923f95f3c360549ba0ba2630c0cd3b1f595cde86 Mon Sep 17 00:00:00 2001 From: omahs <73983677+omahs@users.noreply.github.com> Date: Mon, 3 Mar 2025 15:57:43 +0100 Subject: [PATCH 073/282] Fix typos --- contributor_docs/steward_guidelines.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contributor_docs/steward_guidelines.md b/contributor_docs/steward_guidelines.md index 466fb9888b..98cbdbebdc 100644 --- a/contributor_docs/steward_guidelines.md +++ b/contributor_docs/steward_guidelines.md @@ -74,12 +74,12 @@ Feature request issues should use the "New Feature Request" issue template. The - Does the feature fit into the project scope and [design principles](./contributor_guidelines.md#software-design-principles) of p5.js? - For example, a request to add a new drawing primitive shape may be considered, but a request to adopt a browser-based IOT protocol will likely be out of scope. - Overall, the scope of p5.js should be relatively narrow in order to avoid excessive bloat from rarely used features. - - If a feature does not fit into the scope of p5.js, suggest that the issue author implement the feature as as an addon library. + - If a feature does not fit into the scope of p5.js, suggest that the issue author implement the feature as an addon library. - If it is unclear whether or not it fits, it can be a good idea to suggest making an addon library as a proof-of-concept. This helps give users a way to use the feature, provides a much more concrete example of its usage and importance, and does not necessarily need to be as complete of a solution as a fully integrated feature. It can be integrated into the core of p5.js later if appropriate. - Is the feature likely to cause a breaking change? - Will it conflict with existing p5.js functions and variables? - Will it conflict with typical sketches already written for p5.js? - - Features that are likely to cause conflicts such as the ones above are considered breaking changes. Without a [major version release](https://docs.npmjs.com/about-semantic-versioning), we should not make breaking changes to p5.js. + - Features that are likely to cause conflicts such as the ones above are considered breaking changes. Without a [major version release](https://docs.npmjs.com/about-semantic-versioning), we should not make breaking changes to p5.js. - Can the proposed new feature be achieved using existing functionalities already in p5.js, relatively simple native JavaScript code, or existing easy-to-use libraries? - For example, instead of providing a p5.js function to join an array of strings such as `join(["Hello", "world!"])`, the native JavaScript `["Hello", "world!"].join()` should be preferred instead. 3. If the access requirement and other considerations have been fulfilled, at least two stewards or maintainers must approve the new feature request before work should begin toward a PR. The PR review process for new features is documented below. @@ -119,7 +119,7 @@ Almost all code contributions to the p5.js repositories happen through pull requ ### Simple fix -Simple fixes, such as a small typo fix, can be merged directly by anyone with merge access. Check on the PR "Files Changed" tab to ensure that the automated CI test passes. +Simple fixes, such as a small typo fix, can be merged directly by anyone with merge access. Check on the PR "Files Changed" tab to ensure that the automated CI test passes. ![The "files changed" tab when viewing a pull request on GitHub](images/files-changed.png) @@ -223,7 +223,7 @@ grunt.registerTask('build', [ ]); ``` -Tasks that start with `browserify` are defined in [../tasks/build/browserify.js](../tasks/build/browserify.js). They all similar steps with minor differences. These are the main steps to build the full p5.js library from its many source code files into one: +Tasks that start with `browserify` are defined in [../tasks/build/browserify.js](../tasks/build/browserify.js). They all have similar steps with minor differences. These are the main steps to build the full p5.js library from its many source code files into one: - `browserify` builds p5.js while `browserify:min` builds an intermediate file to be minified in the next step. The difference between `browserify` and `browserify:min` is that `browserify:min` does not contain data needed for FES to function. - `uglify` takes the output file of `browserify:min` and minify it into the final p5.min.js (configuration of this step is in the main Gruntfile.js). From 2a0db63409953a96a5c4caa57da210b36fe15249 Mon Sep 17 00:00:00 2001 From: omahs <73983677+omahs@users.noreply.github.com> Date: Mon, 3 Mar 2025 16:01:21 +0100 Subject: [PATCH 074/282] Fix typos --- .../addons/p5.sound/Filter_LowPass/sketch.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/manual-test-examples/addons/p5.sound/Filter_LowPass/sketch.js b/test/manual-test-examples/addons/p5.sound/Filter_LowPass/sketch.js index b5d26913bd..1be305a3ce 100644 --- a/test/manual-test-examples/addons/p5.sound/Filter_LowPass/sketch.js +++ b/test/manual-test-examples/addons/p5.sound/Filter_LowPass/sketch.js @@ -1,8 +1,8 @@ /** * Example: Apply a p5.LowPass filter to a p5.SoundFile. * Visualize the sound with FFT. - * Map mouseX to the the filter's cutoff frequency - * and mouseY to resonance/width of the a BandPass filter + * Map mouseX to the filter's cutoff frequency + * and mouseY to resonance/width of the BandPass filter */ var soundFile; @@ -44,7 +44,7 @@ function setup() { function draw() { background(30); - // Map mouseX to a the cutoff frequency for our lowpass filter + // Map mouseX to the cutoff frequency for our lowpass filter filterFreq = map(mouseX, 0, width, 10, 22050); // Map mouseY to resonance/width filterRes = map(mouseY, 0, height, 15, 5); From 1b6cf46099de53657dcbf263887bcab95a584e0a Mon Sep 17 00:00:00 2001 From: omahs <73983677+omahs@users.noreply.github.com> Date: Mon, 3 Mar 2025 16:02:46 +0100 Subject: [PATCH 075/282] Fix typo --- contributor_docs/how-to-add-friendly-error-messages.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contributor_docs/how-to-add-friendly-error-messages.md b/contributor_docs/how-to-add-friendly-error-messages.md index 4b945c899d..7fc37ce499 100644 --- a/contributor_docs/how-to-add-friendly-error-messages.md +++ b/contributor_docs/how-to-add-friendly-error-messages.md @@ -163,7 +163,7 @@ Next, you will file an issue ticket to discuss creating a new case or confirm yo Go to the [issue board](https://github.com/processing/p5.js/issues), press the "New Issue" button, and then choose the "Issue: 💡 Existing Feature Enhancement" option. An empty form should appear. -Add a title along the lines of “Adding a new case to `fileLoadErrrorCases`: \[a high-level description of your file load error case].” For the “Increasing access” section, enter a short paragraph on the typical scenario you prepared at the beginning of this step. +Add a title along the lines of “Adding a new case to `fileLoadErrorCases`: \[a high-level description of your file load error case].” For the “Increasing access” section, enter a short paragraph on the typical scenario you prepared at the beginning of this step. Then, check the “Friendly Errors” box for the “Most appropriate sub-area of p5.js?” question. Lastly, for the “Feature enhancement details” section, enter your paragraph detailing your error handling and what file types it loads. From ff0143f68ac3cb0c0eda4e22fd40559b8c59f9b1 Mon Sep 17 00:00:00 2001 From: SITADRITA1 Date: Mon, 3 Mar 2025 22:51:17 +0100 Subject: [PATCH 076/282] Update first-timers.yml --- .github/first-timers.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/first-timers.yml b/.github/first-timers.yml index d6c563c778..5e57720264 100644 --- a/.github/first-timers.yml +++ b/.github/first-timers.yml @@ -1,4 +1,4 @@ -# You can create the issue in a different repo than where the problem is. Just make sure you installed the bot on the configured repository. +# You can create the issue in a different repo than where the problem is. Just make sure you have installed the bot on the configured repository. # The issue will link back to the original repository where the contribution will be made. repository: p5.js @@ -11,4 +11,4 @@ labels: - hacktoberfest # If you would like to add your own template for the issue, add an .md file to your .github folder -# template: .github/first-timers-issue-template.md \ No newline at end of file +# template: .github/first-timers-issue-template.md From fedddf37004d2835ed8ef7fb05f4b21a18623fb3 Mon Sep 17 00:00:00 2001 From: SITADRITA1 Date: Mon, 3 Mar 2025 23:00:43 +0100 Subject: [PATCH 077/282] Update es6-adoption.md --- contributor_docs/archive/es6-adoption.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contributor_docs/archive/es6-adoption.md b/contributor_docs/archive/es6-adoption.md index 4beb93e0f2..76b5ca3e4a 100644 --- a/contributor_docs/archive/es6-adoption.md +++ b/contributor_docs/archive/es6-adoption.md @@ -1,7 +1,7 @@ ## ES6 Adoption p5.js has recently adopted the ECMAScript 2015 (ES6) language specifications in order to reduce the complexity of the codebase, increase readability, and utilize features that facilitate elegant and effective coding practices for both newcomers and seasoned contributors. -The transition process was initially [discussed](https://github.com/processing/p5.js/issues/3758) with the aim of migrating p5 to ES6, which later lead to a series of widespread syntactical changes in the codebase aligned with ES6 specifications. More info on the initial transition can be found [here](https://github.com/processing/p5.js/pull/3874). These changes consisted of minor modifications to the build system to facilitate processing, linting and testing the library based on ES6 standards, as well as major and ubiquitous syntactical modification in line with ES6 features. +The transition process was initially [discussed](https://github.com/processing/p5.js/issues/3758) with the aim of migrating p5 to ES6, which later led to a series of widespread syntactical changes in the codebase aligned with ES6 specifications. More info on the initial transition can be found [here](https://github.com/processing/p5.js/pull/3874). These changes consisted of minor modifications to the build system to facilitate processing, linting and testing the library based on ES6 standards, as well as major and ubiquitous syntactical modification in line with ES6 features. It is worthy to note that as of writing this, these transformations are by no means complete, and do not reflect nor implement every possible feature of ES6. They are intended to facilitate a smoother transition to properly and efficiently utilize ES6 features if and when aligned with the community interests and standards. And serve to motivate contributors to gradually conform to the new style and features. From c1fb8cad2ad8161bf044240a7384266cd20997a0 Mon Sep 17 00:00:00 2001 From: SITADRITA1 Date: Mon, 3 Mar 2025 23:36:48 +0100 Subject: [PATCH 078/282] Update README.md --- src/core/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/README.md b/src/core/README.md index 49f5e3cadf..7dad604622 100644 --- a/src/core/README.md +++ b/src/core/README.md @@ -55,7 +55,7 @@ The `rendering.js` module presents the user-facing API for p5's various graphica ## [p5.Renderer.js](./p5.Renderer.js) -The `p5.Renderer.js` module provides a common base definition for a p5 project output mode that can then be extended as with [p5.Renderer2D](./p5.Renderer2D.js). For three dimensional output, see the [webgl module](../webgl/). Each `p5` object instance typically has a `Renderer` attached as a property. +The `p5.Renderer.js` module provides a common base definition for a p5 project output mode that can then be extended as with [p5.Renderer2D](./p5.Renderer2D.js). For three-dimensional output, see the [webgl module](../webgl/). Each `p5` object instance typically has a `Renderer` attached as a property. ## [p5.Renderer2D.js](./p5.Renderer2D.js) From fcae9749ed323cc6d1ab4f2bc9cb807529a7fff0 Mon Sep 17 00:00:00 2001 From: FORCHA PEARL Date: Tue, 4 Mar 2025 13:02:18 +0100 Subject: [PATCH 079/282] Fix camera tilt function to prevent orientation flipping --- src/webgl/p5.Camera.js | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/webgl/p5.Camera.js b/src/webgl/p5.Camera.js index 1fb6c5012d..b1a7dab6b5 100644 --- a/src/webgl/p5.Camera.js +++ b/src/webgl/p5.Camera.js @@ -2448,6 +2448,18 @@ p5.Camera = class Camera { rotatedCenter[1] += this.eyeY; rotatedCenter[2] += this.eyeZ; + // Compute new up vector to prevent flipping + let forward = createVector( + rotatedCenter[0] - this.eyeX, + rotatedCenter[1] - this.eyeY, + rotatedCenter[2] - this.eyeZ + ).normalize(); + + let up = createVector(this.upX, this.upY, this.upZ); + let right = p5.Vector.cross(forward, up).normalize(); // Right vector + up = p5.Vector.cross(right, forward).normalize(); // Corrected up vector + + this.camera( this.eyeX, this.eyeY, @@ -2455,10 +2467,15 @@ p5.Camera = class Camera { rotatedCenter[0], rotatedCenter[1], rotatedCenter[2], - this.upX, - this.upY, - this.upZ + this.up.x, + this.up.y, + this.up.z ); + + // Update up vector + this.upX = up.x; + this.upY = up.y; + this.upZ = up.z; } /** From daf96429e78e0b4fc67a5247c26c52493ab5a194 Mon Sep 17 00:00:00 2001 From: FORCHA PEARL Date: Tue, 4 Mar 2025 13:06:37 +0100 Subject: [PATCH 080/282] Fixed indentation error --- src/webgl/p5.Camera.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/webgl/p5.Camera.js b/src/webgl/p5.Camera.js index b1a7dab6b5..71ca357e38 100644 --- a/src/webgl/p5.Camera.js +++ b/src/webgl/p5.Camera.js @@ -2450,9 +2450,9 @@ p5.Camera = class Camera { // Compute new up vector to prevent flipping let forward = createVector( - rotatedCenter[0] - this.eyeX, - rotatedCenter[1] - this.eyeY, - rotatedCenter[2] - this.eyeZ + rotatedCenter[0] - this.eyeX, + rotatedCenter[1] - this.eyeY, + rotatedCenter[2] - this.eyeZ ).normalize(); let up = createVector(this.upX, this.upY, this.upZ); From 2128bfc361f0793a8c1961b34ed27be8b3a080d3 Mon Sep 17 00:00:00 2001 From: FORCHA PEARL Date: Tue, 4 Mar 2025 13:09:04 +0100 Subject: [PATCH 081/282] fixed lint --- src/webgl/p5.Camera.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/webgl/p5.Camera.js b/src/webgl/p5.Camera.js index 71ca357e38..3de5e905dc 100644 --- a/src/webgl/p5.Camera.js +++ b/src/webgl/p5.Camera.js @@ -2459,7 +2459,6 @@ p5.Camera = class Camera { let right = p5.Vector.cross(forward, up).normalize(); // Right vector up = p5.Vector.cross(right, forward).normalize(); // Corrected up vector - this.camera( this.eyeX, this.eyeY, From 961dc63a7a2352cacb4b0958a97d4f0b5716b563 Mon Sep 17 00:00:00 2001 From: FORCHA PEARL Date: Tue, 4 Mar 2025 13:11:08 +0100 Subject: [PATCH 082/282] fixed lint --- src/webgl/p5.Camera.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webgl/p5.Camera.js b/src/webgl/p5.Camera.js index 3de5e905dc..00e8a7dad1 100644 --- a/src/webgl/p5.Camera.js +++ b/src/webgl/p5.Camera.js @@ -2458,7 +2458,7 @@ p5.Camera = class Camera { let up = createVector(this.upX, this.upY, this.upZ); let right = p5.Vector.cross(forward, up).normalize(); // Right vector up = p5.Vector.cross(right, forward).normalize(); // Corrected up vector - + this.camera( this.eyeX, this.eyeY, From 7841fe92bf34aa4422cbe0f9b0cd9b8b8ef096fe Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 5 Mar 2025 20:46:49 +0000 Subject: [PATCH 083/282] docs: update README.md [skip ci] --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index cd05598fc4..13cfc26f50 100644 --- a/README.md +++ b/README.md @@ -1110,6 +1110,9 @@ We recognize all types of contributions. This project follows the [all-contribut Greg Stanton
Greg Stanton

🐛 💻 📖 💡 🤔 🔌 📆 📣 💬 🔬 Bojidar Marinov
Bojidar Marinov

💻 ⚠️ + + Mayank Verma
Mayank Verma

💻 + From 75d7649c3862c7f94754d30cd8aba7e5bb1dae33 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 5 Mar 2025 20:46:50 +0000 Subject: [PATCH 084/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 09d746fc96..49ab6d1ef4 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6692,6 +6692,15 @@ "code", "test" ] + }, + { + "login": "webermayank", + "name": "Mayank Verma", + "avatar_url": "https://avatars.githubusercontent.com/u/111176033?v=4", + "profile": "https://github.com/webermayank", + "contributions": [ + "code" + ] } ], "repoType": "github", From ef5749727f6a32e1c94cc9132415166664c19e9e Mon Sep 17 00:00:00 2001 From: FORCHA PEARL Date: Fri, 7 Mar 2025 04:20:25 +0100 Subject: [PATCH 085/282] removed closepath from beizer curve to last condition --- src/core/p5.Renderer2D.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/p5.Renderer2D.js b/src/core/p5.Renderer2D.js index 91944eaf07..3fec8efec2 100644 --- a/src/core/p5.Renderer2D.js +++ b/src/core/p5.Renderer2D.js @@ -855,7 +855,6 @@ class Renderer2D extends p5.Renderer { this.drawingContext.lineTo(vertices[i + 1][0], vertices[i + 1][1]); } this._doFillStrokeClose(closeShape); - this.drawingContext.closePath(); } } else if ( isBezier && @@ -1053,6 +1052,7 @@ class Renderer2D extends p5.Renderer { } } this._doFillStrokeClose(closeShape); + this.drawingContext.closePath(); } } isCurve = false; From ee20bb5c0ddea0ea2d9b87f20e87abdfe1bf893b Mon Sep 17 00:00:00 2001 From: FORCHA PEARL Date: Fri, 7 Mar 2025 04:30:35 +0100 Subject: [PATCH 086/282] fixed lint --- src/core/p5.Renderer2D.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/p5.Renderer2D.js b/src/core/p5.Renderer2D.js index 3fec8efec2..85d3ac7009 100644 --- a/src/core/p5.Renderer2D.js +++ b/src/core/p5.Renderer2D.js @@ -1052,7 +1052,7 @@ class Renderer2D extends p5.Renderer { } } this._doFillStrokeClose(closeShape); - this.drawingContext.closePath(); + this.drawingContext.closePath(); } } isCurve = false; From 44728d346459be17a0bbb15f0893a0230d2f6114 Mon Sep 17 00:00:00 2001 From: swastikCommits Date: Sun, 9 Mar 2025 07:18:47 +0530 Subject: [PATCH 087/282] fix: mouseWheel example fixed while drawing the circle --- src/events/mouse.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/events/mouse.js b/src/events/mouse.js index c36bdf4ffc..0f3985a2db 100644 --- a/src/events/mouse.js +++ b/src/events/mouse.js @@ -1802,7 +1802,7 @@ p5.prototype._pmouseWheelDeltaY = 0; * background(200); * * // Draw the circle - * circle(circleSize, 50, 50); + * circle(50, 50, circleSize); * } * * // Increment circleSize when the user scrolls the mouse wheel. From e30b51b71f37abbddc14940491e7beb6ac66105d Mon Sep 17 00:00:00 2001 From: himanshuukholiya Date: Thu, 13 Mar 2025 11:48:37 +0530 Subject: [PATCH 088/282] Fix offscreen error by skipping invalid locations processing#7259 --- src/accessibility/outputs.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/accessibility/outputs.js b/src/accessibility/outputs.js index 4cdb308c27..1680f18e31 100644 --- a/src/accessibility/outputs.js +++ b/src/accessibility/outputs.js @@ -579,8 +579,13 @@ p5.prototype._getPos = function (x, y) { function _canvasLocator(args, canvasWidth, canvasHeight) { const noRows = 10; const noCols = 10; - let locX = Math.floor(args[0] / canvasWidth * noRows); - let locY = Math.floor(args[1] / canvasHeight * noCols); + let x = args[0]; + let y = args[1]; + if (x < 0 || x >= canvasWidth || y < 0 || y >= canvasHeight) { + return null; + } + let locX = Math.floor(x / canvasWidth * noRows); + let locY = Math.floor(y / canvasHeight * noCols); if (locX === noRows) { locX = locX - 1; } From 3602699074bce0d540ec23a9dddf61eb530e4a08 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 13 Mar 2025 07:31:52 +0000 Subject: [PATCH 089/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 13cfc26f50..8a83386920 100644 --- a/README.md +++ b/README.md @@ -1112,6 +1112,7 @@ We recognize all types of contributions. This project follows the [all-contribut Mayank Verma
Mayank Verma

💻 + Himanshu Kholiya
Himanshu Kholiya

💻 From 9eb7f172e396fdf5e0d6a34ac329a79af0929b33 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 13 Mar 2025 07:31:53 +0000 Subject: [PATCH 090/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 49ab6d1ef4..21950b787b 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6701,6 +6701,15 @@ "contributions": [ "code" ] + }, + { + "login": "himanshuukholiya", + "name": "Himanshu Kholiya", + "avatar_url": "https://avatars.githubusercontent.com/u/128818464?v=4", + "profile": "https://github.com/himanshuukholiya", + "contributions": [ + "code" + ] } ], "repoType": "github", From 1ac8e4382d46715c0ed5cba697aaaf6053fa36d6 Mon Sep 17 00:00:00 2001 From: FORCHA PEARL Date: Thu, 13 Mar 2025 09:49:13 +0100 Subject: [PATCH 091/282] removed create vector error --- src/webgl/p5.Camera.js | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/src/webgl/p5.Camera.js b/src/webgl/p5.Camera.js index 00e8a7dad1..44be60d048 100644 --- a/src/webgl/p5.Camera.js +++ b/src/webgl/p5.Camera.js @@ -2435,6 +2435,7 @@ p5.Camera = class Camera { const rotation = p5.Matrix.identity(this._renderer._pInst); rotation.rotate(this._renderer._pInst._toRadians(a), x, y, z); + // Apply the rotation matrix to the center vector /* eslint-disable max-len */ const rotatedCenter = [ centerX * rotation.mat4[0] + centerY * rotation.mat4[4] + centerZ * rotation.mat4[8], @@ -2443,21 +2444,17 @@ p5.Camera = class Camera { ]; /* eslint-enable max-len */ - // add eye position back into center + // Translate the rotated center back to world coordinates rotatedCenter[0] += this.eyeX; rotatedCenter[1] += this.eyeY; rotatedCenter[2] += this.eyeZ; - // Compute new up vector to prevent flipping - let forward = createVector( - rotatedCenter[0] - this.eyeX, - rotatedCenter[1] - this.eyeY, - rotatedCenter[2] - this.eyeZ - ).normalize(); - - let up = createVector(this.upX, this.upY, this.upZ); - let right = p5.Vector.cross(forward, up).normalize(); // Right vector - up = p5.Vector.cross(right, forward).normalize(); // Corrected up vector + // Rotate the up vector to keep the correct camera orientation + /* eslint-disable max-len */ + const upX = this.upX * rotation.mat4[0] + this.upY * rotation.mat4[4] + this.upZ * rotation.mat4[8]; + const upY = this.upX * rotation.mat4[1] + this.upY * rotation.mat4[5] + this.upZ * rotation.mat4[9]; + const upZ = this.upX * rotation.mat4[2] + this.upY * rotation.mat4[6] + this.upZ * rotation.mat4[10]; + /* eslint-enable max-len */ this.camera( this.eyeX, @@ -2466,15 +2463,10 @@ p5.Camera = class Camera { rotatedCenter[0], rotatedCenter[1], rotatedCenter[2], - this.up.x, - this.up.y, - this.up.z + upX, + upY, + upZ ); - - // Update up vector - this.upX = up.x; - this.upY = up.y; - this.upZ = up.z; } /** From 9d2ba57145482ecf4c899bf7b238aaa54aefc1dc Mon Sep 17 00:00:00 2001 From: FORCHA PEARL Date: Thu, 13 Mar 2025 10:38:59 +0100 Subject: [PATCH 092/282] added test on up vector tilt --- test/unit/webgl/p5.Camera.js | 55 ++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/test/unit/webgl/p5.Camera.js b/test/unit/webgl/p5.Camera.js index b746a5053e..89b7bd545c 100644 --- a/test/unit/webgl/p5.Camera.js +++ b/test/unit/webgl/p5.Camera.js @@ -277,6 +277,61 @@ suite('p5.Camera', function() { assert.strictEqual(myCam.upY, orig.uy, 'up Y pos changed'); assert.strictEqual(myCam.upZ, orig.uz, 'up Z pos changed'); }); + + suite('Camera Tilt and Up Vector', function() { + test('Tilt() correctly updates the up vector', function() { + var orig = getVals(myCam); // Store original camera values + + // Apply tilt to the camera + myCam.tilt(30); // Tilt by 30 degrees + + // Compute expected up vector (normalized) + let forward = myp5.createVector( + myCam.centerX - myCam.eyeX, + myCam.centerY - myCam.eyeY, + myCam.centerZ - myCam.eyeZ + ); + let up = myp5.createVector(orig.ux, orig.uy, orig.uz); + let right = p5.Vector.cross(forward, up); + let expectedUp = p5.Vector.cross(right, forward).normalize(); + + // Verify that the up vector has changed + assert.notStrictEqual(myCam.upX, orig.ux, 'upX should be updated'); + assert.notStrictEqual(myCam.upY, orig.uy, 'upY should be updated'); + assert.notStrictEqual(myCam.upZ, orig.uz, 'upZ should be updated'); + + // Verify up vector matches expected values within a small margin of error + assert.closeTo(myCam.upX, expectedUp.x, 0.001, 'upX mismatch'); + assert.closeTo(myCam.upY, expectedUp.y, 0.001, 'upY mismatch'); + assert.closeTo(myCam.upZ, expectedUp.z, 0.001, 'upZ mismatch'); + }); + + test('Tilt() with negative angle correctly updates the up vector', function() { + var orig = getVals(myCam); // Store original camera values + + myCam.tilt(-30); // Tilt by -30 degrees + + // Compute expected up vector (normalized) + let forward = myp5.createVector( + myCam.centerX - myCam.eyeX, + myCam.centerY - myCam.eyeY, + myCam.centerZ - myCam.eyeZ + ); + let up = myp5.createVector(orig.ux, orig.uy, orig.uz); + let right = p5.Vector.cross(forward, up); + let expectedUp = p5.Vector.cross(right, forward).normalize(); + + // Verify that the up vector has changed + assert.notStrictEqual(myCam.upX, orig.ux, 'upX should be updated'); + assert.notStrictEqual(myCam.upY, orig.uy, 'upY should be updated'); + assert.notStrictEqual(myCam.upZ, orig.uz, 'upZ should be updated'); + + // Verify up vector matches expected values within a small margin of error + assert.closeTo(myCam.upX, expectedUp.x, 0.001, 'upX mismatch'); + assert.closeTo(myCam.upY, expectedUp.y, 0.001, 'upY mismatch'); + assert.closeTo(myCam.upZ, expectedUp.z, 0.001, 'upZ mismatch'); + }); + }); }); suite('Rotation with angleMode(DEGREES)', function() { From 870804cf307dba7d48145b75f4c489cec9739756 Mon Sep 17 00:00:00 2001 From: FORCHA PEARL Date: Thu, 13 Mar 2025 10:40:40 +0100 Subject: [PATCH 093/282] removed trailing spaces --- test/unit/webgl/p5.Camera.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/webgl/p5.Camera.js b/test/unit/webgl/p5.Camera.js index 89b7bd545c..1047b6d4e1 100644 --- a/test/unit/webgl/p5.Camera.js +++ b/test/unit/webgl/p5.Camera.js @@ -331,7 +331,7 @@ suite('p5.Camera', function() { assert.closeTo(myCam.upY, expectedUp.y, 0.001, 'upY mismatch'); assert.closeTo(myCam.upZ, expectedUp.z, 0.001, 'upZ mismatch'); }); - }); + }); }); suite('Rotation with angleMode(DEGREES)', function() { From e40d7ef59810d3cb44fda929c67b97d646267786 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sat, 15 Mar 2025 19:02:27 +0000 Subject: [PATCH 094/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 13cfc26f50..752abab6f5 100644 --- a/README.md +++ b/README.md @@ -1112,6 +1112,7 @@ We recognize all types of contributions. This project follows the [all-contribut Mayank Verma
Mayank Verma

💻 + mclark414
mclark414

🤔 From 7fefa2df55e9af4b35bd8cc7a06ad6467276f83e Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sat, 15 Mar 2025 19:02:28 +0000 Subject: [PATCH 095/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 49ab6d1ef4..1b5d5983a9 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6701,6 +6701,15 @@ "contributions": [ "code" ] + }, + { + "login": "mclark414", + "name": "mclark414", + "avatar_url": "https://avatars.githubusercontent.com/u/26391144?v=4", + "profile": "https://github.com/mclark414", + "contributions": [ + "ideas" + ] } ], "repoType": "github", From 8f4192bd040dc1c74a223294db7b4fbc45ea703b Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sat, 15 Mar 2025 19:03:04 +0000 Subject: [PATCH 096/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 13cfc26f50..4601a46dd0 100644 --- a/README.md +++ b/README.md @@ -1112,6 +1112,7 @@ We recognize all types of contributions. This project follows the [all-contribut Mayank Verma
Mayank Verma

💻 + Jackie Liu
Jackie Liu

🤔 From 611d380dc78e70558af309205f10add900366dfb Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sat, 15 Mar 2025 19:03:05 +0000 Subject: [PATCH 097/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 49ab6d1ef4..5fb742f26f 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6701,6 +6701,15 @@ "contributions": [ "code" ] + }, + { + "login": "jlliu", + "name": "Jackie Liu", + "avatar_url": "https://avatars.githubusercontent.com/u/8304517?v=4", + "profile": "https://github.com/jlliu", + "contributions": [ + "ideas" + ] } ], "repoType": "github", From 1d8c2e0bb096c70746a490b71366162b74c1989f Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sat, 15 Mar 2025 19:03:08 +0000 Subject: [PATCH 098/282] docs: update README.md [skip ci] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 13cfc26f50..6830c764f1 100644 --- a/README.md +++ b/README.md @@ -1044,7 +1044,7 @@ We recognize all types of contributions. This project follows the [all-contribut c-dacanay
c-dacanay

🎨 📋 💡 mathewpan2
mathewpan2

💻 cog25
cog25

🌍 - Aarati Akkapeddi
Aarati Akkapeddi

💻 + Aarati Akkapeddi
Aarati Akkapeddi

💻 🤔 Maya Arguelles
Maya Arguelles

💻 From e70e6755641bc402f1116e3611a8b36d534e9a4f Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sat, 15 Mar 2025 19:03:09 +0000 Subject: [PATCH 099/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 49ab6d1ef4..9444c32c96 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6233,7 +6233,8 @@ "avatar_url": "https://avatars.githubusercontent.com/u/7389189?v=4", "profile": "https://github.com/AaratiAkkapeddi", "contributions": [ - "code" + "code", + "ideas" ] }, { From 88ebbbe326e14470f7dacba651e23636108a09b7 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sat, 15 Mar 2025 19:03:33 +0000 Subject: [PATCH 100/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 13cfc26f50..d95d5d34bf 100644 --- a/README.md +++ b/README.md @@ -1112,6 +1112,7 @@ We recognize all types of contributions. This project follows the [all-contribut Mayank Verma
Mayank Verma

💻 + roxi09
roxi09

🤔 From 71d817e82e3c47725443a2a597f8813d37e5a411 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sat, 15 Mar 2025 19:03:35 +0000 Subject: [PATCH 101/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 49ab6d1ef4..8009a52620 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6701,6 +6701,15 @@ "contributions": [ "code" ] + }, + { + "login": "roxi09", + "name": "roxi09", + "avatar_url": "https://avatars.githubusercontent.com/u/175943104?v=4", + "profile": "https://github.com/Roxi09", + "contributions": [ + "ideas" + ] } ], "repoType": "github", From 19d7aaae8b8f141bc46618892bdaf1473bdd7b29 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sat, 15 Mar 2025 19:04:47 +0000 Subject: [PATCH 102/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 13cfc26f50..7be0ed5911 100644 --- a/README.md +++ b/README.md @@ -1112,6 +1112,7 @@ We recognize all types of contributions. This project follows the [all-contribut Mayank Verma
Mayank Verma

💻 + Carrie Wang
Carrie Wang

🤔 From adc13f876622994bd5d2b75339d0900b4ee85149 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sat, 15 Mar 2025 19:04:48 +0000 Subject: [PATCH 103/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 49ab6d1ef4..9c1bb51b83 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6701,6 +6701,15 @@ "contributions": [ "code" ] + }, + { + "login": "re7l", + "name": "Carrie Wang", + "avatar_url": "https://avatars.githubusercontent.com/u/19353655?v=4", + "profile": "https://github.com/re7l", + "contributions": [ + "ideas" + ] } ], "repoType": "github", From 2e21bf642312686c821e2b989c33a54fe08ea089 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sat, 15 Mar 2025 19:04:49 +0000 Subject: [PATCH 104/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 13cfc26f50..9ac6ec4308 100644 --- a/README.md +++ b/README.md @@ -1112,6 +1112,7 @@ We recognize all types of contributions. This project follows the [all-contribut Mayank Verma
Mayank Verma

💻 + Lauren Berrios
Lauren Berrios

🤔 From 2f0c2b59ad4c356ef334c78cf81215f9b5b6c228 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sat, 15 Mar 2025 19:04:50 +0000 Subject: [PATCH 105/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 49ab6d1ef4..970edcd595 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6701,6 +6701,15 @@ "contributions": [ "code" ] + }, + { + "login": "lab-mediaArts", + "name": "Lauren Berrios", + "avatar_url": "https://avatars.githubusercontent.com/u/179049131?v=4", + "profile": "https://github.com/lab-mediaArts", + "contributions": [ + "ideas" + ] } ], "repoType": "github", From b0c5bc981d312b65d989d816b2ae623c6a499167 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sat, 15 Mar 2025 21:26:28 +0000 Subject: [PATCH 106/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index dc7d35187d..a63f39819e 100644 --- a/README.md +++ b/README.md @@ -1113,6 +1113,7 @@ We recognize all types of contributions. This project follows the [all-contribut Mayank Verma
Mayank Verma

💻 mclark414
mclark414

🤔 + Mx. Ramsey
Mx. Ramsey

🤔 From cf03634805235599a57624db48d0784c2a7dfec1 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sat, 15 Mar 2025 21:26:29 +0000 Subject: [PATCH 107/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 7554fdeed0..0200543013 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6711,6 +6711,15 @@ "contributions": [ "ideas" ] + }, + { + "login": "mxramsey", + "name": "Mx. Ramsey", + "avatar_url": "https://avatars.githubusercontent.com/u/161327383?v=4", + "profile": "https://github.com/mxramsey", + "contributions": [ + "ideas" + ] } ], "repoType": "github", From 22ee83eb5ace40b1d40c73010778d6ec11d634d7 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 17 Mar 2025 13:35:10 +0000 Subject: [PATCH 108/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 2d799bc726..42395626e5 100644 --- a/README.md +++ b/README.md @@ -1116,6 +1116,7 @@ We recognize all types of contributions. This project follows the [all-contribut Himanshu Kholiya
Himanshu Kholiya

💻 mclark414
mclark414

🤔 Mx. Ramsey
Mx. Ramsey

🤔 + Franolich Design
Franolich Design

🐛 💻 From d9d4a3c214b64750f287344b29faa6173209a755 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 17 Mar 2025 13:35:11 +0000 Subject: [PATCH 109/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 410c0d38ec..2f49c604d8 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6738,6 +6738,16 @@ "contributions": [ "ideas" ] + }, + { + "login": "franolichdesign", + "name": "Franolich Design", + "avatar_url": "https://avatars.githubusercontent.com/u/74784668?v=4", + "profile": "https://github.com/franolichdesign", + "contributions": [ + "bug", + "code" + ] } ], "repoType": "github", From 77e1a07c1ba6703efd763389fc065abd687e7405 Mon Sep 17 00:00:00 2001 From: H_vik Date: Wed, 19 Mar 2025 16:48:39 +0530 Subject: [PATCH 110/282] Added Hritvik Bhatia to the contributors list --- .all-contributorsrc | 11 +++++++++++ README.md | 9 +++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 9721db281a..4fd84eebd8 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6784,6 +6784,17 @@ "bug", "code" ] + }, + { + "login": "HritvikBhatia", + "name": "Vik", + "avatar_url": "https://avatars.githubusercontent.com/u/149999573?v=4", + "profile": "https://github.com/HritvikBhatia", + "contributions": [ + "code", + "bug", + "translation" + ] } ], "repoType": "github", diff --git a/README.md b/README.md index bb16f8cce4..7ed403d721 100644 --- a/README.md +++ b/README.md @@ -1113,16 +1113,17 @@ We recognize all types of contributions. This project follows the [all-contribut Chloe Yan
Chloe Yan

📖 Mayank Verma
Mayank Verma

💻 + Lauren Berrios
Lauren Berrios

🤔 + roxi09
roxi09

🤔 Jackie Liu
Jackie Liu

🤔 Carrie Wang
Carrie Wang

🤔 - Himanshu Kholiya
Himanshu Kholiya

💻 - mclark414
mclark414

🤔 + Himanshu Kholiya
Himanshu Kholiya

💻 + mclark414
mclark414

🤔 Mx. Ramsey
Mx. Ramsey

🤔 Franolich Design
Franolich Design

🐛 💻 - roxi09
roxi09

🤔 - Lauren Berrios
Lauren Berrios

🤔 + Vik
Vik

💻 🐛 🌍 From 0cad68edcf613d981c11a58cf8cff6871f92f3b8 Mon Sep 17 00:00:00 2001 From: limzykenneth Date: Sat, 22 Mar 2025 15:03:11 +0000 Subject: [PATCH 111/282] Create 2.0 release action --- .github/workflows/release-workflow-v2.yml | 113 ++++++++++++++++++++++ .github/workflows/release-workflow.yml | 4 +- 2 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/release-workflow-v2.yml diff --git a/.github/workflows/release-workflow-v2.yml b/.github/workflows/release-workflow-v2.yml new file mode 100644 index 0000000000..07c70b75d5 --- /dev/null +++ b/.github/workflows/release-workflow-v2.yml @@ -0,0 +1,113 @@ +name: New p5.js 2.x release +# Requires secrets `NPM_TOKEN` and `ACCESS_TOKEN` to be set + +permissions: + contents: write + +on: + push: + tags: + - 'v2.*.*' # Push events to matching v*.*.*, i.e. v20.15.10 + - 'v2.*.*-*' # Push events to matching v*.*.*-*, i.e. v20.15.10-0 + +jobs: + release: + runs-on: ubuntu-latest + name: Release + env: + INPUT_TOKEN: ${{ secrets.NPM_TOKEN }} + steps: + # 1. Setup + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 20 + - name: Get semver info + id: semver + uses: akshens/semver-tag@v4 + with: + version: ${{ github.ref_name }} + + - name: Get version number + id: version-number + run: | + version=$(echo ${{ github.ref_name }} | cut -c 2-) + echo "version=$version" >> $GITHUB_OUTPUT + + - name: Get current date + id: date + run: echo "date=$(date +"%B %Oe, %Y")" >> $GITHUB_OUTPUT + - name: Install dependencies + run: npm ci + env: + CI: true + - name: Run test + run: npm test + env: + CI: true + - name: Run build + run: npm run build + + # 2. Prepare release files + - run: mkdir release && mkdir p5 && cp -r ./lib/* p5/ + - name: Create release zip file + uses: TheDoctor0/zip-release@0.6.2 + with: + type: zip + filename: release/p5.zip + path: ./p5/* + + - name: Copy release files + run: cp lib/p5.js lib/p5.min.js lib/p5.esm.js release/ + + # 3. Release p5.js + - name: Create GitHub release + uses: softprops/action-gh-release@v0.1.15 + with: + draft: true + prerelease: ${{ steps.semver.outputs.is-prerelease == 'true' }} + files: release/* + generate_release_notes: true + token: ${{ secrets.ACCESS_TOKEN }} + - name: Publish to NPM + uses: JS-DevTools/npm-publish@v1 + with: + token: ${{ secrets.NPM_TOKEN }} + tag: ${{ steps.semver.outputs.is-prerelease != 'true' && 'latest' || 'beta' }} + + # 4. Update p5.js website + - name: Clone p5.js website + if: ${{ steps.semver.outputs.is-prerelease != 'true' }} + uses: actions/checkout@v3 + with: + repository: processing/p5.js-website + ref: '2.0' + path: website + fetch-depth: 0 + token: ${{ secrets.ACCESS_TOKEN }} + - name: Updated website files + if: ${{ steps.semver.outputs.is-prerelease != 'true' }} + run: | + cd website + npm install + npm run build:contributor-docs + npm run build:contributors + npm run build:reference + npm run build:search + npm run build:p5-version + - name: Commit updated website files + if: ${{ steps.semver.outputs.is-prerelease != 'true' }} + run: | + cd website + git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + git add . + git commit -m "Update p5.js to ${{ github.ref_name }}" + - name: Push updated website repo + if: ${{ steps.semver.outputs.is-prerelease != 'true' }} + uses: ad-m/github-push-action@v0.6.0 + with: + github_token: ${{ secrets.ACCESS_TOKEN }} + branch: '2.0' + directory: website/ + repository: processing/p5.js-website diff --git a/.github/workflows/release-workflow.yml b/.github/workflows/release-workflow.yml index 2a3ca4e40d..52f9ff2fe6 100644 --- a/.github/workflows/release-workflow.yml +++ b/.github/workflows/release-workflow.yml @@ -7,8 +7,8 @@ permissions: on: push: tags: - - 'v*.*.*' # Push events to matching v*.*.*, i.e. v20.15.10 - - 'v*.*.*-*' # Push events to matching v*.*.*-*, i.e. v20.15.10-0 + - 'v1.*.*' # Push events to matching v*.*.*, i.e. v20.15.10 + - 'v1.*.*-*' # Push events to matching v*.*.*-*, i.e. v20.15.10-0 jobs: release: From f61cf3962323fc6cd07853b4bcaa57e02b3c4211 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 24 Mar 2025 14:08:08 +0000 Subject: [PATCH 112/282] docs: update README.md [skip ci] --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index bb16f8cce4..431ea5ea7f 100644 --- a/README.md +++ b/README.md @@ -1113,16 +1113,17 @@ We recognize all types of contributions. This project follows the [all-contribut Chloe Yan
Chloe Yan

📖 Mayank Verma
Mayank Verma

💻 + Lauren Berrios
Lauren Berrios

🤔 + roxi09
roxi09

🤔 Jackie Liu
Jackie Liu

🤔 Carrie Wang
Carrie Wang

🤔 - Himanshu Kholiya
Himanshu Kholiya

💻 - mclark414
mclark414

🤔 + Himanshu Kholiya
Himanshu Kholiya

💻 + mclark414
mclark414

🤔 Mx. Ramsey
Mx. Ramsey

🤔 Franolich Design
Franolich Design

🐛 💻 - roxi09
roxi09

🤔 - Lauren Berrios
Lauren Berrios

🤔 + Qingfeng Huang
Qingfeng Huang

🌍 From d11b39de8238e53ffe75d452ad135749750e8e71 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 24 Mar 2025 14:08:09 +0000 Subject: [PATCH 113/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 9721db281a..3e3ccc513e 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6784,6 +6784,15 @@ "bug", "code" ] + }, + { + "login": "Darrenhqf", + "name": "Qingfeng Huang", + "avatar_url": "https://avatars.githubusercontent.com/u/92257843?v=4", + "profile": "https://git.arts.ac.uk/pages/21034426/My_Portfolio_Website/", + "contributions": [ + "translation" + ] } ], "repoType": "github", From 537e860cf81c64428720d8ec9b4f8462be566a12 Mon Sep 17 00:00:00 2001 From: vansh kabra Date: Mon, 3 Mar 2025 23:22:40 +0530 Subject: [PATCH 114/282] Fix: Update sin(), cos(), and tan() docs to respect angleMode() & clarify arc() behavior. --- src/core/shape/2d_primitives.js | 5 ++++- src/math/trigonometry.js | 20 +++++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/core/shape/2d_primitives.js b/src/core/shape/2d_primitives.js index f916339514..b1f7d66ae5 100644 --- a/src/core/shape/2d_primitives.js +++ b/src/core/shape/2d_primitives.js @@ -110,7 +110,10 @@ p5.prototype._normalizeArcAngles = ( * * The fifth and sixth parameters, `start` and `stop`, set the angles * between which to draw the arc. Arcs are always drawn clockwise from - * `start` to `stop`. Angles are always given in radians. + * `start` to `stop`. The fifth and sixth parameters, start and stop, set the + * angles between which to draw the arc. Arcs are always drawn clockwise from + * start to stop. By default, angles are given in radians, but if angleMode + * (DEGREES) is set, the function interprets the values in degrees. * * The seventh parameter, `mode`, is optional. It determines the arc's fill * style. The fill modes are a semi-circle (`OPEN`), a closed semi-circle diff --git a/src/math/trigonometry.js b/src/math/trigonometry.js index cb2af7c709..788dbfb1ff 100644 --- a/src/math/trigonometry.js +++ b/src/math/trigonometry.js @@ -283,10 +283,12 @@ p5.prototype.atan2 = function(y, x) { * * `cos()` is useful for many geometric tasks in creative coding. The values * returned oscillate between -1 and 1 as the input angle increases. `cos()` - * takes into account the current angleMode(). + * calculates the cosine of an angle, using radians by default, or according to + * if angleMode() setting (RADIANS or DEGREES). * * @method cos - * @param {Number} angle the angle in radians unless specified by angleMode(). + * @param {Number} angle the angle, in radians by default, or according to + * if angleMode() setting (RADIANS or DEGREES). * @return {Number} cosine of the angle. * * @example @@ -363,10 +365,12 @@ p5.prototype.cos = function(angle) { * * `sin()` is useful for many geometric tasks in creative coding. The values * returned oscillate between -1 and 1 as the input angle increases. `sin()` - * takes into account the current angleMode(). + * calculates the sine of an angle, using radians by default, or according to + * if angleMode() setting (RADIANS or DEGREES). * * @method sin - * @param {Number} angle the angle in radians unless specified by angleMode(). + * @param {Number} angle the angle, in radians by default, or according to + * if angleMode() setting (RADIANS or DEGREES). * @return {Number} sine of the angle. * * @example @@ -443,11 +447,13 @@ p5.prototype.sin = function(angle) { * * `tan()` is useful for many geometric tasks in creative coding. The values * returned range from -Infinity to Infinity and repeat periodically as the - * input angle increases. `tan()` takes into account the current - * angleMode(). + * input angle increases. `tan()` calculates the tan of an angle, using radians + * by default, or according to + * if angleMode() setting (RADIANS or DEGREES). * * @method tan - * @param {Number} angle the angle in radians unless specified by angleMode(). + * @param {Number} angle the angle, in radians by default, or according to + * if angleMode() setting (RADIANS or DEGREES). * @return {Number} tangent of the angle. * * @example From 7f1a7b3a20655ed5dc318d034efcb6d08dd33b4d Mon Sep 17 00:00:00 2001 From: Renjie Li Date: Tue, 25 Mar 2025 19:05:07 +0800 Subject: [PATCH 115/282] [p5.js - zh(Hans)] translation of missing FES contribution docs --- .../zh-Hans/fes_contribution_guide.md | 526 ++++++++++++++++++ .../how-to-add-friendly-error-messages.md | 316 +++++++++++ 2 files changed, 842 insertions(+) create mode 100644 contributor_docs/zh-Hans/fes_contribution_guide.md create mode 100644 contributor_docs/zh-Hans/how-to-add-friendly-error-messages.md diff --git a/contributor_docs/zh-Hans/fes_contribution_guide.md b/contributor_docs/zh-Hans/fes_contribution_guide.md new file mode 100644 index 0000000000..0f852096ac --- /dev/null +++ b/contributor_docs/zh-Hans/fes_contribution_guide.md @@ -0,0 +1,526 @@ + + +# 友好错误系统贡献指南 + +`core/friendly_errors`文件夹包含了p5js的友好错误系统(FES)代码,该系统负责生成友好错误消息或友好错误。您可能已经在控制台中看到以"`🌸 p5.js says:`"开头的友好错误消息,这些消息是对默认浏览器生成的错误消息的补充。 + +FES包含多个负责生成不同类型错误的友好错误消息的函数。这些函数从各种位置收集错误,包括文件加载错误和自动播放错误的错误处理,库内的参数检查,以及p5.js贡献者实现的其他自定义错误处理。 + +本文档首先概述了FES的主要函数及其位置。在随后的参考部分,您将找到有关这些单独函数的完整信息(描述、语法、参数、位置)。在文档的最后部分,您将找到我们以前的贡献者的笔记(开发笔记),概述了FES的已知限制和可能的未来方向。如果您正在考虑为FES做贡献,请查看[开发笔记](#-开发笔记)! + + +## 概述 + +生成友好错误消息的主要函数是: + +- `p5._friendlyError()`:将输入消息格式化并打印(通过`_report()`)为友好错误 +- `p5._validateParameters()`:验证接收到的输入值是否有错误类型或缺少值 +- `p5._friendlyFileLoadError()`:指导用户解决与文件加载函数相关的错误 +- `p5._friendlyAutoplayError()`:指导用户解决与浏览器自动播放策略相关的错误 + +以下是一个图表,概述了FES中所有函数的位置以及它们如何相互连接: + +![FES中使用的文件及其用途的图表](../images/fes.svg) + +各个文件包含以下主要FES函数: + +- `fes_core.js`:包含`_report()`、`_friendlyError()`和`_friendlyAutoplayError()`,以及用于格式化和测试友好错误的其他辅助函数。 +- `validate_params.js`:包含`_validateParameters()`以及用于参数验证的其他辅助函数。 +- `file_errors.js`:包含`_friendlyFileLoadError()`和用于文件加载错误的其他辅助函数。 +- `browser_errors.js`:包含将使用FES全局错误类(`fes.globalErrors`)生成的浏览器错误列表。 +- `stacktrace.js`:包含解析错误堆栈的代码(借用自[stacktrace.js](https://github.com/stacktracejs/stacktrace.js))。 + + +## 📚 参考:FES函数 + +### `_report()` + +#### 描述 + +`_report()`是直接将错误辅助消息输出到控制台的主要函数。 + +**注意:**如果设置了`p5._fesLogger`(即,我们正在运行测试),则将使用它代替`console.log`。这在我们通过Mocha运行测试时非常有用。在这种情况下,`_fesLogger`将让`_report`将错误消息作为字符串传递给Mocha,该字符串将与断言的字符串进行测试。 + + +#### 语法 + +```js +_report(message); + +_report(message, func); + +_report(message, func, color); +``` + + +#### 参数 + +``` +@param {String} message 要打印的消息 +@param {String} [func] 函数名称 +@param {Number|String} [color] CSS颜色代码 +``` + +`[func]`输入用于在错误消息末尾附加参考链接。 + +`[color]`输入用于设置错误消息的颜色属性。这在当前版本的友好错误消息中未使用。 + + +#### 位置 + +core/friendly\_errors/fes\_core.js + +### `_friendlyError()` + +#### 描述 + +`_friendlyError()`创建并打印友好错误消息。任何p5函数都可以调用此函数来提供友好错误消息。 + +`_friendlyFileLoadError()`位于以下函数内: + +- `image/loading_displaying/loadImage()` +- `io/files/loadFont()` +- `io/files/loadTable()` +- `io/files/loadJSON()` +- `io/files/loadStrings()` +- `io/files/loadXML()` +- `io/files/loadBytes()`。 + +对`_friendlyFileLoadError`的调用序列看起来像这样: + +``` +_friendlyFileLoadError + _report +``` + + +#### 语法 + +```js +_friendlyFileLoadError(errorType, filePath); +``` + + +#### 参数 + +``` +@param {Number} errorType 文件加载错误类型的编号 +@param {String} filePath 导致错误的文件路径 +``` + +`errorType`输入指的是`core/friendly_errors/file_errors.js`中枚举的特定类型的文件加载错误。p5.js中的文件加载错误被分为各种不同的情况。这种分类旨在便于提供与不同错误场景相对应的精确和信息丰富的错误消息。例如,当它无法读取字体文件中的数据时,它可以显示与尝试加载过大无法读取的文件时不同的错误。 + + +#### 示例 + +文件加载错误示例: + +```js +/// 缺少字体文件 +let myFont; +function preload() { + myFont = loadFont('assets/OpenSans-Regular.ttf'); +} +function setup() { + fill('#ED225D'); + textFont(myFont); + textSize(36); + text('p5*js', 10, 50); +} +function draw() {} +``` + +除了浏览器的"不支持"错误外,FES还将在控制台中生成以下消息: + +``` +🌸 p5.js says: 看起来加载字体时出现了问题。请检查文件路径(assets/OpenSans-Regular.ttf)是否正确,尝试在线托管文件,或运行本地服务器。 + ++ 更多信息:https://github.com/processing/p5.js/wiki/Local-server +``` + + +#### 位置 + +/friendly\_errors/file\_errors.js + + +### `_friendlyAutoplayError()` + +#### 描述 + +如果存在与播放媒体(例如视频)相关的错误,`_friendlyAutoplayError()`会在内部调用,这很可能是由于浏览器的自动播放策略。 + +它调用`translator()`使用键`fes.autoplay`生成并打印友好错误消息。您可以在`translations/en/translation.json`中查看所有可用的键。 + + +#### 位置 + +core/friendly\_errors/fes\_core.js + + +### `_validateParameters()` + +#### 描述 + +`_validateParameters()`通过将输入参数与`docs/reference/data.json`中的信息匹配来运行参数验证,该信息是从函数的内联文档创建的。它检查函数调用是否包含正确数量和正确类型的参数。 + +它调用`translator()`使用键`fes.friendlyParamError.*`生成并打印友好错误消息。您可以在`translations/en/translation.json`中查看所有可用的键。 + +可以通过`p5._validateParameters(FUNCT_NAME, ARGUMENTS)`或`p5.prototype._validateParameters(FUNCT_NAME, ARGUMENTS)`在需要参数验证的函数内部调用此函数。建议将静态版本`p5._validateParameters`用于一般用途。`p5.prototype._validateParameters(FUNCT_NAME, ARGUMENTS)`主要用于调试和单元测试。 + +`_validateParameters()`函数位于这些函数内: + +- `accessibility/outputs` +- `color/creating_reading` +- `color/setting` +- `core/environment` +- `core/rendering` +- `core/shape/2d_primitives` +- `core/shape/attributes` +- `core/shape/curves` +- `core/shape/vertex` +- `core/transform` +- `data/p5.TypedDict` +- `dom/dom` +- `events/acceleration` +- `events/keyboard` +- `image/image` +- `image/loading_displaying` +- `image/p5.Image` +- `image/pixel` +- `io/files` +- `math/calculation` +- `math/random` +- `typography/attributes` +- `typography/loading_displaying` +- `utilities/string_functions` +- `webgl/3d_primitives` +- `webgl/interaction` +- `webgl/light` +- `webgl/loading` +- `webgl/material` +- `webgl/p5.Camera` + +从`_validateParameters`的调用序列看起来像这样: + +``` +validateParameters + buildArgTypeCache + addType + lookupParamDoc + scoreOverload + testParamTypes + testParamType + getOverloadErrors + _friendlyParamError + ValidationError + report + friendlyWelcome +``` + + +#### 语法 + +```js +_validateParameters(func, args); +``` + + +#### 参数 + +``` +@param {String} func 被调用的函数的名称 +@param {Array} args 用户输入参数 +``` + + +#### 示例 + +缺少参数的示例: + +```js +arc(1, 1, 10.5, 10); +``` + +FES将在控制台中生成以下消息: + +``` +🌸 p5.js says: [sketch.js, line 13] arc()至少需要6个参数,但只收到了4个。 (https://p5js.org/reference/p5/arc) +``` + +类型不匹配的示例: + +```js +arc(1, ',1', 10.5, 10, 0, Math.PI); +``` + +FES将在控制台中生成以下消息: + +``` +🌸 p5.js says: [sketch.js, line 14] arc()的第一个参数需要Number类型,但收到了string类型。 (https://p5js.org/reference/p5/arc) +``` + + +#### 位置 + +core/friendly\_errors/validate\_params.js + + +### `fesErrorMonitor()` + +#### 描述 + +`fesErrorMonitor()`监控浏览器错误消息,猜测错误的来源并为用户提供额外的指导。这包括堆栈跟踪,它是程序中直到抛出错误点为止调用的函数的顺序列表。堆栈跟踪对于确定错误是内部的还是由用户直接调用的某些内容引起的非常有用。 + +它调用`translator()`使用键`fes.globalErrors.*`生成并打印友好错误消息。您可以在`translations/en/translation.json`中查看所有可用的键。 + +以下是通过`fesErrorMonitor()`生成的错误消息的综合列表: + +- 使用键的友好错误消息:`fes.globalErrors.syntax.*`、`fes.globalErrors.reference.*`、`fes.globalErrors.type.*`。 +- 通过`processStack()`使用键的"内部库"错误消息:`fes.wrongPreload`、`fes.libraryError`。 +- 通过`printFriendlyStack()`使用键的堆栈跟踪消息:`fes.globalErrors.stackTop`、`fes.globalErrors.stackSubseq`。 +- 通过`handleMisspelling()`使用键的拼写检查消息(来自引用错误):`fes.misspelling`。 + +`_fesErrorMonitor()`由`window`上的`error`事件和未处理的承诺拒绝(`unhandledrejection`事件)自动触发。但是,可以在catch块中手动调用,如下所示: + +```js +try { someCode(); } catch(err) { p5._fesErrorMonitor(err); } +``` + +该函数目前适用于`ReferenceError`、`SyntaxError`和`TypeError`的子集。您可以在`browser_errors.js`中找到支持的错误的完整列表。 + +`_fesErrorMonitor`的调用序列大致如下: + +``` + _fesErrorMonitor + processStack + printFriendlyError + (if type of error is ReferenceError) + _handleMisspelling + computeEditDistance + _report + _report + printFriendlyStack + (if type of error is SyntaxError、TypeError, etc) + _report + printFriendlyStack +``` + + +#### 语法 + +```js +fesErrorMonitor(event); +``` + + +#### 参数 + +``` +@param {*} e 错误事件 +``` + + +#### 示例 + +内部错误示例1: + +```js +function preload() { + // 由于在preload中调用background() + // 导致错误 + background(200); +} +``` + +FES将在控制台中生成以下消息: + +``` +🌸 p5.js says: [sketch.js, line 8] 当调用"background"时,p5js库内部发生了一个错误,错误信息为"无法读取未定义的属性(正在读取'background')"。如果没有特别说明,这可能是由于从preload调用"background"导致的。preload函数中除了加载调用(loadImage、loadJSON、loadFont、loadStrings等)之外,不应该有任何其他内容。 (https://p5js.org/reference/p5/preload) +``` + +内部错误示例2: + +```js +function setup() { + cnv = createCanvas(200, 200); + cnv.mouseClicked(); +} +``` + +FES将在控制台中生成以下消息: + +```js +🌸 p5.js says: [sketch.js, line 12] 当调用mouseClicked时,p5js库内部发生了一个错误,错误信息为"无法读取未定义的属性(正在读取'bind')"。如果没有特别说明,这可能是传递给mouseClicked的参数问题。 (https://p5js.org/reference/p5/mouseClicked) +``` + +错误示例(作用域): + +```js +function setup() { + let b = 1; +} +function draw() { + b += 1; +} +``` + +FES将在控制台中生成以下消息: + +``` +🌸 p5.js says: + +[sketch.js, line 5] 当前作用域中未定义"b"。如果您已在代码中定义了它,应检查其作用域、拼写和大小写(JavaScript区分大小写)。 + ++ 更多信息:https://p5js.org/examples/data-variable-scope.html +``` + +错误示例(拼写): + +```js +function setup() { + xolor(1, 2, 3); +} +``` + +FES将在控制台中生成以下消息: + +``` +🌸 p5.js says: [sketch.js, line 2] 您可能不小心写了"xolor"而不是"color"。如果您希望使用p5.js中的函数,请将其更正为color。 (https://p5js.org/reference/p5/color) +``` + + +#### 位置 + +core/friendly\_errors/fes\_core.js + + +### `checkForUserDefinedFunctions()` + +#### 描述 + +检查是否有任何用户定义的函数(`setup()`、`draw()`、`mouseMoved()`等)带有大小写错误。 + +它调用`translator()`使用键`fes.checkUserDefinedFns`生成并打印友好错误消息。您可以在`translations/en/translation.json`中查看所有可用的键。 + + +#### 语法 + +```js +checkForUserDefinedFunctions(context); +``` + + +#### 参数 + +``` +@param {*} context 当前默认上下文。 + 在"全局模式"下设置为window, + 在"实例模式"下设置为p5实例 +``` + + +#### 示例 + +```js +function preload() { + loadImage('myimage.png'); +} +``` + +FES将在控制台中生成以下消息: + +``` +🌸 p5.js says: 您可能不小心写了preLoad而不是preload。如果这不是有意的,请更正它。 (https://p5js.org/reference/p5/preload) +``` + + +#### 位置 + +/friendly\_errors/fes\_core.js + + +### `helpForMisusedAtTopLevelCode()` + +#### 描述 + +`helpForMisusedAtTopLevelCode()`在窗口加载时由`fes_core.js`调用,以检查在`setup()`或`draw()`之外使用p5.js函数的情况。 + +它调用`translator()`使用键`fes.misusedTopLevel`生成并打印友好错误消息。您可以在`translations/en/translation.json`中查看所有可用的键。 + + +#### 参数 + +``` +@param {*} err 错误事件 +@param {Boolean} log false +``` + + +#### 位置 + +/friendly\_errors/fes\_core.js + + +## 💌 开发笔记 + +### 已知限制 + +#### 假阳性与假阴性情况 + +在FES中,您可能会遇到两种类型的错误:假阳性和假阴性。把假阳性想象成虚假警报。当FES警告您有错误,但您的代码实际上是正确的时,就会出现这种情况。另一方面,假阴性就像遗漏了一个错误。当您的代码中有错误,但FES没有提醒您时,就会发生这种情况。 + +识别和修复这些错误很重要,因为它们可以节省调试时间,减少混淆,并使修复实际问题变得更容易。 + +在某些不理想的情况下,错误处理的设计可能需要选择消除假阳性或假阴性。如果必须选择,通常最好消除假阳性。这样,您可以避免生成可能分散注意力或误导用户的不正确警告。 + + +#### 与`fes.GlobalErrors`相关的限制 + +FES只能检测到使用`const`或`var`声明的被覆盖的全局变量。使用let声明的变量不会被检测到。这个限制是由于`let`处理变量实例化的特定方式导致的,目前无法解决。 + +`fesErrorMonitor()`下描述的功能目前仅在Web编辑器上或在本地服务器上运行时有效。有关更多详情,请参见 pull request \[[#4730](https://github.com/processing/p5.js/pull/4730)]。 + + +### FES的性能问题 + +默认情况下,p5.js启用FES,而在`p5.min.js`中禁用,以防止FES函数减慢进程。错误检查系统可能会显著减慢您的代码(在某些情况下最多慢10倍)。请参见[友好错误性能测试](https://github.com/processing/p5.js-website/tree/main/src/assets/learn/performance/code/friendly-error-system)。 + +您可以在草图顶部使用一行代码禁用FES: + +```js +p5.disableFriendlyErrors = true; // 禁用FES +function setup() { + // 进行设置操作 +} +function draw() { + // 进行绘制操作 +} +``` + +请注意,此操作将禁用已知会降低性能的FES某些功能,例如参数检查。但是,不影响性能的友好错误消息仍将启用。这包括在文件加载失败时提供详细的错误消息,或者在您尝试覆盖全局空间中的p5.js函数时显示警告。 + + +### 未来工作的想法 + +- 解耦FES \[[#5629](https://github.com/processing/p5.js/issues/5629)] +- 消除假阳性情况 +- 识别假阴性情况 +- 添加更多单元测试以获得全面的测试覆盖 +- 更直观、清晰且可翻译的消息。关于友好错误国际化的更多讨论,请查看[友好错误i18n手册](https://almchung.github.io/p5-fes-i18n-book/en/)。 +- 识别更多常见错误类型并使用FES进行泛化(例如 `bezierVertex()`、`quadraticVertex()` - 必需对象未初始化;检查 `nf()`、`nfc()`、`nfp()`、`nfs()` 的Number参数是否为正) + + +## 结论 + +在本README文档中,我们概述了`core/friendly_errors`文件夹的结构。本节解释了这个文件夹的组织和目的,使其更容易导航和理解。此外,对于此文件夹中的每个函数,我们都提供了参考指南。 + +在本文档的后半部分,我们包含了以前贡献者的笔记,讨论了FES的当前限制和未来开发中可能的改进领域。 + +此外,我们很高兴通过2021-2022年进行的FES调查分享来自我们社区的见解。调查结果有两种格式可供查阅: + +- [21-22 FES调查报告漫画](https://almchung.github.io/p5jsFESsurvey/) +- [21-22 FES调查完整报告](https://observablehq.com/@almchung/p5-fes-21-survey)。 + + + \ No newline at end of file diff --git a/contributor_docs/zh-Hans/how-to-add-friendly-error-messages.md b/contributor_docs/zh-Hans/how-to-add-friendly-error-messages.md new file mode 100644 index 0000000000..bd51c80acd --- /dev/null +++ b/contributor_docs/zh-Hans/how-to-add-friendly-error-messages.md @@ -0,0 +1,316 @@ + + +# 如何添加友好错误信息 + +本指南将引导您完成使用友好错误系统(FES,🌸)编写友好错误(FE)信息的步骤。如果您的新方法支持自定义错误处理或为用户输出自定义日志,您可能需要为其编写友好错误信息。所有这些信息都是通过基于[i18next](https://www.i18next.com/)的`translator()`方法动态生成的,这使得p5.js能够提供与用户环境匹配的错误信息翻译。 + + +## ❗️`p5.min.js`中没有翻译 + +- 我们已将 \[i18next] 集成到我们的代码库中。但是,它的使用仅限于p5.js的未压缩版本。压缩版本`p5.min.js`仅包含我们国际化代码的基本框架,不包含实际实现。 +- 在Browserify构建任务和`src/core/init.js`中,有特定的逻辑来避免在压缩版本中加载或设置翻译。因此,添加翻译不会影响`p5.min.js`的大小。 + + +## 前提条件 + +在开始之前,请确定以下哪种情况最符合您的需求: + +- 您正在添加一个需要特定数量和类型参数的新方法。 + - 请前往[✅使用FES添加参数验证](#-使用fes添加参数验证)。 +- 您的方法涉及加载特定类型的文件,并且您需要捕获特定于加载文件的错误。 + - 请前往[📥使用FES添加文件加载错误](#-使用fes处理文件加载错误消息)。 +- 您已编写代码检测错误何时发生,并希望显示友好错误。 + - 请前往[🐈使用FES添加库错误信息](#-使用fes添加库错误信息)。 + + + +## ✅ 使用FES添加参数验证 + +### 第1步 – 再次检查您的内联文档 + +首先,确保您的方法有[内联文档](./contributing_to_the_p5js_reference.md),其中包含完整的参数列表。 + +例如,`circle()`方法有以下内联文档,以方法描述开始,后面是参数列表,然后是示例代码: + +``` +/** + * 在画布上绘制一个圆。圆是一个圆形形状。 + * 圆边缘上的每个点到其中心的距离相同。 + * 默认情况下,前两个参数设置圆中心的位置。 + * 第三个参数设置形状的宽度和高度(直径)。 + * 可以使用ellipseMode()函数更改原点。 + * + * @method circle + * @param {Number} x 圆中心的x坐标。 + * @param {Number} y 圆中心的y坐标。 + * @param {Number} d 圆的直径。 + * @chainable + * @example + *
+ * + * circle(30, 30, 20); + * describe('灰色画布中央带有黑色轮廓的白色圆圈。'); + * + *
+ * + */ +``` + +从上面的例子中,FES将查找参数列表以验证参数: + +``` + * @method circle + * @param {Number} x 圆中心的x坐标。 + * @param {Number} y 圆中心的y坐标。 + * @param {Number} d 圆的直径。 +``` + + +### 第2步 – 调用`p5._validateParameters()` + +现在回到您方法的实现,按照以下格式调用`validate_params()`:`p5._validateParameters('[您方法的名称]', arguments);`。 + +例如,以下代码将验证`circle()`的参数并生成FE信息: + +```js +p5._validateParameters('circle', arguments); +``` + +通常在方法中首先调用此函数,以避免在提供的参数不符合预期时继续执行。例如,它在`circle()`方法的第一行被调用: + +```js +p5.prototype.circle = function() { + p5._validateParameters('circle', arguments); + const args = Array.prototype.slice.call(arguments, 0, 2); + args.push(arguments[2]); + args.push(arguments[2]); + return this._renderEllipse(...args); +}; +``` + + +### 第3步 – 构建并测试您的代码以应对典型情况 + +要查看参数验证的效果,请使用`npm run build`重新构建`p5.js`。 + +要测试您的代码,找到`/lib/empty-example/index.html`并将脚本`../p5.min.js`替换为`../p5.js`,如下例所示: + +```js + +``` + +请注意,`lib/p5.min.js`不支持FE信息,因此请使用`lib/p5.js`进行测试。 + +然后,编辑`/lib/empty-example/sketch.js`来测试典型的参数错误情况: + +1. 缺少参数 +2. 参数数量错误 +3. 参数类型错误 + +以下是测试`circle()`方法表达式的示例: + +```js +// 缺少参数 +circle(100); +// 参数数量错误(超过所需数量) +// 注意这段代码仍然能成功绘制一个圆。 +circle(100, 100, 100, 1000); +// 参数类型错误 +circle(100, 100, 'hello'); +``` + +上面的代码应该生成以下FE信息: + +``` +🌸 p5.js says: [sketch.js, line 9] circle()需要至少3个参数,但只收到了1个。 (https://p5js.org/reference/p5/circle) +🌸 p5.js says: [sketch.js, line 14] circle()需要不超过3个参数,但收到了4个。 (https://p5js.org/reference/p5/circle) +🌸 p5.js says: [sketch.js, line 12] circle()的第三个参数需要Number类型,但收到了string类型。 (https://p5js.org/reference/p5/circle) +``` + +恭喜🎈!您现在已经完成了为新方法添加参数验证。 + + +## 📥 使用FES处理文件加载错误消息 + +### 第1步 – 检查文件加载错误情况列表 + +文件加载错误分为多个不同的情况,以便在错误发生时提供尽可能有帮助的信息。这使p5.js能够在不同情况下显示不同的错误。例如,当它无法读取字体文件中的数据时,它会显示一个与尝试加载过大无法读取的文件时不同的错误。 + +这些情况都有自己的编号,可以在`core/friendly_errors/file_errors.js`文件的顶部找到。 + +当您希望添加文件加载错误时,首先查看`core/friendly_errors/file_errors.js`中的`fileLoadErrorCases`,看看是否有适用于您情况的现有案例。 + + + +例如,您可能正在加载基于字符串的文件。这对应于`fileLoadErrorCases`中的`case 3`: + +```js +case 3: + return { + message: translator('fes.fileLoadError.strings', { + suggestion + }), + method: 'loadStrings' + }; +``` + +如果您正在处理的场景已经有相关的编号,请记住案例编号,并跳至[**第4步**](#step-4)。如果您在`fileLoadErrorCases`中找不到匹配的情况,请转到[**第2步**](#step-2)创建新的情况。 + + +### 第2步 – 在问题面板上讨论添加新的错误情况 + +接下来,您将提交一个问题工单,讨论创建新的情况或确认您的情况不是现有情况的重复。编写一个简短的段落描述您的新方法以及用户可能遇到这种特定文件加载错误的场景。然后再写一个简短的段落描述您方法中的错误处理以及它加载的文件类型。 + +转到[问题面板](https://github.com/processing/p5.js/issues),按"New Issue"按钮,然后选择"Issue: 💡 Existing Feature Enhancement"选项。应该出现一个空表单。 + +添加一个标题,如"向`fileLoadErrorCases`添加新情况:\[您的文件加载错误情况的高级描述]"。对于"Increasing access"部分,输入您在此步骤开始时准备的简短段落,描述典型情况。 + +然后,在"Most appropriate sub-area of p5.js?"问题中勾选"Friendly Errors"框。最后,在"Feature enhancement details"部分,输入详细说明错误处理和加载文件类型的段落。 + + +### 第3步 – 向`fileLoadErrorCases`添加新情况 + +在与维护者确认后,您可以向`fileLoadErrorCases`添加新情况。在`fileLoadErrorCases`的`switch`语句中,转到情况列表的末尾,并按照以下格式添加新情况: + +``` +case {{next available case number}}: + return { + message: translator('fes.fileLoadError.{{tag name}}', { + suggestion + }), + method: '{{name of your method}}' + }; +``` + +在上面的例子中,双尖括号(`{{}}`)中的任何内容都是您应该替换的内容。例如,如果前一个情况编号是11,您的代码应该以`case 12:`开始,最终代码中没有双括号。 + + +### 第4步 – 调用`p5._friendlyFileLoadError()` + +添加您的情况后,您现在可以在错误处理语句中调用`p5._friendlyFileLoadError([情况编号], [文件路径])`。 + +例如,请查看`loadStrings()`方法加载基于字符串的文件(对应于`fileLoadErrorCases`中的`case 3`)。`loadStrings()`方法使用[`httpDo.call()`](https://p5js.org/reference/p5/httpDo)和一个在文件错误情况下执行的自定义回调方法: + +```js +p5.prototype.httpDo.call( + this, + args[0], + 'GET', + 'text', + data => { + // [... 省略的代码 ...] + }, + function(err) { + // 错误处理 + p5._friendlyFileLoadError(3, args[0]); + // [... 省略的代码 ...] + } + ); +``` + +我们可以看到错误回调函数如何调用`p5._friendlyFileLoadError(3, [the first argument, which is a file path])`来生成以下FE信息: + +``` +🌸 p5.js says: 看起来加载文本文件时出现了问题。请检查文件路径(assets/wrongname.txt)是否正确,尝试在线托管文件,或运行本地服务器。 ++ 更多信息:https://github.com/processing/p5.js/wiki/Local-server +``` + +恭喜🎈!您现在已经完成为带有文件加载的方法实现FE。 + + + +## 🐈 使用FES添加库错误信息 + +### 第1步 – 编写代码检测错误何时发生 + +首先,查找用户在使用您的方法时可能遇到的典型错误情况,并创建逻辑来捕获这些情况。此外,如果适用,请考虑提供故障保护措施,例如为缺少的参数使用默认值。确定对用户有帮助的FE信息的情况。 + +[MDN Web文档中的这个指南](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Control_flow_and_error_handling)提供了关于控制流和JavaScript原生错误处理结构的良好概述。 + +\ + + + +### 第2步 – 调用`p5._friendlyError()` + +要生成FE信息,您只需要在错误处理语句中按照以下格式调用`p5._friendlyError('[custom message]', '[method name]');`。将方括号内(包括方括号)的所有内容替换为您自己的值。 + +例如,以下代码将为`bezierVertex()`生成FE信息: + +```js +p5._friendlyError( + '在调用bezierVertex()之前必须先使用vertex()', + 'bezierVertex' +); +``` + +这应该生成以下FE信息: + +``` +🌸 p5.js says: [sketch.js, line 19] 当调用bezierVertex时,p5js库内部发生了一个错误,错误信息为"在调用bezierVertex()之前必须先使用vertex()"。如果没有特别说明,可能是传递给bezierVertex的参数有问题。 (https://p5js.org/reference/p5/bezierVertex) +``` + +恭喜🎈!您现在已经完成了为您的方法添加库错误信息。 + + +## ✏️ 为国际受众编写友好错误信息 + +FES信息编写者应优先降低理解错误信息的障碍,提高调试过程的可访问性。以下是一个例子: + +``` +🌸 p5.js says: [sketch.js, line 7] circle() was expecting at least 3 arguments, but received only 1. (https://p5js.org/reference/p5/circle)  +``` + +如果浏览器设置为`ko-KR`(韩语)区域设置,上述参数验证信息将以韩语显示: + +``` +🌸 p5.js says: [sketch.js, 줄7] 최소 3개의 인수(argument)를 받는 함수 circle()에 인수가 1개만 입력되었습니다. (https://p5js.org/reference/p5/circle) +``` + +[友好错误i18n指南](https://almchung.github.io/p5-fes-i18n-book/)讨论了在跨文化i18n上下文中编写友好错误信息的挑战和最佳实践。以下是该指南的主要观点: + +- 了解您的受众:不要对错误信息的受众做出假设。尝试了解谁在使用我们的库以及他们如何使用它。 +- 保持语言包容性。我们努力使错误信息"友好",这对您意味着什么?寻找语言中可能的偏见和伤害。 +- 尽可能使用简单的句子。考虑将句子分解成更小的块,以最好地利用[i18next的插值功能](https://www.i18next.com/translation-function/interpolation)。 +- 优先考虑跨文化交流,并提供跨语言的良好体验。避免使用比喻手法。 +- 一次只介绍一个技术概念或技术术语。保持技术写作的一致性。尝试链接一个以初学者友好语言编写的外部资源,其中包含大量简短、实用的示例。 + +[友好错误i18n指南](https://almchung.github.io/p5-fes-i18n-book/)是一个公共项目,您可以通过[这个单独的仓库](https://github.com/almchung/p5-fes-i18n-book)为该指南做出贡献。 + + +## 🔍 可选:单元测试 + +请考虑为您的新FE信息添加单元测试,以便尽早发现错误并确保您的代码向用户传递预期的信息。此外,单元测试是确保其他贡献者的新代码不会意外破坏或干扰您的代码功能的好方法。以下是几个关于单元测试的好指南: + +- [单元测试和测试驱动开发](https://archive.p5js.org/learn/tdd.html),作者Andy Timmons +- [贡献者文档:单元测试](./unit_testing.md) + + + +示例: + +```js +suite('validateParameters: multi-format', function() { + test('color(): 可选参数,类型不正确', function() { + assert.validationError(function() { + p5._validateParameters('color', [0, 0, 0, 'A']); + }); + }); +} +``` + + +## 结论 + +在本指南中,我们提供了为多种不同情况添加FE信息的分步说明,包括: + +- 添加参数验证, +- 处理文件加载错误,以及 +- 为方法添加库错误信息。 + +此外,我们很高兴通过2021-2022年进行的FES调查分享我们社区的见解。调查结果以两种格式提供: + +- [21-22 FES调查报告漫画](https://almchung.github.io/p5jsFESsurvey/) +- [21-22 FES调查完整报告](https://observablehq.com/@almchung/p5-fes-21-survey) + +有关FES设计和技术方面的更深入信息,请参阅[FES自述文档](./friendly_error_system.md)。该文档提供了详细的解释和开发说明,对那些寻求更深入了解FES的人有所帮助。 From 12567f10dd2bfd4c6e52f9b648cf598fafcd2c90 Mon Sep 17 00:00:00 2001 From: Renjie Li Date: Thu, 10 Apr 2025 15:15:39 +0800 Subject: [PATCH 116/282] add Chinese translation for documentation_style_guide.md --- .../zh-Hans/documentation_style_guide.md | 1246 +++++++++++++++++ 1 file changed, 1246 insertions(+) create mode 100644 contributor_docs/zh-Hans/documentation_style_guide.md diff --git a/contributor_docs/zh-Hans/documentation_style_guide.md b/contributor_docs/zh-Hans/documentation_style_guide.md new file mode 100644 index 0000000000..ae741eb8c0 --- /dev/null +++ b/contributor_docs/zh-Hans/documentation_style_guide.md @@ -0,0 +1,1246 @@ + + +# 文档风格指南 + +你好!欢迎来到 p5.js 文档编写指南。本文档是以下资源的混合: + +- Ruby on Rails [API 文档指南](https://guides.rubyonrails.org/api_documentation_guidelines.html) (CC BY-SA 4.0) +- WordPress 关于[可访问性](https://make.wordpress.org/docs/style-guide/general-guidelines/accessibility/)和[包容性](https://make.wordpress.org/docs/style-guide/general-guidelines/inclusivity/)的文档指南 (CC0) +- Airbnb [JavaScript 风格指南](https://airbnb.io/javascript/) (MIT) + +我们的社区庞大而多样。许多人使用 p5.js 学习编程,其中很大一部分是 K-12 年级的学生。阅读本指南后,你将了解: +- 如何编写有效、包容和易于访问的文档。 +- 如何为文档编写简单的代码示例。 + +## 目录 + +### 写作 +- [YUIDoc](#yuidoc) +- [英语](#英语) +- [牛津逗号](#牛津逗号) +- [措辞](#措辞) +- [无偏见的文档](#无偏见的文档) +- [可访问性和残障](#可访问性和残障) + +### 代码 +- [代码示例](#代码示例) +- [注释](#注释) +- [空白](#空白) +- [分号](#分号) +- [命名约定](#命名约定) +- [变量](#变量) +- [字符串](#字符串) +- [布尔运算符](#布尔运算符) +- [条件语句](#条件语句) +- [迭代](#迭代) +- [对象](#对象) +- [数组](#数组) +- [函数](#函数) +- [箭头函数](#箭头函数) +- [链式调用](#链式调用) +- [类](#类) +- [资源](#资源) + +## YUIDoc + +我们使用 YUIDoc 来生成 p5.js API 文档。要生成文档,请切换到 p5.js 根目录,运行 `npm install`,然后执行: + +``` +$ npm run grunt yui:dev +``` + +输出将出现在 docs/reference 目录中。更多信息请参考[内联文档指南](./contributing_to_the_p5js_reference.md)。 + +**[⬆ 返回顶部](#目录)** + +## 英语 + +请使用美式英语(color、center、modularize 等)。参见[美式和英式英语拼写差异列表](https://en.wikipedia.org/wiki/American_and_British_English_spelling_differences)。 + +**[⬆ 返回顶部](#目录)** + +## 牛津逗号 + +请使用[牛津逗号](https://en.wikipedia.org/wiki/Serial_comma)("red, white, and blue",而不是"red, white and blue")。 + +**[⬆ 返回顶部](#目录)** + +## 措辞 + +写简单、陈述性的句子。简洁是加分项:直奔主题。 + +使用现在时态:"Returns an object that...",而不是"Returned an object that..."或"Will return an object that..."。 + +注释以大写字母开头。遵循常规标点规则: + +```javascript +// Draws a fractal from a Julia set. +function drawFractal(c, radius, maxIter) { + // ... +} +``` + +明确和隐式地传达当前的做事方式。使用本指南中推荐的惯用语。如果需要,重新排序部分以强调首选方法。文档应该是最佳实践的典范,并且对初学者友好。 + +文档必须简洁但全面。探索并记录边缘情况。每种参数组合会发生什么?初学者的代码中最可能出现哪些错误? + +正确拼写名称:p5.js、CSS、HTML、JavaScript、WebGL。如有疑问,请参考官方文档等权威来源。 + +**[⬆ 返回顶部](#目录)** + +## 无偏见的文档 + +编写文档时不要对任何类型的人有偏见。在记录特别要求高/敏感的主题时,花时间自己学习一下。确保你的写作不会无意中伤害或冒犯他人。 + +在编写无偏见的文档时: + +- 包容所有性别认同和表达、性取向、种族、民族、语言、神经类型、体型、残障、阶级、宗教、文化、亚文化、政治观点、年龄、技能水平、职业和背景。使示例像我们的社区一样多样化。 +- 避免政治化内容。如果政治内容是必要的,保持中立。 +- 遵循可访问性指南。 +- 避免会侮辱或伤害人们的内容。 +- 不要对人们、国家和文化做任何概括。这包括正面或中立的概括。 +- 不要编写针对少数群体的偏见和歧视性内容。 +- 避免与历史事件相关的术语。 + +优先使用避免"you"和"your"的措辞。例如,不要: + +``` +If you need to declare a variable, it is recommended that you use `let`. +``` + +而是使用这种风格: + +``` +Always use `let` to declare variables. +``` + +**代词** + +| 推荐 | 不推荐 | +| -- | -- | +| they | he or she | +| them | him or her | +| their | his or her | +| theirs | his or hers | +| themselves | himself or herself | + +**[⬆ 返回顶部](#目录)** + +## 可访问性和残障 + +- 注重读者而不是强调他们的不便。 +- 不要将残障人士称为残疾人。使用[批准的术语](https://make.wordpress.org/docs/style-guide/general-guidelines/inclusivity/#accessibility-terminology)来指代特定残障的人。 +- 在整个 p5.js 文档中保持统一的结构。在风格和视觉上强调重要点。 +- 使用屏幕阅读器测试文档。要测试屏幕阅读器,请参见[屏幕阅读器列表](https://en.wikipedia.org/wiki/List_of_screen_readers)。 +- 考虑所有类型设备和操作系统的多平台可访问性。 +- 创建使用所有类型输入设备的示例,如基于语音和手势的设备、控制器、鼠标和键盘。 +- 不要使用能力歧视语言。在编写关于可访问性和残障的内容时要包容和无偏见。 +- 对 HTML 语义采取实用方法。不要纯粹为了语义而添加语义。如果有明显匹配内容的 HTML 结构,请使用该元素。例如,一组链接很可能应该使用列表元素。 +- 使用简单的表格和表格格式。避免使用 span 标签(如 rowspan 和 colspan)。表格对屏幕阅读器来说很困难。 + +**可访问性术语** + +以下术语改编自 WordPress 文档指南中的[编写包容性文档](https://make.wordpress.org/docs/style-guide/general-guidelines/inclusivity/#accessibility-terminology)。有关以人为本语言的更多背景,请参见 CDC 的[与残障人士沟通指南](https://www.cdc.gov/ncbddd/disabilityandhealth/materials/factsheets/fs-communicating-with-people.html)。 + +| 推荐 | 不推荐 | +| -- | -- | +| 残障人士 | 残疾人、残障、能力不同、有挑战、不正常 | +| 非残障人士 | 正常人、健康人、健全人 | +| 有[残障] | 受害者、遭受、受...影响、被...折磨 | +| 无法说话,使用合成语音 | 哑巴、失语 | +| 聋人,听力低下 | 听力障碍 | +| 盲人,视力低下 | 视力障碍,视觉挑战 | +| 认知或发育障碍 | 智力挑战,学习缓慢 | +| 行动不便的人,身体残障的人 | 瘸子,残障 | + +## 代码示例 + +选择有意义的代码示例,涵盖基础知识以及容易出错的地方。只有在解释功能工作原理时才使用高级语法。当一个圆就能传达想法时,不要画五个圆来解释。代码示例本身应遵循以下指南。 + +**[⬆ 返回顶部](#目录)** + +## 注释 + +- 使用 `//` 进行单行注释。将单行注释放在注释主题上方的新行上。除非是块的第一行,否则在注释前放置一个空行。 + +```javascript +// 不好。 +let magicWord = 'Please'; // 记住这个。 + +// 好。 +// 记住这个。 +let magicWord = 'Please'; + +// 不好。 +if (keyIsPressed === true) { + thing1(); + // 这是一个重要的注释。 + thing2(); +} + +// 好。 +if (keyIsPressed === true) { + thing1(); + + // 这是一个重要的注释。 + thing2(); +} +``` + +- 所有注释都以空格开头,使其更易于阅读。 + +```javascript +// 不好。 +//记住这个。 +let magicWord = 'Please'; + +// 好。 +// 记住这个。 +let magicWord = 'Please'; +``` + +- 使用 `//` 进行多行注释。 + +```javascript + +// 不好。 +/** + * 我将使用 // 进行多行注释。 + * 我将使用 // 进行多行注释。 + * 我将使用 // 进行多行注释。 + * 我将使用 // 进行多行注释。 + * 我将使用 // 进行多行注释。 + */ + +// 不好。 +/* + 我将使用 // 进行多行注释。 + 我将使用 // 进行多行注释。 + 我将使用 // 进行多行注释。 + 我将使用 // 进行多行注释。 + 我将使用 // 进行多行注释。 + */ + +// 好。 +// 我将使用 // 进行多行注释。 +// 我将使用 // 进行多行注释。 +// 我将使用 // 进行多行注释。 +// 我将使用 // 进行多行注释。 +// 我将使用 // 进行多行注释。 + +``` + +**[⬆ 返回顶部](#目录)** + +## 空白 + +- 缩进块 2 个空格。 + +```javascript +// 不好。 +function setup() { +∙∙∙∙createCanvas(400, 400); +} + +// 不好。 +function setup() { +∙createCanvas(400, 400); +} + +// 好。 +function setup() { +∙∙createCanvas(400, 400); +} +``` + +- 在左大括号前放置 1 个空格。 + +```javascript +// 不好。 +function setup(){ + createCanvas(400, 400); +} + +// 好。 +function setup() { + createCanvas(400, 400); +} +``` + +- 在控制语句(如 `if` 和 `for`)中的左括号前放置 1 个空格。在参数列表和函数名之间不要放置空格。 + +```javascript +// 不好。 +if(keyIsPressed === true) { + doStuff (); +} + +// 好。 +if (keyIsPressed === true) { + doStuff(); +} + +// 不好。 +function setup () { + createCanvas (400, 400); +} + +// 好。 +function setup() { + createCanvas(400, 400); +} +``` + +- 在运算符之间放置空格。 + +```javascript +// 不好。 +let y=x+5; + +// 好。 +let y = x + 5; +``` + +## 分号 + +- 使用分号。 + +> 为什么?JavaScript 的[自动分号插入](https://tc39.github.io/ecma262/#sec-automatic-semicolon-insertion)可能导致细微的错误。 + +```javascript +// 不好。 +let x = 0 + +// 好。 +let x = 0; +``` + +## 命名约定 + +- 避免使用单字母名称。要有描述性。 + +```javascript +// 不好。 +function f(x, y) { + // ... +} + +// 好。 +function vectorField(x, y) { + // ... +} +``` + +- 使用驼峰命名法命名对象、函数和实例。 + +```javascript +// 不好。 +let OBJEcttsssss = {}; + +// 不好。 +let this_is_my_object = {}; + +// 好。 +let thisIsMyObject = {}; +``` + +- 使用帕斯卡命名法命名类。 + +```javascript +// 不好。 +class player { + constructor(name) { + this.name = name; + } +} + +// 好。 +class Player { + constructor(name) { + this.name = name; + } +} +``` + +- 不要使用尾随或前导下划线。 + +> 为什么?JavaScript 没有私有属性或方法。 + +```javascript +// 不好。 +class Spy { + constructor(secret) { + this._secret = secret; + } +} + +// 好。 +class Spy { + constructor(secret) { + this.secret = secret; + } +} +``` + +**[⬆ 返回顶部](#目录)** + +## 变量 + +- 避免使用 `var` 声明变量。 + +> 为什么?使用 `var` 声明的变量具有令人困惑的作用域规则。这些会导致细微的错误。 + +```javascript +// 不好,因为它看起来合理。 +circle(x, y, 50); +var x = 200; +var y = 200; + +// 好,因为它会抛出 ReferenceError。 +circle(x, y, 50); +let x = 200; +let y = 200; +``` + +- 始终使用 `let` 声明变量。避免使用 `const`。 + +> 为什么?使用 `let` 声明的变量比使用 `var` 声明的变量更容易理解。变量在草图中经常被重新赋值,所以默认使用 `let` 很有帮助。 + +```javascript +// 不好。 +flower = '🌸'; +var flower = '🌸'; +const flower = '🌸'; + +// 好。 +let flower = '🌸'; +``` + +- 每个变量或赋值使用一个 `let` 声明。 + +> 为什么?这样更容易阅读和添加新的变量声明。 + +```javascript +// 不好。 +let positions = getPositions(), + startSearch = true, + dragonball = 'z'; + +// 好。 +let positions = getPositions(); +let startSearch = true; +let dragonball = 'z'; +``` + +- 在需要的地方分配变量,并将它们放在合理的位置。 + +> 为什么?`let` 是块作用域而不是函数作用域。 + +```javascript +// 不好 - 不必要的搜索。 +function getCharacter(name = 'default') { + let character = characters.find((c) => c.name === name); + + if (name === 'default') { + return false; + } + + if (character) { + return character; + } + + return false; +} + +// 好。 +function getCharacter(name = 'default') { + if (name === 'default') { + return false; + } + + let character = characters.find((c) => c.name === name); + + if (character) { + return character; + } + + return false; +} +``` + +- 避免使用一元递增和递减(`++`,`--`)。 + +> 为什么?一元递增和递减语句受[自动分号插入](https://tc39.github.io/ecma262/#sec-automatic-semicolon-insertion)的影响。这可能导致递增或递减值的静默错误。使用像 `num += 1` 这样的语句更新变量也比 `num++` 更具表现力。 + +```javascript +// 不好。 +let num = 1; +num++; +--num; + +// 好。 +let num = 1; +num += 1; +num -= 1; +``` + +**[⬆ 返回顶部](#目录)** + +## 字符串 + +- 使用单引号 `''` 表示字符串。 + +```javascript +// 不好。 +let name = "Hilma af Klint"; + +// 不好 - 模板字面量应包含插值或换行。 +let name = `Hilma af Klint`; + +// 好。 +let name = 'Hilma af Klint'; +``` + +- 不要连接导致行超过 80 个字符的字符串。 + +> 为什么?断开的字符串难以阅读,使代码不易搜索。 + +```javascript +// 不好。 +let essay = 'You see us as you want to see us: \ +in the simplest terms, in the most convenient definitions.'; + +// 不好。 +let essay = 'You see us as you want to see us: ' + + 'in the simplest terms, in the most convenient definitions.'; + +// 好。 +let essay = 'You see us as you want to see us: in the simplest terms, in the most convenient definitions.'; +``` + +- 需要时使用模板字符串而不是连接。 + +> 为什么?模板字符串具有简洁的语法。它们还提供适当的换行和字符串插值功能。 + +```javascript +let name = 'Dave'; + +// 不好。 +text(name + ', this conversation can serve no purpose anymore. Goodbye.' + name, 0, 0); + +// 好。 +text(`${name}, this conversation can serve no purpose anymore. Goodbye.`, 0, 0); +``` + +- 不要在字符串中不必要地转义字符。 + +> 为什么?反斜杠会损害可读性。 + +```javascript +// 不好。 +let bad = '\'this\' \i\s \"quoted\"'; + +// 好。 +let good = 'Air quotes make you look "cool".'; +``` + +**[⬆ 返回顶部](#目录)** + +## 布尔运算符 + +- 使用 `===` 和 `!==` 而不是 `==` 和 `!=`。 + +- 不要使用布尔值的快捷方式。 + +> 为什么?对初学者来说更容易理解。 + +```javascript +// 不好。 +if (mouseIsPressed) { + // ... +} + +// 好。 +if (mouseIsPressed === true) { + // ... +} + +// 不好。 +if (name) { + // ... +} + +// 好。 +if (name !== '') { + // ... +} + +// 不好。 +if (collection.length) { + // ... +} + +// 好。 +if (collection.length > 0) { + // ... +} +``` + +- 除非必要,否则不要使用 `switch` 语句。 + +- 混合运算符时使用括号。唯一的例外是算术运算符 `+`、`-` 和 `**`。 + +> 为什么?这样更容易阅读并避免细微的错误。 + +```javascript +// 不好。 +let huh = a && b < 0 || c > 0 || d + 1 === 0; + +// 好。 +let huh = (a && b < 0) || c > 0 || (d + 1 === 0); + +// 不好。 +if (a || b && c) { + return d; +} + +// 好。 +if (a || (b && c)) { + return d; +} + +// 不好。 +let what = a + b / c * d; + +// 好。 +let what = a + (b / c) * d; +``` + +## 条件语句 + +- 对所有多行块使用大括号。 + +```javascript +// 不好。 +if (mouseIsPressed === true) + circle(mouseX, mouseY, 50); + +// 更好。 +if (mouseIsPressed === true) circle(mouseX, mouseY, 50); + +// 最好。 +if (mouseIsPressed === true) { + circle(mouseX, mouseY, 50); +} +``` + +- 将 `else` 放在前一个 `if` 块的右大括号的同一行。 + +```javascript +// 不好。 +if (mouseIsPressed === true) { + thing1(); + thing2(); +} +else { + thing3(); +} + +// 好。 +if (mouseIsPressed === true) { + thing1(); + thing2(); +} else { + thing3(); +} +``` + +- 在总是执行 `return` 语句的 `if` 块后不要使用 `else` 块。 + +```javascript +// 不好。 +function mouseIsOnLeft() { + if (mouseX < width * 0.5) { + return true; + } else { + return false; + } +} + +// 好。 +function mouseIsOnLeft() { + if (mouseX < width * 0.5) { + return true; + } + + return false; +} +``` + +- 如果条件太长,将每个(分组的)条件放在新行上。逻辑运算符应该开始行。 + +> 为什么?这样更容易阅读。 + +```javascript +// 不好。 +if ((number === 123 || letters === 'abc') && mouseIsPressed === true && keyIsPressed === true) { + doStuff(); +} + +// 好。 +if ( + (number === 123 || letters === 'abc') + && mouseIsPressed === true + && keyIsPressed === true +) { + doStuff(); +} +``` + +- 不要使用选择运算符代替条件语句。 + +```javascript +// 不好。 +refrigeratorIsRunning && goCatchIt(); + +// 好。 +if (refrigeratorIsRunning === true) { + goCatchIt(); +} +``` + +**[⬆ 返回顶部](#目录)** + +## 迭代 + +- 除非必要,否则不要使用 `while` 或 `do-while` 循环。使用 `for` 循环来迭代固定次数。 + +```javascript +let numPetals = 7; + +// 不好。 +let i = 0; +while (i < numPetals) { + ellipse(0, 0, 20, 80); + rotate(PI / numPetals); + i += 1; +} + +// 好。 +for (let i = 0; i < numPetals; i += 1) { + ellipse(0, 0, 20, 80); + rotate(PI / numPetals); +} +``` + +- 不要使用 `for` 循环来迭代数组。 + +> 为什么?纯函数比副作用更容易推理。 + +> 使用 `forEach()` / `map()` / `every()` / `filter()` / `find()` / `findIndex()` / `reduce()` / `some()` / `...` 来迭代数组。使用 `Object.keys()` / `Object.values()` / `Object.entries()` 来生成用于迭代对象的数组。 + +```javascript +let diameters = [50, 40, 30, 20, 10]; + +// 不好。 +for (let i = 0; i < diameters.length; i += 1) { + circle(0, 0, diameters[i]); +} + +// 不好。 +for (let d of diameters) { + circle(0, 0, d); +} + +// 好。 +diameters.forEach((d) => circle(0, 0, d)); +``` + +**[⬆ 返回顶部](#目录)** + +## 对象 + +- 使用字面量语法创建对象。 + +```javascript +// 不好。 +let ball = new Object(); + +// 好。 +let ball = {}; +``` + +- 只对无效标识符的属性使用引号。 + +> 为什么?这样更容易阅读并提高语法高亮。JavaScript 引擎也更容易优化性能。 + +```javascript +// 不好。 +let secretObject = { + 'x': 100, + 'y': 200, + 'top-secret': 'classified', +}; + +// 好。 +let secretObject = { + x: 3, + y: 4, + 'top-secret': 'classified', +}; +``` + +- 使用点表示法访问属性。 + +```javascript +let turtle = { + name: 'Leonardo', + color: 'dodgerblue', + weapon: '🗡️', + food: '🍕', +}; + +// 不好。 +let turtleName = turtle['name']; + +// 好。 +let turtleName = turtle.name; +``` + +- 使用方括号表示法 `[]` 访问带有变量的属性。 + +```javascript +let turtle = { + name: 'Leonardo', + color: 'dodgerblue', + weapon: '🗡️', + food: '🍕', +}; + +function getProp(prop) { + return turtle[prop]; +} + +let turtleName = getProp('name'); +``` + +- 不要使用前导逗号。 + +```javascript +// 不好。 +let mathematician = { + firstName: 'Ada' + , lastName: 'Lovelace' +}; + +// 好。 +let mathematician = { + firstName: 'Ada', + lastName: 'Lovelace', +}; +``` + +- 添加尾随逗号。 + +```javascript +// 不好。 +let artist = { + firstName: 'Lauren', + lastName: 'McCarthy' +}; + +// 好。 +let artist = { + firstName: 'Lauren', + lastName: 'McCarthy', +}; +``` + +**[⬆ 返回顶部](#目录)** + +## 数组 + +- 使用字面量语法创建数组。 + +```javascript +// 不好。 +let images = new Array(); + +// 好。 +let images = []; +``` + +- 使用 [Array#push](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/push) 而不是直接赋值来向数组添加项目。 + +```javascript +let lyrics = []; + +// 不好。 +lyrics[lyrics.length] = 'Little rough around the edges, but I keep it smooth'; + +// 好。 +lyrics.push('Little rough around the edges, but I keep it smooth'); +``` + +- 使用 `slice()` 方法复制数组。 + +```javascript +// 不好。 +let numbersCopy = []; + +for (let i = 0; i < numbers.length; i += 1) { + numbersCopy[i] = numbers[i]; +} + +// 好。 +let numbersCopy = numbers.slice(); +``` + +- 当提高可读性时,在多行上编写数组。在左括号后和右括号前使用换行。添加尾随逗号。 + +```javascript +// 不好。 +let matrix = [[1, 0, 0], + [0, 1, 0], + [0, 0, 1]]; + +// 好。 +let matrix = [ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1], +]; + +// 也好。 +let matrix = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]; +``` + +**[⬆ 返回顶部](#目录)** + +## 函数 + +- 使用函数声明而不是命名函数表达式。 + +> 为什么?函数声明有一些陷阱,但对初学者来说更容易理解。 + +```javascript +// 不好。 +let foo = function () { + // ... +}; + +// 不好。 +let foo = () => { + // ... +}; + +// 好。 +function foo() { + // ... +} +``` + +- 使用默认参数语法。不要改变函数参数。 + +```javascript +// 不好。 +function createBall(diameter) { + diameter = diameter || 50; + // ... +} + +// 好。 +function createBall(diameter = 50) { + // ... +} +``` + +- 始终将默认参数放在最后。 + +```javascript +// 不好。 +function drawSpiral(angle = 90, length) { + // ... +} + +// 好。 +function drawSpiral(length, angle = 90) { + // ... +} +``` + +**[⬆ 返回顶部](#目录)** + +## 箭头函数 + +- 对匿名函数使用箭头函数表示法。回调是这种语法的常见用例。 + +> 为什么?语法更简洁。它还创建了一个在 `this` 上下文中执行的函数版本,这通常很有帮助。 + +> 为什么不?如果匿名函数很复杂,将其重写为声明的函数。 + +```javascript +// 不好。 +function setup() { + loadImage('assets/moonwalk.jpg', function (img) { + image(img, 0, 0); + }); +} + +// 好。 +function setup() { + loadImage('assets/moonwalk.jpg', (img) => { + image(img, 0, 0); + }); +} + +// 不好。 +function preload() { + loadImage('assets/moonwalk.jpg', (img) => { + // 复杂的预处理... + }); +} + +// 好。 +function preload() { + loadImage('assets/moonwalk.jpg', processImage); +} + +function processImage(img) { + // 复杂的预处理... +} +``` + +- 尽可能使用隐式返回。如果函数体返回单个语句且没有副作用,则省略大括号。否则,保留大括号并使用 `return` 语句。 + +> 为什么?这样更容易阅读。 + +```javascript +// 不好。 +[1, 2, 3].map((number) => { + let squared = number ** 2; + `${number} squared is ${squared}.`; +}); + +// 不好。 +[1, 2, 3].map((number) => { + let squared = number ** 2; + return `${number} squared is ${squared}.`; +}); + +// 好。 +[1, 2, 3].map((number) => `${number} squared is ${number ** 2}.`); +``` + +- 始终在参数周围包含括号。 + +> 为什么?这样做可以减少更改参数时的错误。 + +```javascript +// 不好。 +[1, 2, 3].map(number => number * number); + +// 好。 +[1, 2, 3].map((number) => number * number); +``` + +**[⬆ 返回顶部](#目录)** + +## 链式调用 + +- 使用单独的函数调用而不是函数链式调用。 + +> 为什么?适应可能不熟悉函数链式调用概念的用户。 + +```javascript +// 不好。 +fill(0) + .strokeWeight(6) + .textSize(20); + +// 不好。 +fill(0).strokeWeight(6).textSize(20); + +// 好。 +fill(0); +strokeWeight(6); +textSize(20); +``` + +**[⬆ 返回顶部](#目录)** + +## 类 + +- 始终使用 `class`。避免直接操作 `prototype`。唯一的例外是解释如何[创建库](./creating_libraries.md)。 + +> 为什么?`class` 语法更简洁,更容易理解。 + +```javascript +// 不好。 +function Mover(x, y, radius) { + this.x = x; + this.y = y; + this.radius = radius; +} + +Mover.prototype.update = function () { + this.x += 1; + this.y += 1; +}; + +Mover.prototype.render = function () { + circle(this.x, this.y, 2 * this.radius); +}; + +// 好。 +class Mover { + constructor(x, y, radius) { + this.x = x; + this.y = y; + this.radius = radius; + } + + update() { + this.x += 1; + this.y += 1; + } + + render() { + circle(this.x, this.y, 2 * this.radius); + } +} +``` + +- 使用 `extends` 进行继承。 + +```javascript +class RandomMover extends Mover { + update() { + this.x += random(-1, 1); + this.y += random(-1, 1); + } +} +``` + +- 确保自定义 `toString()` 方法不会引起副作用。 + +```javascript +// 不好。 +class Mover { + // ... + + toString() { + this.x += 1; + return `Mover at (${this.x}, ${this.y})`; + } +} + +// 好。 +class Mover { + // ... + + toString() { + return `Mover at (${this.x}, ${this.y})`; + } +} +``` + +- 不要编写空的构造函数或仅委托给父类的构造函数。 + +> 为什么?如果未指定,类有默认构造函数。 + +```javascript +// 不好。 +class Dot { + constructor() {} + + render() { + circle(mouseX, mouseY, 50); + } +} + +// 好。 +class Dot { + render() { + circle(mouseX, mouseY, 50); + } +} + +// 不好。 +class DragonBall extends Ball { + constructor(x, y, d) { + super(x, y, d); + } +} + +// 好。 +class DragonBall extends Ball { + constructor(x, y, d, numStars) { + super(x, y, d); + this.numStars = numStars; + } +} +``` + +- 避免重复的类成员。 + +> 为什么?重复的类成员声明优先选择最后一个。有重复通常意味着有错误。 + +```javascript +// 不好。 +class Mover { + // ... + + update() { + this.x += this.xspeed; + this.y += this.yspeed; + } + + update() { + this.x = 0; + this.y = 0; + } +} + +// 好。 +class Mover { + // ... + + update() { + this.x += this.xspeed; + this.y += this.yspeed; + } + + reset() { + this.x = 0; + this.y = 0; + } +} +``` + +**[⬆ 返回顶部](#目录)** + +## 资源 + +- 始终从名为"assets"的文件夹加载资源。 + +> 为什么?它模拟了良好的项目组织。这也是在 p5.js 网站上加载资源所必需的。将资源放在以下文件夹中以将其包含在我们的在线文档中: +- 示例:[src/data/examples/assets](https://github.com/processing/p5.js-website/tree/main/src/data/examples) +- 参考页面:[src/templates/pages/reference/assets](https://github.com/processing/p5.js-website/tree/main/src/templates/pages/reference/assets) +- 学习页面:[src/assets/learn](https://github.com/processing/p5.js-website/tree/main/src/assets/learn) + +```javascript +let img; + +// 不好。 +function preload() { + img = loadImage('moonwalk.jpg'); +} + +// 好。 +function preload() { + img = loadImage('assets/moonwalk.jpg'); +} +``` + +**[⬆ 返回顶部](#目录)** From c31674d35f1fc7db00767befd40833b96b5ccfde Mon Sep 17 00:00:00 2001 From: kit <1304340+ksen0@users.noreply.github.com> Date: Sun, 13 Apr 2025 12:53:30 +0200 Subject: [PATCH 117/282] Update CODE_OF_CONDUCT.md - use https --- CODE_OF_CONDUCT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 6768f8d3cf..3b4567712f 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,5 +1,5 @@ -## [p5.js community statement](http://p5js.org/community/) +## [p5.js community statement](https://p5js.org/community/) p5.js is a community interested in exploring the creation of art and design with technology. From ec70757e02154b2c31e0b94a75786873a4238d82 Mon Sep 17 00:00:00 2001 From: ffd8 Date: Mon, 14 Apr 2025 21:36:39 +0200 Subject: [PATCH 118/282] creating_libraries.md typo --- contributor_docs/creating_libraries.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contributor_docs/creating_libraries.md b/contributor_docs/creating_libraries.md index a7f2caa2ae..5ae13e2404 100644 --- a/contributor_docs/creating_libraries.md +++ b/contributor_docs/creating_libraries.md @@ -307,4 +307,4 @@ p5.prototype.myMethod = function(){ **Examples are great, too!** They show people what your library can do. Because this is all JavaScript, people can see them running online before they download anything.[ ](http://jsfiddle.net/) You can create a collection of examples on the p5.js web editor to showcase how your library works. -**Submit your library!** Once your library is ready for distribution and you’d like it included on the [p5js.org/libraries](https://p5js.org/libraries) page, please submit a pull request on the p5.js website GitHub repository following [this intruction](https://github.com/processing/p5.js-website/blob/main/docs/contributing_libraries.md)! +**Submit your library!** Once your library is ready for distribution and you’d like it included on the [p5js.org/libraries](https://p5js.org/libraries) page, please submit a pull request on the p5.js website GitHub repository following [this instruction](https://github.com/processing/p5.js-website/blob/main/docs/contributing_libraries.md)! From 3949e8b7f1dc31d632c3a5e432b8929ba09b945a Mon Sep 17 00:00:00 2001 From: ksen0 Date: Wed, 16 Apr 2025 00:50:34 +0200 Subject: [PATCH 119/282] Adding 2.0 unit testing updates from @Vaivaswat2244 --- contributor_docs/images/pixelmatch.png | Bin 0 -> 5563 bytes contributor_docs/images/pixelmatch2.png | Bin 0 -> 10858 bytes contributor_docs/unit_testing.md | 73 ++++++++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 contributor_docs/images/pixelmatch.png create mode 100644 contributor_docs/images/pixelmatch2.png diff --git a/contributor_docs/images/pixelmatch.png b/contributor_docs/images/pixelmatch.png new file mode 100644 index 0000000000000000000000000000000000000000..bba253dc9f1f499f2794a67c6a125b718477141a GIT binary patch literal 5563 zcma)=bx@p3mxm#EkOT-e!9obm;5t}fu!}pv2X|+1C%8s%*9>lf;BG;Nf#4P(xCe&- zJNa&XU)5&!ZteR|_uGBybamJ1-_z$rsVd9jKL$KTK|#TnmjkOKTOSk@R1s`UWbX+_ z(FwZJPZoFM8B7;OmaeLMY)`BF$g0%Mf4v} zI76CU6iaHE`p$v$6ZOAdM*Vp4%Kr$BGIb3ulyiOT-*E{NUxC?N?HVu2&YtX-Leav$ z(&m%A2D64lYNHcYVAJUlg6rubt)-tLqW`yv?SZ@&3IQu22kR+E`8g(K_dS#(yBWF4 zHw?Gw!;7t>W^VCZLbF|CYMRtgvb&)^^cQd(nRhYQCAB-6Li3uB_?zR&XB{=0DD)GF z)IF2kxn)GC;T)F2xTB7eCxQh)|8svp1)7FI7OwN`n5`b(`VO^;JO9{}9RrO@!s4d z;P+O}yAov?uT!#Oj5suQrY^rx{peNEkIWX7*=o$XGE+Juz!GdvzxJ>SGRetGyPpx7 z4M+_hhKdA3GRrzJmPkz8bK`z^KM`GVnb;B?0PlC;(1^z#eWe=;6qgyslY|=k!`om*tXB=rlwO8aP`SUNsKqSiG4mO5 zxy*O-Q-z*F6dI|)^Jc_EyvLAi`|=WDzbBP&v7RkQ=I52vWFr2OhZX+zR>f_Qu+zIR zE$MXpRvT+)d@nO99Yqm8n{l2v_ck)__>*!~OQ__z2UwZ$b)#GV;l zHimjEp3($pT1v+)v8I8#*`Djy-D}H96o_)xLGMX?lCiY#;xOxKeg};GwT=H-6mjfE z%ZBvC>D<%+!^=A*SYPX^nmK=J&tD0=n7_# zd-cw|4u{B+YLxv}E{(x5Kt5>tlFs6_-%fj8Z3?uHRa|?EtxGrmdgxwY$9W`vi$P;C z;TPSN;dFWYvyDCqUORj7ymk5%aG_%ME8vBattXb#{WgJ@ z;M`9C_2b^%)Rha#OFv7h+dH7Zw9y9!1DJxZPn z?3-IvJ@+$L0~$^UgnPnORbZb})k@DH`qT%8MhVAYy({mhE!~Z9bvcN!3apJgS?DLwqIZl;Qaf~ zQ4>#mo`4;xe6sKp!Tsx4TTIb2{8!c>zV54{OYAJ~7-$Bjd72n#P&%Hdm3R0@TEVOw zkH?yCW@Z>LFm<~~AvPg1zs%diBMnE{Cp=Oh%lvGD?fuaggrt-~t6D06S3+u`-xp%b z5+EOcXz4evG~$gNXuoy-R{vw^!QOIzR}FhoDB!p1<^A-pS0#y_hp4+9IW{fS6g543 zv?^T+dzbX>zbm9_H{>fxadGiiM0}~+)$yvWK$klGKgp>o7otWtR(GFSM-w~Qv}s$H zO~%(3l&2c0$`m%RPPnSo>5AwwNtC01XFQfI%GzBfAx+o(G@>Vo?C``38#7c};B~H~ ze|^uY*S_23(TePh$Na*=t7i6ob)?_@ns>M-K5bw+!YId>Iij9219wIuoShbSQ-#Pe z!YJ_e;UVc9sR_)whci;9Amc_6_%TBAh5Uwvxq`HNyn#iw!iMCIy*xsQ{$ol4J3ByI zy=f3gH7rdwsZu2!Zc?N{h?tz5d{tFay+S&dVKrQGC<%t1*vEWpOO~S#soYafatd)^ z22cYh!p`TkVZQ8izU!LcdIA6P$X&?qN5sv$oI2sRhbqIwCS9!$=g zDbOq@cWYTnKA(K+)n?>wNH%B3bbYg35jnG0R9uXydmW5J5^tRY*MW_$o?g?J;xgF+ zw$g8nH)&c7Doa{V)iyUbr$rOWDFrDBY;A1^&AIniIs%t26XN5=uKNr>TiCzxn4JbG zP8Seie23=c``0fV6t}fe>F&r@&;#O#;$(!}He-tx=75?a`K)S`*LMNJAW+d$)?Ai+ zMg|5p3R~m|(y?5TI{G72LPH6yaGhX@Tzh7b%g~c+zb{LNzvx61r}`1W5G7e*=PS z{=7xy)c&U3{F&MdMU}Dyzm3_Q{KiG#_+L?4aa3(RV6UJ*2+ib8S@8%2p=AHRuq~bC zRZV>H3>N->QvDxs|4$S4qKM`gL=$ssxc1w)#VAdW&^&h z$gqeVKKr6ZCLR@c?(UH|`<*?apU=d1_Dn<6;0Y88Aq__)nT%NEl!z}bgFTwXVWbwO zv3R}HfjQO8f5|Pq;T{q^@ycx4W-7UnO>3kOoOflO`GfwC>5T09gvc3)1mx2hbc$uS z9WdPm);HNoaMc@^5VFp;@nywB19ili9-mEnIzbLZC!fW>u`H2n?ivL3%wx`*c#ezn zj}C0|RrZ%qoKt~W73oL)V+Yn_h0oVIirFQRfwmU-|ml`b&Pdg^xzpZtmELV z*Q3n}iTt9;JRBhsTP+-(8}4j+%Cl)Uy|5_D`8^~t;^jfawvdDA)pFOK+|z8uJkJZ~ z?_JtEyZnP-DMhOpyHMpL=b&{Zu3uvvd8g+Az(coH`!fAo8hyhC0Sm&4IeZ_LCTnHc z)JTh9OP`fpTB@I}47Tr-Gk(LnRA^hw6b(sgL%?K-C_1n|a=q3 zNm&ZPpGsjI0_kZ+5J=&`aC62e&rG~ZS;}eb9NspheOY6 z!N39#enkzzq@}E#jSOR#u6^6sqKtw9u?Lnvcn$5^>T|#FF7QYyCL%S}bA6xxc))a9 zwplPSo|E^zVF$j_=&ZbRO*OvFd$4U%mLQ)WMRbjfuyUNUqyi)zgIQVM+;W>7?fqLD z4h4p+5ZQ@!4T0W+p@8`8fG-lmmg?q%++1969325HOeYif=YAdLIaRLQi`->tvV;<(A^e*hwcweoA-dgFNFcbt4a30QKd`3&pmCQ!*f77Qk$9 zDx94r-v$_NI;*e8IUv=GD|U0nUr2uHMJ^A>BnTYbz(vh$gmY0g8CGLD6k##Vq-aV< zr}w{^4X|(XUkZ8kpM)dtlS}=ghS}|lKSWLSXI%HNzwDLmNj<3h2>nmUvXLD8%}7Vd zS=!`ie!Nf{xK)|4)6ogz^w=zCF)UG<2B5NU$2euna!z(6hUjZgD}^Q+Fz5BL7=h9zxnhWQJo zrR_bvd*?(^VEShE;x*W<%a43elAPR%1EE&Jwj^B=_R`W4-NK`W57u6ZU#0RA3x9Ig zZh(72zlx-MeLFGtF5gX#g@cBKNFnLJSwG|Fa30Jd-v_zx5U4Su+bmUH3vl#RJndxazs8~fq9~hJzTDK;d#aXwG`X|yMBa>;jH#DodM2_#zsQbg&|1*XD_ex!Q|7K{zO;{Y- zAt9a1`$7sU*G`Fow8K@L%G4RTbhpgChBx!{TFj2X@o7}Lqr0%=#g&+tMY+CI91IEq zqu!B9v79tUVTu>tX6HC{GdE zPBr;PL+a&!AT2`O<$;q6;8>s^9(V-*VdE#)7)+Yj-gz|qYw zN4EjqHW_rF&<9o4=@m|S_OAvWcDXi*78ZmJcow7%1r>c`YxwUqy>-|=$i0zX5LR|w z9OMRZy)l?4Wh+2O02+!d(=+si#u3t0PO&F7M`jrmy#jh6mZO~@lC7WBnoApnSEl8a z7&D+0XH>Rj2AlrKn|Lk}VGUDWyWENgAjIt%UtC@FUE<%#!{4=(u>4ZTrjq^(sXq!T zc|VAsI4-xoiHB-tRrw#-O*w`X$^B7%(Pe3FfIh*+#nt{>&D#BM-2gd(M&?eaY$S%p z#!n>HPvQDa6c9AsWm%42J1VRXK(^}ER{QhKFh-N6?fH2<$H03bq=Usa-;{+$rx>KV zp(1=yybhbTW?MWt_%oEkbWryqbof}+mQ3`8r~={HqTZ{GPAkch6_T0`lxWiZl zc%@;>7w^+zaATjQ@)8#Xo(b=4}AXoS@rbCj2q%^BgObHq~=Y>EcarF z`(7SOPx2-?pju>~eCPUxqVPP>S4s*kz1U@Ij4C-LDF%}jd8yjLFzmEniWOGGoO{V2xWz`ng+QP{(Mn*<)YbAJ9{F0CkWGVqqJ}j7_ ztBon)1}R>YQ_c=1+X#2I`CiuA%>ZG80$mN!+merCcp?4`71mGZGV)CGodWNhUhR?0 zJujfkPf1DEj+YnE<&n<(osLMm-_^mBMS6VzbhkV9dtyH9LUY__J|Ci^jEwZwEQJlf zIgXExkB@gE&jNe_U;+Hzx5aY>@wo7COj1%(FckH-SpHmegGX&YDi=S=4MLv(;c~?Y zr3F4dJ_;KLM^)z6LO~LhCGAVZTTNGe{jBJc!srLw)^W zGGjl;4nK0Hhvwl*R%oR>s5G*HrSu3naK1NleVX&2Xl7Or3Czv!(~ZBmx%pME)szp@ zbrnzLXuk^iJ%CI_w7_V*{QR}m)twU)>P8pYQ|r?zrZzUr;shM~p>}q5p1(vOMe2ON zH}c!AwRL2v#q*7kk)^lyHR0Ubk8a8=ojh=n&{2j<#2k|raaMsU_3>a@HeH>Frs0{M zxu7{d2uk+pnDc+c_Ugy|qh`bJ*;?*ZQsByWTjV9~2}pPzh1t;NUQ%rNorMt2Z1Ryf88%I4W@`5(6*K zoJ6Emk-?7_vT+D_Pv9)B;jCh3>g;CVXaZ+uYiDD^=w#$*Vq)uLZs&aPv{4Y8#Q1oU zsH2I2vxS}QYgG#y6F7Nrz{>qv-oWuS8w(rfYnFGsENr~&EU!Pvzm`@}B__Hshl6_! zCoLwd>YlQf3eiwCxqr|*Y3e)t>x(7B8-RMLkz=GG7=KA`V1=*k)2v(Ytzdee+ng-F zBEDR_sBmP0%ckh`ra=Ef`?^+nI{43Z*g2<^Hn~b4&PZT)jcJcDmi2r6v??E;%@hPO z{r9gr20rUdRu?9+Z`{wN^Bgz{rQF=lZR7-@lQ4bwO0wPT`rg3)LqGy;*dd$v3*D@@ zExkD6?qpdeyXC6Kb(%s`Y0sWL1g8H`oSxJ(syC+ZmnD9GaohR>7C!=G{~Bz3=U<^N zSvgtq#*IgO!qp;S)ON=%-6J&S6rH`}TG(}kHzVO=J$5ZDEGdc5qHHSlYgGgZC#Q8c zs}8@yVB4+080mE1tp<}?M*FJidRb;^&`c2{@q;}*!d6MDHBn-XH9H@@RSrz!U0rs_ z96<;D!#yl;MN)7zIx)7J?)qy28%3zkVbK`mj&ov}I0EiE)Y#_j()-9jt=<z5G-$&PBK2;>LqosVvw9FE0h+@EIaUigA zGMv`=&_sIEZiLRRc`x>It@nUtFN$G8wY|)})s(bhO8G}Am&y-(+4e9p)|2zARk9E& zw-dxtCS9Velz!{(^Z*wXrfD~`81+L`s*jSi-tK}>%t|B3iT5{&C`v&qwC53hdKYG> z)E~?C@A(pWgc1xPT+BAQ5){6ysT<+PtlHc$PMxU?UGsi|G(=^;^aeUygb(sOS}Bhg z9+LPig5w!47Q07r6&M2Pr@r1lr=M7jG4E?tZSXUpI#&pt2Io0p`vxOV=#PLB2aX@04)KR2&MdT=wA+K{b{-DT$m8wBOlg95` zb-Vu_+;}Rnvzoe*6}R5-!bQviN;I~o4z8qS;Vsl#gQ5iPTEj4M=;IaXP^HSz$lYp! z>-UM!R@< zdD)-hGCsu;W9;Z$YSL_2wq);DP)I6=Z~3D8?o!OqWURyL^w$gM9WR^fbIdzu{-|id z)+{m^Yiov*l9E>rLt}Ys=VlA~s>rIA;VW;>6THlEgaJ;w&|uab3rKKA)2Z_FzQ*He!oAbk&9S?v;OTunItxi$#A3L zV!CAig)R3sJPp~s17oe``=tgMnMuZ`kW_(Q{3CbTKSi`zUWN^FG&X> zp-GpW)1^h zOu{JYa6m0mbIJO8cYc&pH1&OzwRJFj2Mde~A~UVeDBk&fxiHHjgS5rcwF zjb1_Yl(}wZt4+U*_4D!SmjSxX5)Fo`h>kQ&bhxKXUScksu?LMlKg+6_q@D>DRrmZ3 zfWxjDNX2^nOb>EJ#gwgbP1?1G$z0cz6Y$J7ESly-QmAEmf$6T|uv5rXRpiMLH8$U( z_f67CO`oo&W|IO;=vleC&+)2sMfImXrzp@I)L*3Ob=Jy;g{9+q($5{6n%a-SJ!h|}d$QhdwA2!q zuqWhm&yRtD@y*?~GC3#+ab{+w=IqY$+%M1G+n%eE-8DEUnW=mP zs(&3nU|Oc6t2^-JDbib7T7$71rA=pEJf=@wQzb^ZP^i(__W13VqR%pTyLsk8{2Zyh zy*-7;2{E=?OjuYr{Vt8g;E8TgLgj)78u>FMOj5DzQC5?lIKf$T#3$6ZzeIzPF)_{V zZ?D=qJ5^Lw1A5nv>G!OP>Lm;fDct59kPr|MGz!!d()guSRIsB3uixIB?`2e1C)zdM z;rUX@em|^iyo=0~O>n%w{hY66m42rnCH0zSPpp>emYUY}gQrSW+UN($XUFeg^{6QjhCH;1^jCY3ctfcdqYD*_vKI;DJiMHql!Xn z3!VpS^KOeKmxoJp?kkbXM2q<4T8xcX{dSkj;mlJF5I(Nt$nx@X!C5ps#9P6I&Srn4 z&!E(aY$m9nq@Wymd3jO_3j45vwl*<|h*w_}vRB&i_1adB4x@c;{f|~U%OE$dghWI< zpN}aK{l7#+pwsGTYZKX462ZmGh=U^%5|V(Rppm(`h|U%G_XTRBb8~VU8m|Z=gQm;O zu<`Lb4}2axsTESBl$DjE1$8Zp3JM~JbRS0Hjk|`HTGIQ?IZ!i(-+IVvCStvoh$5!7 zw6y#)U%BXATXizPS1W%FdJ-*Ff#&|g=i#DsQAS24pjjVlX=#aqfw49(9C71~M8NHVO)g2r@ZXYXJ(`JEeE~ZjIO?$T8o)PnbL$F15Csr9-IK zDh*l@;Y09s-J6RVA-VOnVcP0ubDJi8E^*r}rq_YbKtwBfU zvvzt8RTsfRx8!7Ahw$m%*ReUxtI@D$bQ4emngAU={|On_Jn3%%=p=I6 zE&QCJXJn+}RDqk=*{ES>)Hf(8WdFQk)m!R1c74@6}4~<44vt|~7ily>PRTWM!=*?B0lS1bOzXwVmlOabXalg8hkl7t(9y~8 zA2vM|fsUgVsL@y0EizH1vzdeqnR6)f#&%OGq`Y$&-=(9Y6LWX3`jD$CQlJ+8^()p9 z=mVKXq07Ji%7OsaV$XvE0zyDjqLK%=uP2&`IXjo<Hjfrr)m8P*PKu`aF22d2G|_f`JQOZ@vk@a_1+t<|6XE*f%-fogR7R=It$L zHkh{Nk142scYT&KZn@yTg0Z|@C@9C{acYi=hBj;o<3Ak|wVto}m?WW7W{Tl?zH2a9 zsIxl*3*X+hq%8vT21Ye-eYW%1qM9|%v;h3}Cv@HN^%~RS;&3D)3B?Tz$f0V5yTN5s z(a-YQpsI97%}8X(L@I_)b+hWSrjJUY!_TpKei*lMCl-!DJqP=bT674Z+}A_FU15 zCh6JO*aEZ)@Ib%ekw#~0d)~9S?SBGzi8DMlMwuF{PkRJURJvE^ES0JJf`DL}%6{ZR zGgDdm29&Uyv2soX0Q>V`f6#f~0kWR|NT_;8KK42HTjxqlh113W{MW?9?jNj1pmJdD zOb1e=Ei7nPIwE(LJL7k+!nFz{3Z6FzIyVJexbqVWc*KD{!vLmLqE+xGE6X+6bhg5V zl7>b_Sy@C*4*l1!`#`o!u@je^=OnyssrfKPmSXyV zP33$?zGhjCJT?i5yo(Db*x-K1QGbh#{k#&%ecN*Y_NJ_#KjF%z`@T`hf&u00)Z!)d zikq5dt#($}%pSV)^IxsT0&FSvys-7YKS@8C(6(~`7!I8|nG6PNVPtgFpXn35{>hPU zbnr@NbeYv8Q%4kutb_!jfq_9e3TgAZ6*)gmikq-Bb zWE5zk!+!3?pA+V)#f%0=&+03w!DOs=hz{}S2%yvjc);{R0Oi6c8D*Iiv*Uk*io6`5aiVg8PDPh55j#fQ|D;`m`_ zwmr)9|Nj;KYX~#7Zad zRMd=`Elcb#TPg5pp8QXX!YeyZ(AAbS&@<|TRf&CFX@JnWTw6$@A0}g5LE2P1y@~=W zOp=RT?;sen#7VQ{Of*WnA**6tv?4z(w82R{_DAPH5@CgLqKBJhA$ws#q?;?_dRBfv z&U(9Y$+Bc$9YpX7$*_CA?n}Ogug1FFr4N7l`XBetcw3s`-99ErxZmlgf-nY4qPeK{IjSn>L%U#!}*eeHDnSvCCyCla`%B_x*I2K*ROB zA!}xgMT2`4t-o_w>TxRWJI~|hIN=HO%fn~{9QEm9O}Z(qL)7@a)Y3|8!{)Z!Rh-!y z56eO{kI4=q>X?hDz+hH=miKpGCcCxEzsu14Oc(ps-So%AXU#o|`3ouJ4}3T)9z>af zdV5N1T*a&jkS+e8L?|t^JK=o$4aTeI=%RXM{@=Duj7^d>RXzsNzDdnJXVc9C3`Eq6 zqGYV3whYr1&85P%uPa>8b)O>f$oWO@85hHMg^#}*Qo|DVX&TF&IJepiDw|ElEh-6) zbhc3O_!nWV8_rYqfB*dXleET@D5s+x%`+NN;LIqQ;=3S3R-?AO*A=5H__TAf+CRxJ zLCR;tVPZWlroR2je~9?fZ$QMy=`Dz8K}%wzrmdf8yJap2r}iuS`TSBs`v^gpxmiuC zCFYj6bbUrD$vDGHd_3^>_Sk?)g=VYS^+?_5Fj1CwII!#@@WXHUtNbc69cZpPp;7+QhzhN?L%wLAu6}Zzp#05Vb7;Eip+nX;- zSJTH6?a`E2^z$FGv!5?Nm>yWra6!|mACAb3sX33fi=9MGKw_(Pg!kSbh2+d+;2=(;2;0Vvg$gp_On>v@qreree z6bhFrdf=ntEO_d+j+AJ%JwAz3__NE@w7rH{&eukki3ds_(m&la03lPkA3${6=+MpA z-os(``Qh@hgum{Jq~`*+Y^#JLNXMeM&=k9u)Egz7Hd_8*H^XaCO}8g8K#8u!)%75U zf{PZVcYtKfS!SjlldEEVUD=rP#OtV&*xig>bFsc9sC2-tYeLVQwQ#NN6Vl}!p+n#S zelw7mSoZ%A&)$oj&^jA9uZwv%0peUNsfb|*h)gyB#Qzq>{sE3MMT>ls+Pu8H_PmXY ztlRYfl7EhFA*}C@B$jzmIdrEKUfTk=U=%mjVsV_+fKL06ZXG1!#(BT z;u<;adh;4-=}jIqbgCT1`*!6~jfXBYrkf{Y^z;SneRQBaU<3 z$Mm^;n#^sNm6733tCIEM)29esAM!L;uF^#{w%3&oZk1&O5_+ripb5P)d7;L*!dpeUH0_Rgk`MULl$^8?|sl)dblZ($( zFB@;yn1P@L>|dZU%B^;OYR~l(6TaC%%F?V|VAR?w-E1;GcK2;r--faw~XaD*o{Bm&5b#!Rxy|%V? zWrJS7ZZVL<+FDvuwQkIS9c;iRbu;SgH#n{E!V$`*<iB^zz{$zk zm&_f_)) zXUQdwm?byAZwe4{-h7mKed$8!mzVBgVPU{E@Xmzn!6v2Toao$oMNEeD8x7;gR1fmeIMP*IR(0SYJoSYC~ znVHc2qrluC1uV^J2W&j;uY%?Fn!_74I!N?OJon1NT9T4z)}FK zA5=ja9q}mv0fBN&MFki5XE?g}FmME#3K;_j=H*ch+r1V$2Vu*Ph#dxQg z>kgj)3-wWZ5DR+!SZWO}GwmmY!(-5R9m&j~RUWdsYHVrAl;8R>SM~OKvT=Q`+KEA< z7|#FK#@VTQxw_8$>?oK1WxZC#AR1jyFF9l6aVZ<%+6ur*fCJ@dwS+l>KK#UKVPy1% z%;%OB%wEF09}0O+e*P+OLZ~Py1Hb}jv7LJdcYihL!%cAn~xZT}dVKn}&C|}eAXI>uf z+jjstzMofrVzN-%8_QMkx>`%n87Z%x z&@qMQZU;w&Ugs>7Rr>N+_G3CHh@w~7D7y*yiK?XT}!IZF5`l40X?Ef`m8ZMX7 zSWWw00W~ZxB^9Dk?U;!r5+WM>JTxcg?NQTHOk^O#%e4xC%TycZ)e}c6k})i`B}X0m z4tO9R%b+sf+^CViXY(X#-39?cM!fe@vMxfJcfmWI*44XVReq`aaPt?Zxo$ z@NeKoNqVZkVPaAMBJh`TZh#sT*R)KNBkK<`tDCLepnl~gbTLyK*c^)9$Jj5iv8Nk- zgdS_c+<43OI2;jVeo{=}dDVMfuz8+ad*941KKYuSJ_tnb6}YoTqql%1EQx!;-M^{| zim4JsDv;FDA_6=!Oo3A@?MmDDETzeO&DJyl&ncJ{ey!`?@0uE|9w-2=z1hk#?>mnL zuM>Ij&^@c&v9+*ClAXyS8sK0mWk@J#Xmphg3hqp{SM0iPYU+?>qr#Jc5)%FJom0XxgxgMISx5-z6o(Mb_{o4l5E{ zH&-Vc?WbF#;vyn`8ZgWF$KR^0tmL-c>9WAtJv`kab>K1~gGrW%CS~L&RjfR}HQ1l4 zHUuU4otxWT`Nmwvt0~BukC{X{S5-_x!WAXu6td5s0driFv8`Ui1HJF?j+p;ux6Hdg zA~YOZBvrIZfHb;1mCx`WAG3izUnurX?*ezsJ=Nv?p*Ev;O=E`0?YFh^XjYPcKbUk*Et;xmohb z63)&XHa0fEYX}48nv%A*tfM0v05)JTlmc&VWMl+%xAE2STHWn&uR6>P>_^vY;k|3X zkkFHwo$4CeG;bWi;DE2inJm!md^Fd7i--RZgz#3*yApvX+2)c5cNiZZ2dHnzmI$6? zJ(7FjkiN0@pds1M?@6C2yXcFBMwzgnOnKE!t}I<1tvp&eB}Sd!Vq$~=Zh@fz zf0)*z0+5_Xt3Bq8aD02YI0saRMICtY?I->Hxu017(&Cn~vaHEB=V{ph5)+={;syi<#>B?9%5%?;4U!^8 z`P}X3VZCgbYIY5PLuM}5np0B3BAU%U6}p`syj&Xeo*2}{c)k!6)a)uuak8K5OkQ~O;+iy2}`FOi7z#=RA@>7G5$ zjQlsV8;^WJHa5rCw;wj?lN$Q{-%{yjUFs~0lNB)p{uQG=`bU2LZxPcfzq?d8IF!oA z?*ja%nCQP1>6s6K+-t>aU8Jae*Wr8-ayn{anvn?5%%Bl3c8{0cb01m^dM7m)CEcmm z-=&?urMcDP;9*TKy&!wjeNkVZ>YS;F!@fh4MKdr zE;BcDXq852+@Yfi<}V$tJIBcgv3znOI>?_EQ$moFS6msnkQ>KgqGohMI@?3)N@w|Y znTuIwdgX932az+{a&iE#J2E=F3qqJ{WCOAa zSMC!$t}K4FeKTF0xlAZqOL{6mmO13}FCo-J8TrrM`f?ts{$E6o|E3jmObhuhJ?|ZZ>pNY8xtI%Dn?NRuYb8u%&B1zgW`Jycj z4}Tfm664^;bXF6N?pz_KFhpj#l-Fz8P6-L8TG%=Jtp-KPOtrGG_yvREl0O5n1Ryf1 z#~Hb~D3!C3SbiWMK}T!_T8GNBU)cEwsazdEHXsF^d#*@q+9>|bO<&1HfmsQ%QRgd0 z28M``5M)3vuQS9_0@Oup*G=&)%E2XhhpC95!KG!cWHCn*50Jtkb znIC2WZ5$fvT}oStY-b! zzHDL|<^RPu-o0qjv&6|snAk@aA}NUk!cQXGsxO$u3&2v2N5_}(@${@6i#hSAhn&wQWY6wB z>d%P@wU*Y_8*63_WQ|Ze8=Fk<8L(ynSFx>}wG(EtiG}Pz!5*8b{7Vgrf{7`aG5puH z*23EQPklWJ*kmO#s!bPLTU(FZ`GNZj?&`m;d#eSm1=OaPxVZF3Gf~l}ww1Mt85)F< z5;asDgv|LxHgcD8BkDS0-mFwfKkH~1@u7F2j*U0ULMd+*&8sIAP4}TK_HNXx}_F~ zm#l1f`2!%G0l~pW9E9Mx<7N&(vOH$V$;!(5tr76Rcf`-p5&iZ0N8@)9R2pCFw_pOA zEh`-w7PeiIrw$z#la$mu3Lrp71PSM#&u}2|3&kNJi3I7uH9~{YsfPe>YGF7@ddLg) zSITP8aplHl_11vEz^gN#BI7}~7{sUW*!LsYh2xf<`RkC>=6!2j%L|zs$knGU4KnrK z&Lw*=pTN;aCtzC*GlILHIT?p*Zu+Z;jlk28H?PlfsWVfAgtO%N*Amuq_TL0#fQQwh zPd*P4$R4E?Uw%dekGp{HFw67q_ep+|-NfDqhi#>{%*K&>4av#*w3U@rEQJk|zyi1U zTp|=f`_kw@=F$*Dhe>M>{<_rapY(qmI zEa;}ToPR6l0(oEciAj|%e(atQJ%|ZE^+2RHsXpzn{XAEd?$o1xQJCh7;SjHzCG5Ji zsauwS%@`SE_dv4`r1DKdrC(MZD`yVCCwbI2$i9LVQR)>CY=zr5=*Q^4`Dt_pT0?eI zRq>-K2&_Re4bn2f_T`%yjmlZZaU2l()%fz0MpKr8X3fk*NL2_19COKDD)Zj*{I+>g z7`@`TZc_jmn{fz7JCMhj0}5_5tuzXtgkqN2Ww zOi$P8feQ>wir`UbOi>xzn!CB1N@;U$s=W z6Fzn3LRn;5L^Crx3n1bZI--`gHY?$qtwAbP2&B}cDL}pIy|XiV^Xpq*^)n!VK*A%q z*jfRaS>Uj^xY#>1iG+bk48ImRX!Z&oe_;~3XEn$LzK@WTKyenNzdi3`*SU>bBl%zF zFPoN{fq$zLFuULsSont&f6>D$QEC)A2Kr=_|9g}yPB(h|MlFi&8A?)v_-p!qkJVj0 ZI5zR};yQ6`g71OCNsB9p6^iKl{SPx|h2Q`H literal 0 HcmV?d00001 diff --git a/contributor_docs/unit_testing.md b/contributor_docs/unit_testing.md index 789ad7d035..0b98d34a6c 100644 --- a/contributor_docs/unit_testing.md +++ b/contributor_docs/unit_testing.md @@ -249,3 +249,76 @@ visualSuite('3D Model rendering', function() { }); ``` + +Different operating systems and browsers render graphics with subtle variations. These differences are normal and shouldn't cause tests to fail. +Common acceptable differences include: + +* Single-pixel shifts in line positions +* Slight variations in anti-aliasing +* Text rendering differences (especially font weight and kerning) +* Minor differences in curve smoothness + +For example, text rendered on macOS might appear slightly different from text rendered in a Linux CI environment. The same applies to thin lines, curves, and other graphical elements with anti-aliasing. +An example of this can be the below image which earlier caused tests to fail in CI because of different rendering environments. + +![Example](./images/pixelmatch2.png) + +The p5.js visual testing system uses a sophisticated algorithm to distinguish between acceptable rendering variations and actual bugs: + +* Initial comparison - Compares pixels with a moderate threshold (0.5) to identify differences using [pixelmatch](https://github.com/mapbox/pixelmatch) library for pixel to pixel comparison. +* Cluster identification - Groups connected difference pixels using a Breadth-First Search (BFS) algorithm +* Pattern recognition - The algorithm specifically identifies: + + - "Line shift" clusters - differences that likely represent the same visual element shifted by 1px + - Isolated pixel differences (noise) + + +* Smart failure criteria - Applies different thresholds: + + - Ignores clusters smaller than 4 pixels + - Allows up to 40 total significant difference pixels + - Permits minor line shifts that are typical across platforms + +The below is the example of the tests that should fail: + +![Example](./images/pixelmatch.png) + + + +This approach balances sensitivity to real bugs while tolerating platform-specific rendering variations. The algorithm uses these key parameters: +```js +const MIN_CLUSTER_SIZE = 4; // Minimum significant cluster size +const MAX_TOTAL_DIFF_PIXELS = 40; // Maximum allowed significant differences +``` +The algorithm identifies line shifts by analyzing the neighborhood of each difference pixel. If more than 80% of pixels in a cluster have ≤2 neighbors, it's classified as a line shift rather than a structural difference. +This intelligent comparison ensures tests don't fail due to minor rendering differences while still catching actual visual bugs. + +It's important to note that the improved algorithm described above allows tests with acceptable platform-specific variations to pass correctly. Tests that previously failed due to minor rendering differences (like anti-aliasing variations or subtle text rendering differences) will now pass as they should, while still detecting actual rendering bugs. +For example, a test showing text rendering that previously failed on CI (despite looking correct visually) will now pass with the improved algorithm, as it can distinguish between meaningful differences and acceptable platform-specific rendering variations. This makes the test suite more reliable and reduces false failures that require manual investigation. + +### Some best practices for writing visual tests + +When creating visual tests for p5.js, following these practices will help ensure reliable and efficient tests: + +* Keep canvas sizes small - Use dimensions close to 50x50 pixels whenever possible. The test system resizes images for efficiency before comparison, and smaller canvases result in faster tests, especially on CI environments. +* Focus on visible details - At small canvas sizes, intricate details may be hard to distinguish. Design your test sketches to clearly demonstrate the feature being tested with elements that are visible at the reduced size. +* Use multiple screenshots per test - Instead of cramming many variants into a single screenshot, call screenshot() multiple times within a test: + ```js + visualTest('stroke weight variations', function(p5, screenshot) { + p5.createCanvas(50, 50); + + // Test thin stroke + p5.background(200); + p5.stroke(0); + p5.strokeWeight(1); + p5.line(10, 25, 40, 25); + screenshot(); // Screenshot with thin lines + + // Test thick stroke + p5.background(200); + p5.strokeWeight(5); + p5.line(10, 25, 40, 25); + screenshot(); // Screenshot with thick lines + }); + ``` + \ No newline at end of file From 1f6c44b362ee6c9227dfcded5221aacb68b842f3 Mon Sep 17 00:00:00 2001 From: ksen0 Date: Wed, 16 Apr 2025 00:53:55 +0200 Subject: [PATCH 120/282] Add context for shared contributor doc --- contributor_docs/unit_testing.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/contributor_docs/unit_testing.md b/contributor_docs/unit_testing.md index 0b98d34a6c..a20758faff 100644 --- a/contributor_docs/unit_testing.md +++ b/contributor_docs/unit_testing.md @@ -249,6 +249,10 @@ visualSuite('3D Model rendering', function() { }); ``` +## Visual tests in p5.js 2.0 + +_Both p5.js 1.x and p5.js 2.0 include visual tests. In p5.js 2.0, there are more tests, and the visual testing system uses a new diffing algorithm that is more robust. This section is this p5.js 2.0 specific system._ + Different operating systems and browsers render graphics with subtle variations. These differences are normal and shouldn't cause tests to fail. Common acceptable differences include: @@ -321,4 +325,3 @@ When creating visual tests for p5.js, following these practices will help ensure screenshot(); // Screenshot with thick lines }); ``` - \ No newline at end of file From eada7d6722daebab13e1b514acda622c79cff215 Mon Sep 17 00:00:00 2001 From: ksen0 Date: Wed, 16 Apr 2025 10:51:28 +0200 Subject: [PATCH 121/282] 1.11.4 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7040c18256..5ebd41ea27 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "p5", - "version": "1.11.3", + "version": "1.11.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "p5", - "version": "1.11.3", + "version": "1.11.4", "license": "LGPL-2.1", "devDependencies": { "@babel/core": "^7.7.7", diff --git a/package.json b/package.json index 3de1f9e9a0..62c525d0a9 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "node --require @babel/register ./utils/sample-linter.js" ] }, - "version": "1.11.3", + "version": "1.11.4", "devDependencies": { "@babel/core": "^7.7.7", "@babel/preset-env": "^7.10.2", From 414c414aa85483ff481191a95a8ee15aeac95837 Mon Sep 17 00:00:00 2001 From: Renjie Li Date: Thu, 17 Apr 2025 10:12:42 +0000 Subject: [PATCH 122/282] reorder npm run commands to make p5.js-website update the correct version docs --- .github/workflows/release-workflow-v2.yml | 2 +- .github/workflows/release-workflow.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release-workflow-v2.yml b/.github/workflows/release-workflow-v2.yml index 07c70b75d5..4cd8fe562c 100644 --- a/.github/workflows/release-workflow-v2.yml +++ b/.github/workflows/release-workflow-v2.yml @@ -90,11 +90,11 @@ jobs: run: | cd website npm install + npm run build:p5-version npm run build:contributor-docs npm run build:contributors npm run build:reference npm run build:search - npm run build:p5-version - name: Commit updated website files if: ${{ steps.semver.outputs.is-prerelease != 'true' }} run: | diff --git a/.github/workflows/release-workflow.yml b/.github/workflows/release-workflow.yml index 52f9ff2fe6..7a55f0b273 100644 --- a/.github/workflows/release-workflow.yml +++ b/.github/workflows/release-workflow.yml @@ -88,11 +88,11 @@ jobs: run: | cd website npm install + npm run build:p5-version npm run build:contributor-docs npm run build:contributors npm run build:reference npm run build:search - npm run build:p5-version - name: Commit updated website files if: ${{ steps.semver.outputs.is-prerelease != 'true' }} run: | From d377bb52814799eed685e014c0d16a4d99614e5d Mon Sep 17 00:00:00 2001 From: kit <1304340+ksen0@users.noreply.github.com> Date: Thu, 17 Apr 2025 18:15:42 +0200 Subject: [PATCH 123/282] Update README.md - 2.0 Info --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 992deea94a..ef9d956c22 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,15 @@ The p5.js community shares an interest in exploring the creation of art and desi Learn more about [our community](https://p5js.org/community/) and read our community statement and [code of conduct](https://github.com/processing/p5.js/blob/main/CODE_OF_CONDUCT.md). You can directly support our work with p5.js by donating to [the Processing Foundation](https://processingfoundation.org/support). +## 🌼 p5.js 2.0 Now Available for Community Testing & Development! + +We are releasing p5.js 2.0 to the community for testing and development! Here’s what you need to know. + +* For **reference**: p5.js 1.x reference will stay on [https://p5js.org/](https://p5js.org/), and p5.js 2.x documentation will be on [https://beta.p5js.org/](https://beta.p5js.org/) +* In the p5.js Editor: the **default will continue to be 1.x** until at least August 2026 - more information and discussion on timeline can be found on [this Discourse thread](https://discourse.processing.org/t/dev-updates-p5-js-2-0-you-are-here/46130) or [this GitHub thread](https://github.com/processing/p5.js/issues/7488) +* For updating sketches and add-on libraries: check out [the compatibility add-on libraries and guides](https://github.com/processing/p5.js-compatibility) +* For **contribution**: `npm latest` will default to 2.x, but the git branches are still separated with `main` on 1.x and `dev-2.0` on 2.x. We will switch the branches when we have updated all automations (including deploying updated documentation to the website). Want to contribute ideas or implementation? Check the [2.x project board](https://github.com/orgs/processing/projects/21/views/8) for an overview of what still needs discussion, and what’s ready for work! + ## Issues If you have found a bug in the p5.js library or want to request new features, feel free to file an issue! See our [contributor guidelines](https://p5js.org/contribute/contributor_guidelines) for a full reference of our contribution process. A set of templates for reporting issues and requesting features are provided to assist you (and us!). Different parts of p5.js are in different repositories. You can open an issue on each of them through these links: @@ -54,14 +63,12 @@ If you have found a bug in the p5.js library or want to request new features, fe p5.js is maintained mostly by volunteers, so we thank you for your patience as we try to address your issues as soon as we can. - ## Get Started for Contributors p5.js is a collaborative project with many contributors, mostly volunteers, and you are invited to help. All types of involvement are welcome. See the [contribute](https://p5js.org/contribute) for more in-depth details about contributing to different areas of the project, including code, bug fixes, documentation, discussion, and more. A quick Getting Started with the Build and setting up the repository could be found [here](https://p5js.org/contribute/contributor_guidelines/#quick-get-started-for-developers). - ## Stewards Stewards are contributors who are particularly involved, familiar, or responsive to certain areas of the project. Their role is to help provide context and guidance to others working on p5.js. If you have a question about contributing to a particular area, you can tag the listed steward in an issue or pull request. They may also weigh in on feature requests and guide the overall direction of their area, with the input of the community. You can read more about the organization of the project in our p5.js [Contributor Guidelines](https://p5js.org/contribute/contributor_guidelines) and p5.js [Steward Guidelines](https://p5js.org/contribute/steward_guidelines). From 31aebe1fc38153dffa34627aa5490e328dbe06f1 Mon Sep 17 00:00:00 2001 From: ksen0 Date: Thu, 17 Apr 2025 18:32:11 +0200 Subject: [PATCH 124/282] 1.11.5 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5ebd41ea27..9574b8aef7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "p5", - "version": "1.11.4", + "version": "1.11.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "p5", - "version": "1.11.4", + "version": "1.11.5", "license": "LGPL-2.1", "devDependencies": { "@babel/core": "^7.7.7", diff --git a/package.json b/package.json index 62c525d0a9..47c2550f6e 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "node --require @babel/register ./utils/sample-linter.js" ] }, - "version": "1.11.4", + "version": "1.11.5", "devDependencies": { "@babel/core": "^7.7.7", "@babel/preset-env": "^7.10.2", From db82bc0130288a59030c9940af286b72f3b7d667 Mon Sep 17 00:00:00 2001 From: kit <1304340+ksen0@users.noreply.github.com> Date: Fri, 18 Apr 2025 12:21:04 +0200 Subject: [PATCH 125/282] Update 1-p5.js-2.0-bug-report.yml --- .../ISSUE_TEMPLATE/1-p5.js-2.0-bug-report.yml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/1-p5.js-2.0-bug-report.yml b/.github/ISSUE_TEMPLATE/1-p5.js-2.0-bug-report.yml index bb04352fa9..bb680bc5ec 100644 --- a/.github/ISSUE_TEMPLATE/1-p5.js-2.0-bug-report.yml +++ b/.github/ISSUE_TEMPLATE/1-p5.js-2.0-bug-report.yml @@ -1,18 +1,16 @@ -name: 📃 p5.js 2.0 Beta Bug Report +name: 📃 p5.js 2.0 Bug Report description: This template is for submitting a bug report for bugs found in the p5.js 2.0 beta releases. -title: "[p5.js 2.0 Beta Bug Report]: " +title: "[p5.js 2.0 Bug Report]: " labels: [p5.js 2.0] body: - type: markdown attributes: value: | ### What falls under this category? - There has been many changes to p5.js in 2.0 that is currently released as beta versions. If you suspect there may be a bug, please follow the below steps before opening a bug report using this template: - - 1. There are some differences in behavior between p5.js 1.x and 2.0 beta, please check the changelog and/or [proposal list](https://github.com/orgs/processing/projects/21) to see if the difference in behavior is intended. If in doubt, feel free to open the issue anyway and ask. - 2. Breaking changes may still happen between beta versions, please make sure to include the full beta version number and use the latest beta release where possible. - 3. We are not considering any new proposal for p5.js 2.0 at this stage and if you would like to request new features, please use the "New feature request" issue template. - 4. The documentation and examples may be outdated at this stage while we work on updating them. + There has been many changes to p5.js in 2.0! You can try it in p5.js Editor by updating the version in "Settings," and reference is available [on the beta version of the site](https://beta.p5js.org/). If you suspect there may be a bug, please follow the below steps before opening a bug report using this template: + 1. There are some differences in behavior between p5.js 1.x and 2.0 beta, please check the changelog and/or [2.0 status board](https://github.com/orgs/processing/projects/21) to see if the difference in behavior is intended. If in doubt, feel free to open the issue anyway and ask. + 2. New proposals for future p5.js 2.x minor releases may be considered! Please use the "New feature request" issue template, or check the [2.0 status board](https://github.com/orgs/processing/projects/21) is there is already discussion abotu this proposal. + 3. Reports of errors or potential improvements in documentation and examples is expecially helpful, since many things have been updated from 1.x to 2.0! - type: checkboxes id: sub-area attributes: @@ -78,4 +76,4 @@ body: ```" validations: - required: true \ No newline at end of file + required: true From f06e232a2a18c1cd6d7220512c9c9b28f131ec04 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 22 Apr 2025 13:24:29 +0000 Subject: [PATCH 126/282] docs: update README.md [skip ci] --- README.md | 178 +++++++++++++++++++++++++++--------------------------- 1 file changed, 89 insertions(+), 89 deletions(-) diff --git a/README.md b/README.md index ef9d956c22..3012d5c6c1 100644 --- a/README.md +++ b/README.md @@ -425,713 +425,713 @@ We recognize all types of contributions. This project follows the [all-contribut Sarthak Saxena
Sarthak Saxena

💻 Nick McIntyre
Nick McIntyre

🔌 🐛 Amey Bhavsar
Amey Bhavsar

🐛 💡 - Minjun Kim
Minjun Kim

🐛 🌍 Fisher Diede
Fisher Diede

💻 karinaxlpz
karinaxlpz

🌍 + Samuel Alarco Cantos
Samuel Alarco Cantos

🌍 - Samuel Alarco Cantos
Samuel Alarco Cantos

🌍 DIVYANSHU RAJ
DIVYANSHU RAJ

💻 🐛 📖 sm7515
sm7515

📖 💡 Aditya Rachman Putra
Aditya Rachman Putra

📖 shaharyarshamshi
shaharyarshamshi

🌍 Ayush Jain
Ayush Jain

🌍 + Summer Rizzo
Summer Rizzo

📖 - Summer Rizzo
Summer Rizzo

📖 Aierie
Aierie

💻 🐛 Mateusz Swiatkowski
Mateusz Swiatkowski

💻 🐛 XingZiLong
XingZiLong

🌍 ov
ov

🌍 Kyle James
Kyle James

💻 + Abhi Gulati
Abhi Gulati

📖 - Abhi Gulati
Abhi Gulati

📖 Jeremy Tuloup
Jeremy Tuloup

📖 Luis Morales-Navarro
Luis Morales-Navarro

️️️️♿️ Yuki
Yuki

🌍 cedarfall
cedarfall

📖 Isaac Durazo
Isaac Durazo

🌍 + İsmail Namdar
İsmail Namdar

💻 ⚠️ - İsmail Namdar
İsmail Namdar

💻 ⚠️ skyperx
skyperx

💻 Joseph Aronson
Joseph Aronson

💻 🐛 Haider Ali Punjabi
Haider Ali Punjabi

💻 Swapnil-2001
Swapnil-2001

📖 Takuma Kira
Takuma Kira

🐛 💻 ⚠️ + Mohammad Hussain Nagaria
Mohammad Hussain Nagaria

🐛 - Mohammad Hussain Nagaria
Mohammad Hussain Nagaria

🐛 Tushar Choudhari
Tushar Choudhari

📖 💻 Nakul Shahdadpuri
Nakul Shahdadpuri

💻 Jacques P. du Toit
Jacques P. du Toit

💻 surajsurajsuraj
surajsurajsuraj

🐛 Connie Liu
Connie Liu

💻 🎨 + Zeke Sikelianos
Zeke Sikelianos

📖 - Zeke Sikelianos
Zeke Sikelianos

📖 Ramon Jr. Yniguez
Ramon Jr. Yniguez

💻 Benoît Bouré
Benoît Bouré

📖 Hitesh Kumar
Hitesh Kumar

💻 Sampo Rapeli
Sampo Rapeli

💡 Nick Müller
Nick Müller

🔌 + Keith Tan
Keith Tan

📖 - Keith Tan
Keith Tan

📖 Berke Özgen
Berke Özgen

🐛 💡 Musab Kılıç
Musab Kılıç

💻 ⚠️ Nicholas Marino
Nicholas Marino

📖 Greg Sadetsky
Greg Sadetsky

💻 Priya-Pathak
Priya-Pathak

💡 + Daniel Michel
Daniel Michel

💻 - Daniel Michel
Daniel Michel

💻 Nisar Hassan Naqvi
Nisar Hassan Naqvi

💻 Joshua Noble
Joshua Noble

📖 Liam Piesley
Liam Piesley

💻 Rishabh Taparia
Rishabh Taparia

💻 📖 Daniel Sarno
Daniel Sarno

💡 + Kunal Kumar Verma
Kunal Kumar Verma

📖 🐛 💻 - Kunal Kumar Verma
Kunal Kumar Verma

📖 🐛 💻 Bharath Kumar R
Bharath Kumar R

💻 Aditya Mohan
Aditya Mohan

💻 Arijit Kundu
Arijit Kundu

🐛 💻 📖 Tanner Dolby
Tanner Dolby

💻 sam delong
sam delong

💻 + Zhao Xin
Zhao Xin

💻 👀 - Zhao Xin
Zhao Xin

💻 👀 Sivaram D
Sivaram D

📖 💻 Pragya
Pragya

💻 Jonathan-David Schröder
Jonathan-David Schröder

🤔 💻 Shubham Kumar
Shubham Kumar

💻 Jean Pierre Charalambos
Jean Pierre Charalambos

💻 🔧 + Sai Bhushan
Sai Bhushan

💻 📖 - Sai Bhushan
Sai Bhushan

💻 📖 Long Phan
Long Phan

💻 Jean-Michaël Celerier
Jean-Michaël Celerier

🐛 So Sun Park
So Sun Park

📖 Daniel Adams
Daniel Adams

💻 📖 Aloneduckling
Aloneduckling

📖 + Mohana Sundaram S
Mohana Sundaram S

💻 - Mohana Sundaram S
Mohana Sundaram S

💻 TwoTicks
TwoTicks

💻 📖 💡 Kathryn Isabelle Lawrence
Kathryn Isabelle Lawrence

💻 🤔 Joonas Jokinen
Joonas Jokinen

🎨 Ajaya Mati
Ajaya Mati

💻 Suhas CV
Suhas CV

📖 💡 + Sanjay Singh Rajpoot
Sanjay Singh Rajpoot

📖 - Sanjay Singh Rajpoot
Sanjay Singh Rajpoot

📖 Chris P.
Chris P.

📖 Thomas Herlea
Thomas Herlea

🐛 💻 📖 Simranjeet Singh
Simranjeet Singh

💻 📢 🎨 👀 Rahul Mohata
Rahul Mohata

📖 Dave Pagurek
Dave Pagurek

💻 ⚠️ 💡 + Leo Kamwathi
Leo Kamwathi

💻 - Leo Kamwathi
Leo Kamwathi

💻 David Weiss
David Weiss

💻 📢 👀 📖 Chris Thomson
Chris Thomson

💻 🐛 mainstreamdev
mainstreamdev

🐛 Aaron George
Aaron George

🐛 Alex Lyons
Alex Lyons

📖 + Tyler Jordan
Tyler Jordan

📖 - Tyler Jordan
Tyler Jordan

📖 Ghales
Ghales

🎨 💻 🔧 JetStarBlues
JetStarBlues

📖 💻 Avelar
Avelar

📖 Oliver Steele
Oliver Steele

📖 MiniPear
MiniPear

📖 + Paul Wheeler
Paul Wheeler

💻 - Paul Wheeler
Paul Wheeler

💻 Nitin Rana
Nitin Rana

📖 Annie McKinnon
Annie McKinnon

🐛 💻 Jiwon Park (hanpanic)
Jiwon Park (hanpanic)

💻 truemaxdh
truemaxdh

🐛 💻 Katie
Katie

💻 + Guilherme Silveira
Guilherme Silveira

📖 - Guilherme Silveira
Guilherme Silveira

📖 Camille Roux
Camille Roux

💻 reejuBhattacharya
reejuBhattacharya

📖 💻 Akshat Nema
Akshat Nema

💻 Anshuman Maurya
Anshuman Maurya

🐛 Himanshu Malviya
Himanshu Malviya

🐛 + Samuel Cho
Samuel Cho

🐛 - Samuel Cho
Samuel Cho

🐛 Théodore Orfèvres
Théodore Orfèvres

🐛 Jyotiraditya Pradhan
Jyotiraditya Pradhan

📖 Zearin
Zearin

📖 pifragile
pifragile

🐛 Jstodd
Jstodd

🐛 + Jens Axel Søgaard
Jens Axel Søgaard

📖 🐛 - Jens Axel Søgaard
Jens Axel Søgaard

📖 🐛 oleboleskole3
oleboleskole3

🐛 A Welles
A Welles

🐛 andrei antonescu
andrei antonescu

🐛 Fun Planet
Fun Planet

🐛 Stig Møller Hansen
Stig Møller Hansen

🐛 + Derek Enlow
Derek Enlow

💻 - Derek Enlow
Derek Enlow

💻 Will Martin
Will Martin

🤔 Beau Muylle
Beau Muylle

📖 Ivy Feraco
Ivy Feraco

🐛 Gareth Williams
Gareth Williams

💻 Ikko Ashimine
Ikko Ashimine

📖 + Jonas Rinke
Jonas Rinke

🐛 - Jonas Rinke
Jonas Rinke

🐛 MATSUDA, Kouichi
MATSUDA, Kouichi

🐛 stampyzfanz
stampyzfanz

📖 tae
tae

🐛 Divyansh013
Divyansh013

🌍 rinkydevi
rinkydevi

🌍 + Coding for the Arts
Coding for the Arts

🐛 - Coding for the Arts
Coding for the Arts

🐛 Dan
Dan

🐛 sparshg
sparshg

🐛 Liz Peng
Liz Peng

🎨 💻 🔧 koolaidkrusade
koolaidkrusade

📖 smilee
smilee

💻 + CommanderRoot
CommanderRoot

💻 - CommanderRoot
CommanderRoot

💻 Philip Bell
Philip Bell

📖 tapioca24
tapioca24

🔌 Qianqian Ye
Qianqian Ye

💻 🎨 📖 📋 👀 🌍 Adarsh
Adarsh

🌍 kaabe1
kaabe1

🎨 📋 + Seb Méndez
Seb Méndez

🌍 - Seb Méndez
Seb Méndez

🌍 Ryuya
Ryuya

🐛 👀 💻 LEMIBANDDEXARI
LEMIBANDDEXARI

🌍 Vivek Tiwari
Vivek Tiwari

🌍 Kevin Grajeda
Kevin Grajeda

💻 anniezhengg
anniezhengg

💻 🎨 + Seung-Gi Kim(David)
Seung-Gi Kim(David)

🌍 - Seung-Gi Kim(David)
Seung-Gi Kim(David)

🌍 Ike Bischof
Ike Bischof

💻 Ong Zhi Zheng
Ong Zhi Zheng

🔌 bsubbaraman
bsubbaraman

🔌 Jenna deBoisblanc
Jenna deBoisblanc

🔌 manpreet
manpreet

📖 💻 ⚠️ + TetroGem
TetroGem

🤔 - TetroGem
TetroGem

🤔 ggorlen
ggorlen

💻 raclim
raclim

💻 David White
David White

💻 Akhil Raj
Akhil Raj

🐛 📖 🌍 🎨 💻 Brahvim
Brahvim

📖 + UnityOfFairfax
UnityOfFairfax

💻 - UnityOfFairfax
UnityOfFairfax

💻 INARI_DARKFOX
INARI_DARKFOX

💻 James Dunn
James Dunn

🐛 💻 Malay Vasa
Malay Vasa

🎨 💻 💡 wagedu
wagedu

🐛 Wes Lord
Wes Lord

📖 ⚠️ + pinky-pig
pinky-pig

🌍 - pinky-pig
pinky-pig

🌍 Chinmay Kadam
Chinmay Kadam

📖 Prateekgit
Prateekgit

💻 Aditya Shrivastav
Aditya Shrivastav

🐛 💻 📖 David
David

🐛 💻 Aryan Koundal
Aryan Koundal

💻 + alp tuğan
alp tuğan

💻 🔌 🔧 💡 - alp tuğan
alp tuğan

💻 🔌 🔧 💡 Laura Ciro
Laura Ciro

🌍 Kate Grant
Kate Grant

🐛 💻 ⚠️ Yograj Rajput
Yograj Rajput

💡 Dr. Holomorfo
Dr. Holomorfo

🌍 Quinton Ashley
Quinton Ashley

💻 🐛 🔌 + Xavier Góngora
Xavier Góngora

🌍 - Xavier Góngora
Xavier Góngora

🌍 hvillase
hvillase

🌍 Shivansh Sharma
Shivansh Sharma

🌍 Elliot-Hernandez
Elliot-Hernandez

🌍 hunahpu18
hunahpu18

🌍 Dewansh Thakur
Dewansh Thakur

🐛 + konstantinstanmeyer
konstantinstanmeyer

📖 - konstantinstanmeyer
konstantinstanmeyer

📖 al6862
al6862

🐛 💻 Monalisa Maity
Monalisa Maity

💻 Abhinav Kumar
Abhinav Kumar

🐛 Abhinav Srinivas
Abhinav Srinivas

🐛 💻 Sawai Singh Rajpurohit
Sawai Singh Rajpurohit

📖 🐛 💻 + Jack Dempsey
Jack Dempsey

🐛 - Jack Dempsey
Jack Dempsey

🐛 Aryan Thakor
Aryan Thakor

💻 Mostafa Ewis
Mostafa Ewis

🌍 Nabil Hassein
Nabil Hassein

🌍 AsukaMinato
AsukaMinato

🌍 💻 agrshch
agrshch

💻 + SHIBAHARA Hiroki
SHIBAHARA Hiroki

💻 🌍 - SHIBAHARA Hiroki
SHIBAHARA Hiroki

💻 🌍 siddhant
siddhant

🐛 💻 Caleb Foss
Caleb Foss

🤔 👀 🔌 💡 chechenxu
chechenxu

💻 Peter Marsh
Peter Marsh

💻 Ahmet Kaya
Ahmet Kaya

🌍 + oz
oz

💻 - oz
oz

💻 Munus Shih
Munus Shih

💻 Peiling Jiang
Peiling Jiang

💻 🎨 🌍 Decoy4ever
Decoy4ever

💻 Linda Paiste
Linda Paiste

🐛 💻 🎨 📖 shujulin
shujulin

🐛 🤔 🎨 + J Wong
J Wong

💻 📖 - J Wong
J Wong

💻 📖 Austin Lee Slominski
Austin Lee Slominski

💻 📖 💡 Nick Briz
Nick Briz

👀 Ayush Shankar
Ayush Shankar

💻 zelf0
zelf0

📖 JT Nimoy
JT Nimoy

💻 🔌 + Victor Morgan
Victor Morgan

📖 - Victor Morgan
Victor Morgan

📖 Sekani Warner
Sekani Warner

📖 e-Coucou
e-Coucou

🐛 Aaron Ni
Aaron Ni

📖 Onexi
Onexi

📖 Vijith Assar
Vijith Assar

💻 📖 + Dorothy R. Santos
Dorothy R. Santos

📖 📋 🔍 📢 - Dorothy R. Santos
Dorothy R. Santos

📖 📋 🔍 📢 tonipizza
tonipizza

🔍 💵 Anna Carreras
Anna Carreras

💡 📢 takawo
takawo

💡 📋 📝 Spencer Faith
Spencer Faith

💻 Ayush Sharma
Ayush Sharma

💻 + Aaron Casanova
Aaron Casanova

💻 - Aaron Casanova
Aaron Casanova

💻 Adam Smith
Adam Smith

💻 Acha
Acha

💻 💡 Aditya Siddheshwar
Aditya Siddheshwar

💻 Adwaith D
Adwaith D

💻 æmon
æmon

💻 + ajayTDM
ajayTDM

💻 - ajayTDM
ajayTDM

💻 Akash
Akash

💻 AliLordLoss
AliLordLoss

💻 Lauren
Lauren

💻 anagondesign
anagondesign

💻 András Gárdos
András Gárdos

💻 + AndrasGG
AndrasGG

💻 - AndrasGG
AndrasGG

💻 Aqmalp99
Aqmalp99

💻 Arbaaz
Arbaaz

💻 Arihant Parsoya
Arihant Parsoya

💻 ArshM17
ArshM17

💻 AsukaMinato
AsukaMinato

💻 + Jared Donovan
Jared Donovan

💻 💡 - Jared Donovan
Jared Donovan

💻 💡 beau-muylle
beau-muylle

💻 Yana Agun Siswanto
Yana Agun Siswanto

💻 Benjamin Davies
Benjamin Davies

💻 BerfinA
BerfinA

💻 Bernice Wu
Bernice Wu

💻 + Ben Scheiner
Ben Scheiner

💻 - Ben Scheiner
Ben Scheiner

💻 Bryan
Bryan

💻 Bulkan Evcimen
Bulkan Evcimen

💻 Brian Whitman
Brian Whitman

💻 cacoollib
cacoollib

💻 Caitlin
Caitlin

💻 + Caleb Eggensperger
Caleb Eggensperger

💻 - Caleb Eggensperger
Caleb Eggensperger

💻 Cody Fuller
Cody Fuller

💻 Christopher John Ryan
Christopher John Ryan

💻 Constance Yu
Constance Yu

💻 Cosme Escobedo
Cosme Escobedo

💻 Dominic Jodoin
Dominic Jodoin

💻 + Dabe Andre Enajada
Dabe Andre Enajada

💻 - Dabe Andre Enajada
Dabe Andre Enajada

💻 Dana Mulder
Dana Mulder

💻 Derrick McMillen
Derrick McMillen

💻 Dan Hoizner
Dan Hoizner

💻 digitalfrost
digitalfrost

💻 Thomas Diewald
Thomas Diewald

💻 + dummyAccount22
dummyAccount22

💻 - dummyAccount22
dummyAccount22

💻 Dusk
Dusk

💻 Ed Brannin
Ed Brannin

💻 Ewan Johnstone
Ewan Johnstone

💻 elgin mclaren
elgin mclaren

💻 epramer-godaddy
epramer-godaddy

💻 + Bob Ippolito
Bob Ippolito

💻 - Bob Ippolito
Bob Ippolito

💻 FAL
FAL

💻 Corey Farwell
Corey Farwell

💻 Shubham Rathore
Shubham Rathore

💻 Geraldo Neto
Geraldo Neto

💻 Gregor Martynus
Gregor Martynus

💻 + Gracia-zhang
Gracia-zhang

💻 - Gracia-zhang
Gracia-zhang

💻 Brett Cooper
Brett Cooper

💻 Half Scheidl
Half Scheidl

💻 Ashris
Ashris

💻 Arijit
Arijit

💻 Urvashi
Urvashi

💻 💡 + José Miguel Tajuelo Garrigós
José Miguel Tajuelo Garrigós

💻 - José Miguel Tajuelo Garrigós
José Miguel Tajuelo Garrigós

💻 Jai Kotia
Jai Kotia

💻 Jatin Panjwani
Jatin Panjwani

💻 jeong
jeong

💻 Jesús Enrique Rascón
Jesús Enrique Rascón

💻 Joseph Hong
Joseph Hong

💻 + Jithin KS
Jithin KS

💻 💡 - Jithin KS
Jithin KS

💻 💡 Jason Mandel
Jason Mandel

💻 JoeCastor
JoeCastor

💻 Juan Irache
Juan Irache

💻 juliane nagao
juliane nagao

💻 Chan Jun Shern
Chan Jun Shern

💻 + Ashley Kang
Ashley Kang

💻 - Ashley Kang
Ashley Kang

💻 Darío Hereñú
Darío Hereñú

💻 Sithe Ncube
Sithe Ncube

💻 Laksh Singla
Laksh Singla

💻 Leslie Yip
Leslie Yip

💻 linnhallonqvist
linnhallonqvist

💻 + Frederik Ring
Frederik Ring

💻 - Frederik Ring
Frederik Ring

💻 maddyfisher
maddyfisher

💻 Caleb Mazalevskis
Caleb Mazalevskis

💻 manpreet
manpreet

💻 David Aerne
David Aerne

💻 Naoto Hieda
Naoto Hieda

💻 + min-kim42
min-kim42

💻 - min-kim42
min-kim42

💻 M
M

💻 Adam Král
Adam Král

💻 Ben Greenberg
Ben Greenberg

💻 Pratyay Banerjee
Pratyay Banerjee

💻 Nikhil
Nikhil

💻 + Niki Ito
Niki Ito

💻 - Niki Ito
Niki Ito

💻 Nik Nyby
Nik Nyby

💻 nully0x
nully0x

💻 odm275
odm275

💻 Oleksii Bulba
Oleksii Bulba

💻 paollabd
paollabd

💻 + Prateek Jain
Prateek Jain

💻 - Prateek Jain
Prateek Jain

💻 Ceesjan Luiten
Ceesjan Luiten

💻 NIINOMI
NIINOMI

💻 Ben Wendt
Ben Wendt

💻 Reijo Vosu
Reijo Vosu

💻 peter
peter

💻 + Sachin Varghese
Sachin Varghese

💻 - Sachin Varghese
Sachin Varghese

💻 Sarah Groff Hennigh-Palermo
Sarah Groff Hennigh-Palermo

💻 Dwiferdio Seagal Putra
Dwiferdio Seagal Putra

💻 Abishake
Abishake

💻 sheamus
sheamus

💻 Liang Tang
Liang Tang

💻 + Michael J Conrad
Michael J Conrad

💻 - Michael J Conrad
Michael J Conrad

💻 Samir Ghosh
Samir Ghosh

💻 Stalgia Grigg
Stalgia Grigg

💻 Stef Tervelde
Stef Tervelde

💻 stormCup
stormCup

💻 Cliff Su
Cliff Su

💻 + sz245
sz245

💻 - sz245
sz245

💻 Alex Troesch
Alex Troesch

💻 Maciej Stankiewicz
Maciej Stankiewicz

💻 Alberto Di Biase
Alberto Di Biase

💻 Vedhant Agarwal
Vedhant Agarwal

💻 Varsha Verma
Varsha Verma

💻 + vipulrawat
vipulrawat

💻 - vipulrawat
vipulrawat

💻 Erik Butcher
Erik Butcher

💻 Wade Marshall
Wade Marshall

💻 XTY
XTY

💻 Jenna
Jenna

💻 Yifan Mai
Yifan Mai

💻 + Inhwa
Inhwa

💻 - Inhwa
Inhwa

💻 Yousef Abu-Salah
Yousef Abu-Salah

💻 Zoe Stenger
Zoe Stenger

💻 mcturner1995
mcturner1995

💻 Seonghyeon Kim
Seonghyeon Kim

💻 🌍 Gus Becker
Gus Becker

🚧 🤔 💬 + senbaku
senbaku

💡 📝 🌍 - senbaku
senbaku

💡 📝 🌍 reona396
reona396

💡 🌍 Mauricio Verano Merino
Mauricio Verano Merino

📋 🔬 🧑‍🏫 RandomGamingDev
RandomGamingDev

💻 🐛 Wu Che Yu
Wu Che Yu

📋 📝 📹 Sarah Ciston
Sarah Ciston

🧑‍🏫 📖 📋 + Tiago Hermano
Tiago Hermano

🌍 👀 - Tiago Hermano
Tiago Hermano

🌍 👀 Unicar
Unicar

🌍 💡 Yolonanido
Yolonanido

📋 Raphaël de Courville
Raphaël de Courville

📋 📹 🤔 📣 Mike
Mike

💻 🐛 Ankush Banik
Ankush Banik

🐛 💻 📢 💬 + tetunori
tetunori

📝 💻 💡 🔧 - tetunori
tetunori

📝 💻 💡 🔧 Emma Krantz
Emma Krantz

🐛 💻 Zac Tolle
Zac Tolle

️️️️♿️ 💻 🔧 💡 Dharshan
Dharshan

💻 Sandeep Kumar Bhagat
Sandeep Kumar Bhagat

🎨 💻 Gaurav Tiwary
Gaurav Tiwary

💻 + Garima
Garima

💻 - Garima
Garima

💻 Lakshay Joshi
Lakshay Joshi

💻 perminder-17
perminder-17

💻 🐛 📖 💡 🤔 🔌 📆 📣 💬 🔬 Yash Pandey
Yash Pandey

🐛 💻 Aditya Deshpande
Aditya Deshpande

🐛 📖 Alejandro
Alejandro

🐛 💻 + Diya Solanki
Diya Solanki

💻 - Diya Solanki
Diya Solanki

💻 mhsh312
mhsh312

💻 🐛 wackbyte
wackbyte

📖 Ajeet Pratap Singh
Ajeet Pratap Singh

💻 🐛 Jai Vignesh J
Jai Vignesh J

💻 cab_kyabe
cab_kyabe

🐛 💻 + Vishwas Srivastava
Vishwas Srivastava

💻 - Vishwas Srivastava
Vishwas Srivastava

💻 suhani6904
suhani6904

🌍 Nabeel (Dexter)
Nabeel (Dexter)

💻 Umang Utkarsh
Umang Utkarsh

📖 🌍 aditya123473892
aditya123473892

💻 🐛 📖 Harsh Range
Harsh Range

💻 🐛 + Sudhanshu Tiwari
Sudhanshu Tiwari

💻 - Sudhanshu Tiwari
Sudhanshu Tiwari

💻 mohamedalisaifudeen
mohamedalisaifudeen

🐛 Aryan Singh
Aryan Singh

💻 nikhilkalburgi
nikhilkalburgi

🐛 📖 Samrudh Shetty
Samrudh Shetty

️️️️♿️ Mattia Micheletta Merlin
Mattia Micheletta Merlin

💡 💻 ⚠️ + Armaan Gupta
Armaan Gupta

💻 - Armaan Gupta
Armaan Gupta

💻 Harman Batheja
Harman Batheja

🌍 🐛 PracDuckling
PracDuckling

🐛 📖 Poulav Bhowmick
Poulav Bhowmick

🐛 📖 Keshav Malik
Keshav Malik

💻 📖 🐛 Deveshi Dwivedi
Deveshi Dwivedi

💻 + Mohit Balwani
Mohit Balwani

💻 - Mohit Balwani
Mohit Balwani

💻 rahulrangers
rahulrangers

💻 Sudhanshu Tiwari
Sudhanshu Tiwari

🐛 💻 meezwhite
meezwhite

📖 pie999
pie999

📖 Muhammad Haroon
Muhammad Haroon

📖 💻 + Nat Decker
Nat Decker

️️️️♿️ 📖 - Nat Decker
Nat Decker

️️️️♿️ 📖 Miaoye Que
Miaoye Que

🌍 🚧 sphantom-code
sphantom-code

📖 Minwook Park
Minwook Park

🌍 Harrycheng233
Harrycheng233

🌍 Diana Galindo
Diana Galindo

🌍 + Lingxiao Wang
Lingxiao Wang

🌍 - Lingxiao Wang
Lingxiao Wang

🌍 ml.008
ml.008

🌍 EmilioOcelotl
EmilioOcelotl

🌍 Teixido
Teixido

🌍 IENGROUND
IENGROUND

🌍 Orwiss
Orwiss

🌍 + Aditya Rana
Aditya Rana

🌍 - Aditya Rana
Aditya Rana

🌍 Eshaan Aggarwal
Eshaan Aggarwal

🌍 everything became blue
everything became blue

🌍 YewonCALLI
YewonCALLI

🌍 SejinOH
SejinOH

🌍 👀 Surbhi Pittie
Surbhi Pittie

🌍 + nancy
nancy

🌍 - nancy
nancy

🌍 Akash Jaiswal
Akash Jaiswal

🌍 Jack B. Du
Jack B. Du

💡 togekisse
togekisse

🌍 tuan
tuan

🌍 🤔 Janis Sepúlveda
Janis Sepúlveda

🌍 🤔 + viola
viola

🌍 🤔 - viola
viola

🌍 🤔 yu
yu

🌍 🤔 李坤霖
李坤霖

🐛 Leo Wang
Leo Wang

🌍 Hilary Lau
Hilary Lau

💻 ⚠️ Bobby Kazimiroff
Bobby Kazimiroff

📖 + Nahuel Palumbo
Nahuel Palumbo

🐛 📖 - Nahuel Palumbo
Nahuel Palumbo

🐛 📖 lottihill
lottihill

📖 🐛 Julio Lab
Julio Lab

📖 Jordan Sucher
Jordan Sucher

🐛 💻 iambiancafonseca
iambiancafonseca

📖 Vishal Sharma
Vishal Sharma

💻 + PiyushChandra17
PiyushChandra17

💻 🐛 👀 - PiyushChandra17
PiyushChandra17

💻 🐛 👀 Daniel Grantham
Daniel Grantham

💻 Monica Powell
Monica Powell

📢 💡 📖 🐛 Rohan Julka
Rohan Julka

💻 Mr. Algorithm
Mr. Algorithm

📖 sambensim
sambensim

📖 + NicholasGillen
NicholasGillen

📖 - NicholasGillen
NicholasGillen

📖 Abhinav kumar
Abhinav kumar

📖 chaski
chaski

🔬 💻 💡 Evorage
Evorage

🐛 💻 Daniel Marino
Daniel Marino

📖 Shahma Ansari
Shahma Ansari

🐛 + Manan Arora
Manan Arora

📖 - Manan Arora
Manan Arora

📖 Serena20003
Serena20003

💻 Souvik Kumar
Souvik Kumar

📖 Abdiel Lopez
Abdiel Lopez

🧑‍🏫 Pim Tournaye
Pim Tournaye

💻 Martin Lorentzon
Martin Lorentzon

🐛 + Rishi
Rishi

💻 🐛 - Rishi
Rishi

💻 🐛 FORCHA PEARL
FORCHA PEARL

💻 c-dacanay
c-dacanay

🎨 📋 💡 mathewpan2
mathewpan2

💻 cog25
cog25

🌍 Aarati Akkapeddi
Aarati Akkapeddi

💻 🤔 + Maya Arguelles
Maya Arguelles

💻 - Maya Arguelles
Maya Arguelles

💻 Shoury Singh
Shoury Singh

💻 Melody Sharp
Melody Sharp

🐛 Tibor Udvari
Tibor Udvari

💻 willallstet
willallstet

📖 Ashwani Dey
Ashwani Dey

📖 + Ilona Brand
Ilona Brand

🐛 - Ilona Brand
Ilona Brand

🐛 Antoinette Bumatay-Chan
Antoinette Bumatay-Chan

📖 benpalevsky
benpalevsky

📖 jeanette
jeanette

💻 William Hazard
William Hazard

💡 Vishesh Rawal
Vishesh Rawal

🐛 📖 💻 + Callie
Callie

📖 💻 - Callie
Callie

📖 💻 Jared Berghold
Jared Berghold

📖 computational mama
computational mama

💻 Fabian Morón Zirfas
Fabian Morón Zirfas

📖 💻 Luke Plowden
Luke Plowden

💻 Martin Leopold Groedl
Martin Leopold Groedl

🐛 💻 + ashish singh
ashish singh

💻 - ashish singh
ashish singh

💻 blackboxlogic
blackboxlogic

📖 ℤ

📖 dhanush
dhanush

📖 ma haidong
ma haidong

🐛 💻 Rishab Kumar Jha
Rishab Kumar Jha

🐛 💻 + Rajas Samse
Rajas Samse

💻 📖 - Rajas Samse
Rajas Samse

💻 📖 Jordan Philyaw
Jordan Philyaw

📖 oliver thurley
oliver thurley

📖 💻 Renjie Li
Renjie Li

📖 💻 Vaivaswat Dubey
Vaivaswat Dubey

💻 Xin Xin
Xin Xin

📋 📢 🧑‍🏫 🤔 + Ashish Karn
Ashish Karn

💻 - Ashish Karn
Ashish Karn

💻 Darren Kessner
Darren Kessner

💡 Animesh Sinha
Animesh Sinha

💡 Kathryn Lichlyter
Kathryn Lichlyter

💡 Greg Albers
Greg Albers

💡 Marco Macarena
Marco Macarena

💡 + Kristian Hamilton
Kristian Hamilton

💡 - Kristian Hamilton
Kristian Hamilton

💡 Keshav Gupta
Keshav Gupta

💡 Ritesh Patil
Ritesh Patil

💡 Gabriel Sroka
Gabriel Sroka

💡 Casey Conchinha
Casey Conchinha

💡 davidblitz
davidblitz

💡 + crh82
crh82

💡 - crh82
crh82

💡 Aaron Welles
Aaron Welles
💡 Seyko
Seyko

💻 Xevi H. Aqeel
Xevi H. Aqeel

💡 🎨 Greg Stanton
Greg Stanton

🐛 💻 📖 💡 🤔 🔌 📆 📣 💬 🔬 Bojidar Marinov
Bojidar Marinov

💻 ⚠️ + Chloe Yan
Chloe Yan

📖 - Chloe Yan
Chloe Yan

📖 Mayank Verma
Mayank Verma

💻 Lauren Berrios
Lauren Berrios

🤔 roxi09
roxi09

🤔 Jackie Liu
Jackie Liu

🤔 Carrie Wang
Carrie Wang

🤔 + Himanshu Kholiya
Himanshu Kholiya

💻 - Himanshu Kholiya
Himanshu Kholiya

💻 mclark414
mclark414

🤔 Mx. Ramsey
Mx. Ramsey

🤔 Franolich Design
Franolich Design

🐛 💻 Vik
Vik

💻 🐛 🌍 Qingfeng Huang
Qingfeng Huang

🌍 + HughJacks
HughJacks

💻 From 22346d5eea29763cf1915ae7c846aa7f17827188 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 22 Apr 2025 13:24:30 +0000 Subject: [PATCH 127/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index adb21ac26b..cb5da8551d 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6794,6 +6794,15 @@ "contributions": [ "translation" ] + }, + { + "login": "HughJacks", + "name": "HughJacks", + "avatar_url": "https://avatars.githubusercontent.com/u/102194905?v=4", + "profile": "https://github.com/HughJacks", + "contributions": [ + "code" + ] } ], "repoType": "github", From e0fb0d400415b7d1de3124b6082e5ecaa1590350 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 23 Apr 2025 13:48:34 +0000 Subject: [PATCH 128/282] docs: update README.md [skip ci] --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 3012d5c6c1..949c66e5f2 100644 --- a/README.md +++ b/README.md @@ -1133,6 +1133,9 @@ We recognize all types of contributions. This project follows the [all-contribut Qingfeng Huang
Qingfeng Huang

🌍 HughJacks
HughJacks

💻 + + Jack L
Jack L

🐛 📖 + From bb0128c880d8a5f371c59662e90762a6dc660c80 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 23 Apr 2025 13:48:41 +0000 Subject: [PATCH 129/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index cb5da8551d..21e77167e8 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6803,6 +6803,16 @@ "contributions": [ "code" ] + }, + { + "login": "jackeddielove", + "name": "Jack L", + "avatar_url": "https://avatars.githubusercontent.com/u/130420780?v=4", + "profile": "http://jackeddielove.github.io", + "contributions": [ + "bug", + "doc" + ] } ], "repoType": "github", From 72882324512339450c128fa03b4c882f95d38c0e Mon Sep 17 00:00:00 2001 From: Lalit Narayan Yadav <162928571+LalitNarayanYadav@users.noreply.github.com> Date: Fri, 25 Apr 2025 17:58:05 +0530 Subject: [PATCH 130/282] "Fix typo in directionalLight reference (main branch)" - #7743 --- src/webgl/light.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webgl/light.js b/src/webgl/light.js index 3163bc6a65..7197cb70d8 100644 --- a/src/webgl/light.js +++ b/src/webgl/light.js @@ -482,7 +482,7 @@ p5.prototype.specularColor = function (v1, v2, v3) { * three parameters, `v1`, `v2`, and `v3`, set the light’s color using the * current colorMode(). The last parameter, * `direction` sets the light’s direction using a - * p5.Geometry object. For example, + * p5.Vector object. For example, * `directionalLight(255, 0, 0, lightDir)` creates a red `(255, 0, 0)` light * that shines in the direction the `lightDir` vector points. * From fbffbc173793197daff9ebc7937f58dad3bdd1b6 Mon Sep 17 00:00:00 2001 From: IIITM-Jay Date: Tue, 6 May 2025 23:36:25 +0530 Subject: [PATCH 131/282] Consistent `movedX` and `movedY` behaviour across zoom levels --- src/events/mouse.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/events/mouse.js b/src/events/mouse.js index 0f3985a2db..4b2446913c 100644 --- a/src/events/mouse.js +++ b/src/events/mouse.js @@ -819,21 +819,27 @@ p5.prototype.mouseIsPressed = false; p5.prototype._updateNextMouseCoords = function(e) { if (this._curElement !== null && (!e.touches || e.touches.length > 0)) { + this._updateMouseCoords(); + const mousePos = getMousePos( this._curElement.elt, this.width, this.height, e ); - this._setProperty('movedX', e.movementX); - this._setProperty('movedY', e.movementY); + this._setProperty('mouseX', mousePos.x); this._setProperty('mouseY', mousePos.y); this._setProperty('winMouseX', mousePos.winX); this._setProperty('winMouseY', mousePos.winY); + + const deltaX = this.mouseX - this.pmouseX; + const deltaY = this.mouseY - this.pmouseY; + this._setProperty('movedX', deltaX); + this._setProperty('movedY', deltaY); } + if (!this._hasMouseInteracted) { - // For first draw, make previous and next equal this._updateMouseCoords(); this._setProperty('_hasMouseInteracted', true); } From 173e09552c698cb2ec5e107d42280edfc9c75995 Mon Sep 17 00:00:00 2001 From: vansh kabra Date: Tue, 29 Apr 2025 18:51:16 +0530 Subject: [PATCH 132/282] Fix _isglobal flag in init method and correct comments in main.js --- src/core/main.js | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/core/main.js b/src/core/main.js index 36db13d4e5..4e9684dc80 100644 --- a/src/core/main.js +++ b/src/core/main.js @@ -37,7 +37,7 @@ class p5 { ////////////////////////////////////////////// // PUBLIC p5 PROPERTIES AND METHODS ////////////////////////////////////////////// - + this._isGlobal = !sketch; /** * A function that's called once to load assets before the sketch runs. * @@ -286,7 +286,6 @@ class p5 { this._glAttributes = null; this._requestAnimId = 0; this._preloadCount = 0; - this._isGlobal = false; this._loop = true; this._startListener = null; this._initializeInstanceVariables(); @@ -661,21 +660,11 @@ class p5 { // ensure correct reporting of window dimensions this._updateWindowSize(); - // call any registered init functions - this._registeredMethods.init.forEach(function(f) { - if (typeof f !== 'undefined') { - f.call(this); - } - }, this); - // Set up promise preloads - this._setupPromisePreloads(); - const friendlyBindGlobal = this._createFriendlyGlobalFunctionBinder(); // If the user has created a global setup or draw function, // assume "global" mode and make everything global (i.e. on the window) - if (!sketch) { - this._isGlobal = true; + if (this._isGlobal) { p5.instance = this; // Loop through methods on the prototype and attach them to the window for (const p in p5.prototype) { @@ -710,8 +699,14 @@ class p5 { p5._checkForUserDefinedFunctions(this); } - // Bind events to window (not using container div bc key events don't work) + this._updateWindowSize(); + + // call any registered init functions + this.callRegisteredHooksFor('init'); + // Set up promise preloads + this._setupPromisePreloads(); + // Bind events to window (not using container div bc key events don't work) for (const e in this._events) { const f = this[`_on${e}`]; if (f) { From f7233a4a4bb2777d69794d30edaec54885f46cc1 Mon Sep 17 00:00:00 2001 From: AhmedMaged Date: Tue, 13 May 2025 13:09:05 +0300 Subject: [PATCH 133/282] Fix: keyTyped() can now accept the same char consecutively --- src/events/keyboard.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/events/keyboard.js b/src/events/keyboard.js index f6e3b04703..bbb7ab8b61 100644 --- a/src/events/keyboard.js +++ b/src/events/keyboard.js @@ -441,11 +441,13 @@ p5.prototype.keyCode = 0; *
*/ p5.prototype._onkeydown = function(e) { + // Ignore repeated key events when holding down a key if (e.repeat) { - // Ignore repeated key events when holding down a key + this._setProperty('isKeyRepeated', true); return; } + this._setProperty('isKeyRepeated', false); this._setProperty('isKeyPressed', true); this._setProperty('keyIsPressed', true); this._setProperty('keyCode', e.which); @@ -781,7 +783,7 @@ p5.prototype._onkeyup = function(e) { *
*/ p5.prototype._onkeypress = function(e) { - if (e.which === this._lastKeyCodeTyped) { + if (e.which === this._lastKeyCodeTyped && this.isKeyRepeated) { // prevent multiple firings return; } From 197f3ee1953948803a554d2e064d6461a4c175ec Mon Sep 17 00:00:00 2001 From: IIITM-Jay Date: Tue, 13 May 2025 16:51:24 +0530 Subject: [PATCH 134/282] removed redundant calling of updateMouseCoords() --- src/events/mouse.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/events/mouse.js b/src/events/mouse.js index 4b2446913c..536c68f11f 100644 --- a/src/events/mouse.js +++ b/src/events/mouse.js @@ -819,8 +819,6 @@ p5.prototype.mouseIsPressed = false; p5.prototype._updateNextMouseCoords = function(e) { if (this._curElement !== null && (!e.touches || e.touches.length > 0)) { - this._updateMouseCoords(); - const mousePos = getMousePos( this._curElement.elt, this.width, From f86a20e7befbe890f4190e6fc6efcc723cdb5ab4 Mon Sep 17 00:00:00 2001 From: ksen0 Date: Wed, 14 May 2025 10:08:04 +0200 Subject: [PATCH 135/282] 1.11.6 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9574b8aef7..130461ed71 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "p5", - "version": "1.11.5", + "version": "1.11.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "p5", - "version": "1.11.5", + "version": "1.11.6", "license": "LGPL-2.1", "devDependencies": { "@babel/core": "^7.7.7", diff --git a/package.json b/package.json index 47c2550f6e..11112ab31c 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "node --require @babel/register ./utils/sample-linter.js" ] }, - "version": "1.11.5", + "version": "1.11.6", "devDependencies": { "@babel/core": "^7.7.7", "@babel/preset-env": "^7.10.2", From dee8f69a6b6c2be2553321cc34e36d50ce433d91 Mon Sep 17 00:00:00 2001 From: kit <1304340+ksen0@users.noreply.github.com> Date: Wed, 14 May 2025 12:02:53 +0200 Subject: [PATCH 136/282] Publish 1.x under r1 tag --- .github/workflows/release-workflow.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release-workflow.yml b/.github/workflows/release-workflow.yml index 7a55f0b273..a96e97b7c8 100644 --- a/.github/workflows/release-workflow.yml +++ b/.github/workflows/release-workflow.yml @@ -73,6 +73,7 @@ jobs: uses: JS-DevTools/npm-publish@v1 with: token: ${{ secrets.NPM_TOKEN }} + tag: r1 # 4. Update p5.js website - name: Clone p5.js website From 5f0fcfac9d03a5ec2fee271a98fa1d1edb70ec68 Mon Sep 17 00:00:00 2001 From: ksen0 Date: Wed, 14 May 2025 13:03:05 +0200 Subject: [PATCH 137/282] 1.11.7 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 130461ed71..e9291f1fc6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "p5", - "version": "1.11.6", + "version": "1.11.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "p5", - "version": "1.11.6", + "version": "1.11.7", "license": "LGPL-2.1", "devDependencies": { "@babel/core": "^7.7.7", diff --git a/package.json b/package.json index 11112ab31c..132b2ad0e4 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "node --require @babel/register ./utils/sample-linter.js" ] }, - "version": "1.11.6", + "version": "1.11.7", "devDependencies": { "@babel/core": "^7.7.7", "@babel/preset-env": "^7.10.2", From f3255001a38b65817b667bc48e8b068257ee4d03 Mon Sep 17 00:00:00 2001 From: LalitNarayanYadav Date: Thu, 15 May 2025 00:39:11 +0530 Subject: [PATCH 138/282] Regenerate README with 64px contributor avatars --- README.md | 1550 ++++++++++++++++++++++++++--------------------------- 1 file changed, 775 insertions(+), 775 deletions(-) diff --git a/README.md b/README.md index 949c66e5f2..5a72e7568e 100644 --- a/README.md +++ b/README.md @@ -118,1023 +118,1023 @@ We recognize all types of contributions. This project follows the [all-contribut - - - - - - + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - +
Lauren McCarthy
Lauren McCarthy

Jason Sigal
Jason Sigal

Karen
Karen

Evelyn Eastmond
Evelyn Eastmond

Daniel Shiffman
Daniel Shiffman

Casey Reas
Casey Reas

Lauren McCarthy
Lauren McCarthy

Jason Sigal
Jason Sigal

Karen
Karen

Evelyn Eastmond
Evelyn Eastmond

Daniel Shiffman
Daniel Shiffman

Casey Reas
Casey Reas

Ben Fry
Ben Fry

Kenneth Lim
Kenneth Lim

🐛 💻 📖
kate hollenbach
kate hollenbach

Stalgia Grigg
Stalgia Grigg

Jerel Johnson
Jerel Johnson

Saksham Saxena
Saksham Saxena

Ben Fry
Ben Fry

Kenneth Lim
Kenneth Lim

🐛 💻 📖
kate hollenbach
kate hollenbach

Stalgia Grigg
Stalgia Grigg

Jerel Johnson
Jerel Johnson

Saksham Saxena
Saksham Saxena

saber khan
saber khan

Daniel Howe
Daniel Howe

Kevin Siwoff
Kevin Siwoff

Atul Varma
Atul Varma

Jess Klein
Jess Klein

uno seis tres
uno seis tres

saber khan
saber khan

Daniel Howe
Daniel Howe

Kevin Siwoff
Kevin Siwoff

Atul Varma
Atul Varma

Jess Klein
Jess Klein

uno seis tres
uno seis tres

susan evans
susan evans

Saskia Freeke
Saskia Freeke

Phoenix Perry
Phoenix Perry

jesse cahn-thompson
jesse cahn-thompson

Lee T
Lee T

Chelly Jin
Chelly Jin

susan evans
susan evans

Saskia Freeke
Saskia Freeke

Phoenix Perry
Phoenix Perry

jesse cahn-thompson
jesse cahn-thompson

Lee T
Lee T

Chelly Jin
Chelly Jin

L05
L05

DIYgirls
DIYgirls

lam802
lam802

Maya Man
Maya Man

Tega Brain
Tega Brain

luisaph
luisaph

L05
L05

DIYgirls
DIYgirls

lam802
lam802

Maya Man
Maya Man

Tega Brain
Tega Brain

luisaph
luisaph

AlM Chng
AlM Chng

aarón montoya-moraga
aarón montoya-moraga

Cassie Tarakajian
Cassie Tarakajian

Niklas Peters
Niklas Peters

📖
Mathura MG
Mathura MG

Yining Shi
Yining Shi

AlM Chng
AlM Chng

aarón montoya-moraga
aarón montoya-moraga

Cassie Tarakajian
Cassie Tarakajian

Niklas Peters
Niklas Peters

📖
Mathura MG
Mathura MG

Yining Shi
Yining Shi

Jen Kagan
Jen Kagan

Jiashan Wu
Jiashan Wu

Marc Abbey
Marc Abbey

K.Adam White
K.Adam White

Eden Cridge
Eden Cridge

💻 🐛 👀 ⚠️
Michael Hadley
Michael Hadley

Jen Kagan
Jen Kagan

Jiashan Wu
Jiashan Wu

Marc Abbey
Marc Abbey

K.Adam White
K.Adam White

Eden Cridge
Eden Cridge

💻 🐛 👀 ⚠️
Michael Hadley
Michael Hadley

Todd H. Page
Todd H. Page

Jared Sprague
Jared Sprague

💻 📖 💡 💵 ⚠️ 🐛
evelyn masso
evelyn masso

Blaize Kaye
Blaize Kaye

Sanchit Kapoor
Sanchit Kapoor

Oliver Wright
Oliver Wright

Todd H. Page
Todd H. Page

Jared Sprague
Jared Sprague

💻 📖 💡 💵 ⚠️ 🐛
evelyn masso
evelyn masso

Blaize Kaye
Blaize Kaye

Sanchit Kapoor
Sanchit Kapoor

Oliver Wright
Oliver Wright

Matthew Kaney
Matthew Kaney

Spongman
Spongman

Claire K-V
Claire K-V

R. Luke DuBois
R. Luke DuBois

Kevin Barabash
Kevin Barabash

codeanticode
codeanticode

Matthew Kaney
Matthew Kaney

Spongman
Spongman

Claire K-V
Claire K-V

R. Luke DuBois
R. Luke DuBois

Kevin Barabash
Kevin Barabash

codeanticode
codeanticode

Bob Holt
Bob Holt

Sarah Groff Hennigh-Palermo
Sarah Groff Hennigh-Palermo

Jordan Shaw
Jordan Shaw

brightredchilli
brightredchilli

Derek J. Kinsman
Derek J. Kinsman

harkirat singh
harkirat singh

Bob Holt
Bob Holt

Sarah Groff Hennigh-Palermo
Sarah Groff Hennigh-Palermo

Jordan Shaw
Jordan Shaw

brightredchilli
brightredchilli

Derek J. Kinsman
Derek J. Kinsman

harkirat singh
harkirat singh

GoToLoop
GoToLoop

Max Goldstein
Max Goldstein

XY Feng
XY Feng

Sparsh Paliwal
Sparsh Paliwal

Austin Cawley-Edwards
Austin Cawley-Edwards

📖 💡
taseenb
taseenb

GoToLoop
GoToLoop

Max Goldstein
Max Goldstein

XY Feng
XY Feng

Sparsh Paliwal
Sparsh Paliwal

Austin Cawley-Edwards
Austin Cawley-Edwards

📖 💡
taseenb
taseenb

Yannick Assogba
Yannick Assogba

John Pasquarello
John Pasquarello

💻
Kevin Workman
Kevin Workman

📖
gauini
gauini

David Wicks
David Wicks

Guillermo Montecinos
Guillermo Montecinos

Yannick Assogba
Yannick Assogba

John Pasquarello
John Pasquarello

💻
Kevin Workman
Kevin Workman

📖
gauini
gauini

David Wicks
David Wicks

Guillermo Montecinos
Guillermo Montecinos

Shawn Van Every
Shawn Van Every

Sinan Ascioglu
Sinan Ascioglu

Abe Pazos
Abe Pazos

Char
Char

Gene Kogan
Gene Kogan

Jason Mandel
Jason Mandel

Shawn Van Every
Shawn Van Every

Sinan Ascioglu
Sinan Ascioglu

Abe Pazos
Abe Pazos

Char
Char

Gene Kogan
Gene Kogan

Jason Mandel
Jason Mandel

Mark Russo
Mark Russo

Jonathan Dahan
Jonathan Dahan

Darius Morawiec
Darius Morawiec

Darby Rathbone
Darby Rathbone

hrishit
hrishit

Chiun Hau You
Chiun Hau You

Mark Russo
Mark Russo

Jonathan Dahan
Jonathan Dahan

Darius Morawiec
Darius Morawiec

Darby Rathbone
Darby Rathbone

hrishit
hrishit

Chiun Hau You
Chiun Hau You

Francesco Bigiarini
Francesco Bigiarini

Fabian Morón Zirfas
Fabian Morón Zirfas

Mike Anderson
Mike Anderson

Mikael Lindqvist
Mikael Lindqvist

Chris
Chris

Max Segal
Max Segal

Francesco Bigiarini
Francesco Bigiarini

Fabian Morón Zirfas
Fabian Morón Zirfas

Mike Anderson
Mike Anderson

Mikael Lindqvist
Mikael Lindqvist

Chris
Chris

Max Segal
Max Segal

Tyler Stefanich
Tyler Stefanich

Dave
Dave

Xavier Snelgrove
Xavier Snelgrove

Gareth Battensby
Gareth Battensby

Taeyoon Choi
Taeyoon Choi

AKASH RAJ
AKASH RAJ

Tyler Stefanich
Tyler Stefanich

Dave
Dave

Xavier Snelgrove
Xavier Snelgrove

Gareth Battensby
Gareth Battensby

Taeyoon Choi
Taeyoon Choi

AKASH RAJ
AKASH RAJ

Kevin Ho
Kevin Ho

Harsh Agrawal
Harsh Agrawal

Luca Damasco
Luca Damasco

Sam Lavigne
Sam Lavigne

Epic Jefferson
Epic Jefferson

Caroline Record
Caroline Record

Kevin Ho
Kevin Ho

Harsh Agrawal
Harsh Agrawal

Luca Damasco
Luca Damasco

Sam Lavigne
Sam Lavigne

Epic Jefferson
Epic Jefferson

Caroline Record
Caroline Record

Christine de Carteret
Christine de Carteret

Chris Hallberg
Chris Hallberg

David Newbury
David Newbury

piinthecloud
piinthecloud

Paolo Pedercini
Paolo Pedercini

Jason Alderman
Jason Alderman

Christine de Carteret
Christine de Carteret

Chris Hallberg
Chris Hallberg

David Newbury
David Newbury

piinthecloud
piinthecloud

Paolo Pedercini
Paolo Pedercini

Jason Alderman
Jason Alderman

Jennifer Jacobs
Jennifer Jacobs

Sepand Ansari
Sepand Ansari

Val Head
Val Head

Emily Chen
Emily Chen

Ben Moren
Ben Moren

Rune Skjoldborg Madsen
Rune Skjoldborg Madsen

Jennifer Jacobs
Jennifer Jacobs

Sepand Ansari
Sepand Ansari

Val Head
Val Head

Emily Chen
Emily Chen

Ben Moren
Ben Moren

Rune Skjoldborg Madsen
Rune Skjoldborg Madsen

Scott Murray
Scott Murray

Scott Garner
Scott Garner

b2renger
b2renger

Craig Pickard
Craig Pickard

mxchelle
mxchelle

Zach Rispoli
Zach Rispoli

Scott Murray
Scott Murray

Scott Garner
Scott Garner

b2renger
b2renger

Craig Pickard
Craig Pickard

mxchelle
mxchelle

Zach Rispoli
Zach Rispoli

Liu Chang
Liu Chang

Cristóbal Valenzuela
Cristóbal Valenzuela

Miles Peyton
Miles Peyton

Golan Levin
Golan Levin

feedzh
feedzh

Shahriar Rahman Rubayet
Shahriar Rahman Rubayet

Liu Chang
Liu Chang

Cristóbal Valenzuela
Cristóbal Valenzuela

Miles Peyton
Miles Peyton

Golan Levin
Golan Levin

feedzh
feedzh

Shahriar Rahman Rubayet
Shahriar Rahman Rubayet

Chiciuc Nicușor
Chiciuc Nicușor

Ken Miller
Ken Miller

Chandler McWilliams
Chandler McWilliams

Jaymz Rhime
Jaymz Rhime

Niels Joubert
Niels Joubert

Utkarsh Tiwari
Utkarsh Tiwari

Chiciuc Nicușor
Chiciuc Nicușor

Ken Miller
Ken Miller

Chandler McWilliams
Chandler McWilliams

Jaymz Rhime
Jaymz Rhime

Niels Joubert
Niels Joubert

Utkarsh Tiwari
Utkarsh Tiwari

Arihant Parsoya
Arihant Parsoya

Brad Buchanan
Brad Buchanan

Johan Karlsson
Johan Karlsson

Andy Timmons
Andy Timmons

zacharystenger
zacharystenger

Brian Boucheron
Brian Boucheron

Arihant Parsoya
Arihant Parsoya

Brad Buchanan
Brad Buchanan

Johan Karlsson
Johan Karlsson

Andy Timmons
Andy Timmons

zacharystenger
zacharystenger

Brian Boucheron
Brian Boucheron

sortasleepy
sortasleepy

Kyle McDonald
Kyle McDonald

Antonio Jesús Sánchez Padial
Antonio Jesús Sánchez Padial

💻
Brad Smith
Brad Smith

Vítor Galvão
Vítor Galvão

Devon Rifkin
Devon Rifkin

sortasleepy
sortasleepy

Kyle McDonald
Kyle McDonald

Antonio Jesús Sánchez Padial
Antonio Jesús Sánchez Padial

💻
Brad Smith
Brad Smith

Vítor Galvão
Vítor Galvão

Devon Rifkin
Devon Rifkin

Emily Xie
Emily Xie

Boris Bucha
Boris Bucha

Petr Brzek
Petr Brzek

Ramin
Ramin

Arsenije Savic
Arsenije Savic

Luke Burgess-Yeo
Luke Burgess-Yeo

Emily Xie
Emily Xie

Boris Bucha
Boris Bucha

Petr Brzek
Petr Brzek

Ramin
Ramin

Arsenije Savic
Arsenije Savic

Luke Burgess-Yeo
Luke Burgess-Yeo

Sun Lifei
Sun Lifei

naoyashiga
naoyashiga

Jimish Fotariya
Jimish Fotariya

Jorge Moreno
Jorge Moreno

🐛 💻 📖
Steven Green
Steven Green

Marcus Parsons
Marcus Parsons

Sun Lifei
Sun Lifei

naoyashiga
naoyashiga

Jimish Fotariya
Jimish Fotariya

Jorge Moreno
Jorge Moreno

🐛 💻 📖
Steven Green
Steven Green

Marcus Parsons
Marcus Parsons

Nick Yahnke
Nick Yahnke

Anthony Su
Anthony Su

kroko / Reinis Adovičs
kroko / Reinis Adovičs

Robyn Overstreet
Robyn Overstreet

Ben Hinchley
Ben Hinchley

Max Kolyanov
Max Kolyanov

Nick Yahnke
Nick Yahnke

Anthony Su
Anthony Su

kroko / Reinis Adovičs
kroko / Reinis Adovičs

Robyn Overstreet
Robyn Overstreet

Ben Hinchley
Ben Hinchley

Max Kolyanov
Max Kolyanov

Zeno Zeng
Zeno Zeng

Seth
Seth

plural
plural

Lionel Ringenbach
Lionel Ringenbach

Harshil Goel
Harshil Goel

Joshua Storm Becker
Joshua Storm Becker

Zeno Zeng
Zeno Zeng

Seth
Seth

plural
plural

Lionel Ringenbach
Lionel Ringenbach

Harshil Goel
Harshil Goel

Joshua Storm Becker
Joshua Storm Becker

maxdevjs
maxdevjs

trych
trych

Alejandra Trejo
Alejandra Trejo

Prashant Gupta
Prashant Gupta

Kai-han Chang
Kai-han Chang

kjav
kjav

maxdevjs
maxdevjs

trych
trych

Alejandra Trejo
Alejandra Trejo

Prashant Gupta
Prashant Gupta

Kai-han Chang
Kai-han Chang

kjav
kjav

maddy
maddy

Christopher Coleman
Christopher Coleman

Boaz
Boaz

Yasai
Yasai

📝
Jay Gupta
Jay Gupta

Nitish Bansal
Nitish Bansal

maddy
maddy

Christopher Coleman
Christopher Coleman

Boaz
Boaz

Yasai
Yasai

📝
Jay Gupta
Jay Gupta

Nitish Bansal
Nitish Bansal

Caroline Hermans
Caroline Hermans

💡 📖
Faith Wuyue Yu
Faith Wuyue Yu

Aatish Bhatia
Aatish Bhatia

📖 🐛 💡
Mislav Milicevic
Mislav Milicevic

💻 🐛
Yuting Lu
Yuting Lu

📖
Adil Rabbani
Adil Rabbani

💻 🐛 💡
Caroline Hermans
Caroline Hermans

💡 📖
Faith Wuyue Yu
Faith Wuyue Yu

Aatish Bhatia
Aatish Bhatia

📖 🐛 💡
Mislav Milicevic
Mislav Milicevic

💻 🐛
Yuting Lu
Yuting Lu

📖
Adil Rabbani
Adil Rabbani

💻 🐛 💡
Pierre Krafft
Pierre Krafft

🐛 💻 📖 💡 👀 ⚠️ 🔧
Zoë Ingram
Zoë Ingram

📖
Aidan Nelson
Aidan Nelson

🐛 💻 📖 💡
Cameron Yick
Cameron Yick

📖 💡
Tanvi Kumar
Tanvi Kumar

🐛 💻 📖 💡
Katsuya Endoh
Katsuya Endoh

Pierre Krafft
Pierre Krafft

🐛 💻 📖 💡 👀 ⚠️ 🔧
Zoë Ingram
Zoë Ingram

📖
Aidan Nelson
Aidan Nelson

🐛 💻 📖 💡
Cameron Yick
Cameron Yick

📖 💡
Tanvi Kumar
Tanvi Kumar

🐛 💻 📖 💡
Katsuya Endoh
Katsuya Endoh

Kevin Bradley
Kevin Bradley

📖
Justin Kim
Justin Kim

📖
Federico Grandi
Federico Grandi

💻 📖
Freddie Rawlins
Freddie Rawlins

💻 📖
Luc de wit
Luc de wit

💻 🐛
Mark Nikora
Mark Nikora

💻
Kevin Bradley
Kevin Bradley

📖
Justin Kim
Justin Kim

📖
Federico Grandi
Federico Grandi

💻 📖
Freddie Rawlins
Freddie Rawlins

💻 📖
Luc de wit
Luc de wit

💻 🐛
Mark Nikora
Mark Nikora

💻
Louis Demange
Louis Demange

🐛
Sanket Singh
Sanket Singh

💻 🐛 📖 💡
Oren Shoham
Oren Shoham

💻
Abhinav Sagar
Abhinav Sagar

💻
Jonathan Heindl
Jonathan Heindl

💻 💡 🤔 📖
Hirad Sab
Hirad Sab

💻 🐛 📖 💡
Louis Demange
Louis Demange

🐛
Sanket Singh
Sanket Singh

💻 🐛 📖 💡
Oren Shoham
Oren Shoham

💻
Abhinav Sagar
Abhinav Sagar

💻
Jonathan Heindl
Jonathan Heindl

💻 💡 🤔 📖
Hirad Sab
Hirad Sab

💻 🐛 📖 💡
Vishal Singh
Vishal Singh

📖 💻
Corey Gouker
Corey Gouker

💻 📖 🐛
Lisa Mabley
Lisa Mabley

📖 💡
Adam Ferriss
Adam Ferriss

💻 📖 🐛 💡
Joshua Marris
Joshua Marris

📖 💻 📢
Erica Pramer
Erica Pramer

📖
Vishal Singh
Vishal Singh

📖 💻
Corey Gouker
Corey Gouker

💻 📖 🐛
Lisa Mabley
Lisa Mabley

📖 💡
Adam Ferriss
Adam Ferriss

💻 📖 🐛 💡
Joshua Marris
Joshua Marris

📖 💻 📢
Erica Pramer
Erica Pramer

📖
Vasu Goel
Vasu Goel

💻 ⚠️
Tokini Irene Fubara
Tokini Irene Fubara

📖
Dhruv Sahnan
Dhruv Sahnan

💻 📖
Jon Kaufman
Jon Kaufman

📖
Nico Finkernagel
Nico Finkernagel

🚇 👀
ashu8912
ashu8912

💻
Vasu Goel
Vasu Goel

💻 ⚠️
Tokini Irene Fubara
Tokini Irene Fubara

📖
Dhruv Sahnan
Dhruv Sahnan

💻 📖
Jon Kaufman
Jon Kaufman

📖
Nico Finkernagel
Nico Finkernagel

🚇 👀
ashu8912
ashu8912

💻
ffd8
ffd8

💻
Sona Lee
Sona Lee

💻
Ryan Slade
Ryan Slade

💻
Mann Shah
Mann Shah

Juraj Onuska
Juraj Onuska

ANURAG GUPTA
ANURAG GUPTA

📖
ffd8
ffd8

💻
Sona Lee
Sona Lee

💻
Ryan Slade
Ryan Slade

💻
Mann Shah
Mann Shah

Juraj Onuska
Juraj Onuska

ANURAG GUPTA
ANURAG GUPTA

📖
Sagar Arora
Sagar Arora

Rajiv Ranjan Singh
Rajiv Ranjan Singh

Fenil Gandhi
Fenil Gandhi

📖 💡
Akshay Padte
Akshay Padte

💻 🐛 ⚠️
Satyam Kulkarni
Satyam Kulkarni

📖
Shirou
Shirou

💻 🐛
Sagar Arora
Sagar Arora

Rajiv Ranjan Singh
Rajiv Ranjan Singh

Fenil Gandhi
Fenil Gandhi

📖 💡
Akshay Padte
Akshay Padte

💻 🐛 ⚠️
Satyam Kulkarni
Satyam Kulkarni

📖
Shirou
Shirou

💻 🐛
Sarthak Saxena
Sarthak Saxena

💻
Nick McIntyre
Nick McIntyre

🔌 🐛
Amey Bhavsar
Amey Bhavsar

🐛 💡
Fisher Diede
Fisher Diede

💻
karinaxlpz
karinaxlpz

🌍
Samuel Alarco Cantos
Samuel Alarco Cantos

🌍
Sarthak Saxena
Sarthak Saxena

💻
Nick McIntyre
Nick McIntyre

🔌 🐛
Amey Bhavsar
Amey Bhavsar

🐛 💡
Fisher Diede
Fisher Diede

💻
karinaxlpz
karinaxlpz

🌍
Samuel Alarco Cantos
Samuel Alarco Cantos

🌍
DIVYANSHU RAJ
DIVYANSHU RAJ

💻 🐛 📖
sm7515
sm7515

📖 💡
Aditya Rachman Putra
Aditya Rachman Putra

📖
shaharyarshamshi
shaharyarshamshi

🌍
Ayush Jain
Ayush Jain

🌍
Summer Rizzo
Summer Rizzo

📖
DIVYANSHU RAJ
DIVYANSHU RAJ

💻 🐛 📖
sm7515
sm7515

📖 💡
Aditya Rachman Putra
Aditya Rachman Putra

📖
shaharyarshamshi
shaharyarshamshi

🌍
Ayush Jain
Ayush Jain

🌍
Summer Rizzo
Summer Rizzo

📖
Aierie
Aierie

💻 🐛
Mateusz Swiatkowski
Mateusz Swiatkowski

💻 🐛
XingZiLong
XingZiLong

🌍
ov
ov

🌍
Kyle James
Kyle James

💻
Abhi Gulati
Abhi Gulati

📖
Aierie
Aierie

💻 🐛
Mateusz Swiatkowski
Mateusz Swiatkowski

💻 🐛
XingZiLong
XingZiLong

🌍
ov
ov

🌍
Kyle James
Kyle James

💻
Abhi Gulati
Abhi Gulati

📖
Jeremy Tuloup
Jeremy Tuloup

📖
Luis Morales-Navarro
Luis Morales-Navarro

️️️️♿️
Yuki
Yuki

🌍
cedarfall
cedarfall

📖
Isaac Durazo
Isaac Durazo

🌍
İsmail Namdar
İsmail Namdar

💻 ⚠️
Jeremy Tuloup
Jeremy Tuloup

📖
Luis Morales-Navarro
Luis Morales-Navarro

️️️️♿️
Yuki
Yuki

🌍
cedarfall
cedarfall

📖
Isaac Durazo
Isaac Durazo

🌍
İsmail Namdar
İsmail Namdar

💻 ⚠️
skyperx
skyperx

💻
Joseph Aronson
Joseph Aronson

💻 🐛
Haider Ali Punjabi
Haider Ali Punjabi

💻
Swapnil-2001
Swapnil-2001

📖
Takuma Kira
Takuma Kira

🐛 💻 ⚠️
Mohammad Hussain Nagaria
Mohammad Hussain Nagaria

🐛
skyperx
skyperx

💻
Joseph Aronson
Joseph Aronson

💻 🐛
Haider Ali Punjabi
Haider Ali Punjabi

💻
Swapnil-2001
Swapnil-2001

📖
Takuma Kira
Takuma Kira

🐛 💻 ⚠️
Mohammad Hussain Nagaria
Mohammad Hussain Nagaria

🐛
Tushar Choudhari
Tushar Choudhari

📖 💻
Nakul Shahdadpuri
Nakul Shahdadpuri

💻
Jacques P. du Toit
Jacques P. du Toit

💻
surajsurajsuraj
surajsurajsuraj

🐛
Connie Liu
Connie Liu

💻 🎨
Zeke Sikelianos
Zeke Sikelianos

📖
Tushar Choudhari
Tushar Choudhari

📖 💻
Nakul Shahdadpuri
Nakul Shahdadpuri

💻
Jacques P. du Toit
Jacques P. du Toit

💻
surajsurajsuraj
surajsurajsuraj

🐛
Connie Liu
Connie Liu

💻 🎨
Zeke Sikelianos
Zeke Sikelianos

📖
Ramon Jr. Yniguez
Ramon Jr. Yniguez

💻
Benoît Bouré
Benoît Bouré

📖
Hitesh Kumar
Hitesh Kumar

💻
Sampo Rapeli
Sampo Rapeli

💡
Nick Müller
Nick Müller

🔌
Keith Tan
Keith Tan

📖
Ramon Jr. Yniguez
Ramon Jr. Yniguez

💻
Benoît Bouré
Benoît Bouré

📖
Hitesh Kumar
Hitesh Kumar

💻
Sampo Rapeli
Sampo Rapeli

💡
Nick Müller
Nick Müller

🔌
Keith Tan
Keith Tan

📖
Berke Özgen
Berke Özgen

🐛 💡
Musab Kılıç
Musab Kılıç

💻 ⚠️
Nicholas Marino
Nicholas Marino

📖
Greg Sadetsky
Greg Sadetsky

💻
Priya-Pathak
Priya-Pathak

💡
Daniel Michel
Daniel Michel

💻
Berke Özgen
Berke Özgen

🐛 💡
Musab Kılıç
Musab Kılıç

💻 ⚠️
Nicholas Marino
Nicholas Marino

📖
Greg Sadetsky
Greg Sadetsky

💻
Priya-Pathak
Priya-Pathak

💡
Daniel Michel
Daniel Michel

💻
Nisar Hassan Naqvi
Nisar Hassan Naqvi

💻
Joshua Noble
Joshua Noble

📖
Liam Piesley
Liam Piesley

💻
Rishabh Taparia
Rishabh Taparia

💻 📖
Daniel Sarno
Daniel Sarno

💡
Kunal Kumar Verma
Kunal Kumar Verma

📖 🐛 💻
Nisar Hassan Naqvi
Nisar Hassan Naqvi

💻
Joshua Noble
Joshua Noble

📖
Liam Piesley
Liam Piesley

💻
Rishabh Taparia
Rishabh Taparia

💻 📖
Daniel Sarno
Daniel Sarno

💡
Kunal Kumar Verma
Kunal Kumar Verma

📖 🐛 💻
Bharath Kumar R
Bharath Kumar R

💻
Aditya Mohan
Aditya Mohan

💻
Arijit Kundu
Arijit Kundu

🐛 💻 📖
Tanner Dolby
Tanner Dolby

💻
sam delong
sam delong

💻
Zhao Xin
Zhao Xin

💻 👀
Bharath Kumar R
Bharath Kumar R

💻
Aditya Mohan
Aditya Mohan

💻
Arijit Kundu
Arijit Kundu

🐛 💻 📖
Tanner Dolby
Tanner Dolby

💻
sam delong
sam delong

💻
Zhao Xin
Zhao Xin

💻 👀
Sivaram D
Sivaram D

📖 💻
Pragya
Pragya

💻
Jonathan-David Schröder
Jonathan-David Schröder

🤔 💻
Shubham Kumar
Shubham Kumar

💻
Jean Pierre Charalambos
Jean Pierre Charalambos

💻 🔧
Sai Bhushan
Sai Bhushan

💻 📖
Sivaram D
Sivaram D

📖 💻
Pragya
Pragya

💻
Jonathan-David Schröder
Jonathan-David Schröder

🤔 💻
Shubham Kumar
Shubham Kumar

💻
Jean Pierre Charalambos
Jean Pierre Charalambos

💻 🔧
Sai Bhushan
Sai Bhushan

💻 📖
Long Phan
Long Phan

💻
Jean-Michaël Celerier
Jean-Michaël Celerier

🐛
So Sun Park
So Sun Park

📖
Daniel Adams
Daniel Adams

💻 📖
Aloneduckling
Aloneduckling

📖
Mohana Sundaram S
Mohana Sundaram S

💻
Long Phan
Long Phan

💻
Jean-Michaël Celerier
Jean-Michaël Celerier

🐛
So Sun Park
So Sun Park

📖
Daniel Adams
Daniel Adams

💻 📖
Aloneduckling
Aloneduckling

📖
Mohana Sundaram S
Mohana Sundaram S

💻
TwoTicks
TwoTicks

💻 📖 💡
Kathryn Isabelle Lawrence
Kathryn Isabelle Lawrence

💻 🤔
Joonas Jokinen
Joonas Jokinen

🎨
Ajaya Mati
Ajaya Mati

💻
Suhas CV
Suhas CV

📖 💡
Sanjay Singh Rajpoot
Sanjay Singh Rajpoot

📖
TwoTicks
TwoTicks

💻 📖 💡
Kathryn Isabelle Lawrence
Kathryn Isabelle Lawrence

💻 🤔
Joonas Jokinen
Joonas Jokinen

🎨
Ajaya Mati
Ajaya Mati

💻
Suhas CV
Suhas CV

📖 💡
Sanjay Singh Rajpoot
Sanjay Singh Rajpoot

📖
Chris P.
Chris P.

📖
Thomas Herlea
Thomas Herlea

🐛 💻 📖
Simranjeet Singh
Simranjeet Singh

💻 📢 🎨 👀
Rahul Mohata
Rahul Mohata

📖
Dave Pagurek
Dave Pagurek

💻 ⚠️ 💡
Leo Kamwathi
Leo Kamwathi

💻
Chris P.
Chris P.

📖
Thomas Herlea
Thomas Herlea

🐛 💻 📖
Simranjeet Singh
Simranjeet Singh

💻 📢 🎨 👀
Rahul Mohata
Rahul Mohata

📖
Dave Pagurek
Dave Pagurek

💻 ⚠️ 💡
Leo Kamwathi
Leo Kamwathi

💻
David Weiss
David Weiss

💻 📢 👀 📖
Chris Thomson
Chris Thomson

💻 🐛
mainstreamdev
mainstreamdev

🐛
Aaron George
Aaron George

🐛
Alex Lyons
Alex Lyons

📖
Tyler Jordan
Tyler Jordan

📖
David Weiss
David Weiss

💻 📢 👀 📖
Chris Thomson
Chris Thomson

💻 🐛
mainstreamdev
mainstreamdev

🐛
Aaron George
Aaron George

🐛
Alex Lyons
Alex Lyons

📖
Tyler Jordan
Tyler Jordan

📖
Ghales
Ghales

🎨 💻 🔧
JetStarBlues
JetStarBlues

📖 💻
Avelar
Avelar

📖
Oliver Steele
Oliver Steele

📖
MiniPear
MiniPear

📖
Paul Wheeler
Paul Wheeler

💻
Ghales
Ghales

🎨 💻 🔧
JetStarBlues
JetStarBlues

📖 💻
Avelar
Avelar

📖
Oliver Steele
Oliver Steele

📖
MiniPear
MiniPear

📖
Paul Wheeler
Paul Wheeler

💻
Nitin Rana
Nitin Rana

📖
Annie McKinnon
Annie McKinnon

🐛 💻
Jiwon Park (hanpanic)
Jiwon Park (hanpanic)

💻
truemaxdh
truemaxdh

🐛 💻
Katie
Katie

💻
Guilherme Silveira
Guilherme Silveira

📖
Nitin Rana
Nitin Rana

📖
Annie McKinnon
Annie McKinnon

🐛 💻
Jiwon Park (hanpanic)
Jiwon Park (hanpanic)

💻
truemaxdh
truemaxdh

🐛 💻
Katie
Katie

💻
Guilherme Silveira
Guilherme Silveira

📖
Camille Roux
Camille Roux

💻
reejuBhattacharya
reejuBhattacharya

📖 💻
Akshat Nema
Akshat Nema

💻
Anshuman Maurya
Anshuman Maurya

🐛
Himanshu Malviya
Himanshu Malviya

🐛
Samuel Cho
Samuel Cho

🐛
Camille Roux
Camille Roux

💻
reejuBhattacharya
reejuBhattacharya

📖 💻
Akshat Nema
Akshat Nema

💻
Anshuman Maurya
Anshuman Maurya

🐛
Himanshu Malviya
Himanshu Malviya

🐛
Samuel Cho
Samuel Cho

🐛
Théodore Orfèvres
Théodore Orfèvres

🐛
Jyotiraditya Pradhan
Jyotiraditya Pradhan

📖
Zearin
Zearin

📖
pifragile
pifragile

🐛
Jstodd
Jstodd

🐛
Jens Axel Søgaard
Jens Axel Søgaard

📖 🐛
Théodore Orfèvres
Théodore Orfèvres

🐛
Jyotiraditya Pradhan
Jyotiraditya Pradhan

📖
Zearin
Zearin

📖
pifragile
pifragile

🐛
Jstodd
Jstodd

🐛
Jens Axel Søgaard
Jens Axel Søgaard

📖 🐛
oleboleskole3
oleboleskole3

🐛
A Welles
A Welles

🐛
andrei antonescu
andrei antonescu

🐛
Fun Planet
Fun Planet

🐛
Stig Møller Hansen
Stig Møller Hansen

🐛
Derek Enlow
Derek Enlow

💻
oleboleskole3
oleboleskole3

🐛
A Welles
A Welles

🐛
andrei antonescu
andrei antonescu

🐛
Fun Planet
Fun Planet

🐛
Stig Møller Hansen
Stig Møller Hansen

🐛
Derek Enlow
Derek Enlow

💻
Will Martin
Will Martin

🤔
Beau Muylle
Beau Muylle

📖
Ivy Feraco
Ivy Feraco

🐛
Gareth Williams
Gareth Williams

💻
Ikko Ashimine
Ikko Ashimine

📖
Jonas Rinke
Jonas Rinke

🐛
Will Martin
Will Martin

🤔
Beau Muylle
Beau Muylle

📖
Ivy Feraco
Ivy Feraco

🐛
Gareth Williams
Gareth Williams

💻
Ikko Ashimine
Ikko Ashimine

📖
Jonas Rinke
Jonas Rinke

🐛
MATSUDA, Kouichi
MATSUDA, Kouichi

🐛
stampyzfanz
stampyzfanz

📖
tae
tae

🐛
Divyansh013
Divyansh013

🌍
rinkydevi
rinkydevi

🌍
Coding for the Arts
Coding for the Arts

🐛
MATSUDA, Kouichi
MATSUDA, Kouichi

🐛
stampyzfanz
stampyzfanz

📖
tae
tae

🐛
Divyansh013
Divyansh013

🌍
rinkydevi
rinkydevi

🌍
Coding for the Arts
Coding for the Arts

🐛
Dan
Dan

🐛
sparshg
sparshg

🐛
Liz Peng
Liz Peng

🎨 💻 🔧
koolaidkrusade
koolaidkrusade

📖
smilee
smilee

💻
CommanderRoot
CommanderRoot

💻
Dan
Dan

🐛
sparshg
sparshg

🐛
Liz Peng
Liz Peng

🎨 💻 🔧
koolaidkrusade
koolaidkrusade

📖
smilee
smilee

💻
CommanderRoot
CommanderRoot

💻
Philip Bell
Philip Bell

📖
tapioca24
tapioca24

🔌
Qianqian Ye
Qianqian Ye

💻 🎨 📖 📋 👀 🌍
Adarsh
Adarsh

🌍
kaabe1
kaabe1

🎨 📋
Seb Méndez
Seb Méndez

🌍
Philip Bell
Philip Bell

📖
tapioca24
tapioca24

🔌
Qianqian Ye
Qianqian Ye

💻 🎨 📖 📋 👀 🌍
Adarsh
Adarsh

🌍
kaabe1
kaabe1

🎨 📋
Seb Méndez
Seb Méndez

🌍
Ryuya
Ryuya

🐛 👀 💻
LEMIBANDDEXARI
LEMIBANDDEXARI

🌍
Vivek Tiwari
Vivek Tiwari

🌍
Kevin Grajeda
Kevin Grajeda

💻
anniezhengg
anniezhengg

💻 🎨
Seung-Gi Kim(David)
Seung-Gi Kim(David)

🌍
Ryuya
Ryuya

🐛 👀 💻
LEMIBANDDEXARI
LEMIBANDDEXARI

🌍
Vivek Tiwari
Vivek Tiwari

🌍
Kevin Grajeda
Kevin Grajeda

💻
anniezhengg
anniezhengg

💻 🎨
Seung-Gi Kim(David)
Seung-Gi Kim(David)

🌍
Ike Bischof
Ike Bischof

💻
Ong Zhi Zheng
Ong Zhi Zheng

🔌
bsubbaraman
bsubbaraman

🔌
Jenna deBoisblanc
Jenna deBoisblanc

🔌
manpreet
manpreet

📖 💻 ⚠️
TetroGem
TetroGem

🤔
Ike Bischof
Ike Bischof

💻
Ong Zhi Zheng
Ong Zhi Zheng

🔌
bsubbaraman
bsubbaraman

🔌
Jenna deBoisblanc
Jenna deBoisblanc

🔌
manpreet
manpreet

📖 💻 ⚠️
TetroGem
TetroGem

🤔
ggorlen
ggorlen

💻
raclim
raclim

💻
David White
David White

💻
Akhil Raj
Akhil Raj

🐛 📖 🌍 🎨 💻
Brahvim
Brahvim

📖
UnityOfFairfax
UnityOfFairfax

💻
ggorlen
ggorlen

💻
raclim
raclim

💻
David White
David White

💻
Akhil Raj
Akhil Raj

🐛 📖 🌍 🎨 💻
Brahvim
Brahvim

📖
UnityOfFairfax
UnityOfFairfax

💻
INARI_DARKFOX
INARI_DARKFOX

💻
James Dunn
James Dunn

🐛 💻
Malay Vasa
Malay Vasa

🎨 💻 💡
wagedu
wagedu

🐛
Wes Lord
Wes Lord

📖 ⚠️
pinky-pig
pinky-pig

🌍
INARI_DARKFOX
INARI_DARKFOX

💻
James Dunn
James Dunn

🐛 💻
Malay Vasa
Malay Vasa

🎨 💻 💡
wagedu
wagedu

🐛
Wes Lord
Wes Lord

📖 ⚠️
pinky-pig
pinky-pig

🌍
Chinmay Kadam
Chinmay Kadam

📖
Prateekgit
Prateekgit

💻
Aditya Shrivastav
Aditya Shrivastav

🐛 💻 📖
David
David

🐛 💻
Aryan Koundal
Aryan Koundal

💻
alp tuğan
alp tuğan

💻 🔌 🔧 💡
Chinmay Kadam
Chinmay Kadam

📖
Prateekgit
Prateekgit

💻
Aditya Shrivastav
Aditya Shrivastav

🐛 💻 📖
David
David

🐛 💻
Aryan Koundal
Aryan Koundal

💻
alp tuğan
alp tuğan

💻 🔌 🔧 💡
Laura Ciro
Laura Ciro

🌍
Kate Grant
Kate Grant

🐛 💻 ⚠️
Yograj Rajput
Yograj Rajput

💡
Dr. Holomorfo
Dr. Holomorfo

🌍
Quinton Ashley
Quinton Ashley

💻 🐛 🔌
Xavier Góngora
Xavier Góngora

🌍
Laura Ciro
Laura Ciro

🌍
Kate Grant
Kate Grant

🐛 💻 ⚠️
Yograj Rajput
Yograj Rajput

💡
Dr. Holomorfo
Dr. Holomorfo

🌍
Quinton Ashley
Quinton Ashley

💻 🐛 🔌
Xavier Góngora
Xavier Góngora

🌍
hvillase
hvillase

🌍
Shivansh Sharma
Shivansh Sharma

🌍
Elliot-Hernandez
Elliot-Hernandez

🌍
hunahpu18
hunahpu18

🌍
Dewansh Thakur
Dewansh Thakur

🐛
konstantinstanmeyer
konstantinstanmeyer

📖
hvillase
hvillase

🌍
Shivansh Sharma
Shivansh Sharma

🌍
Elliot-Hernandez
Elliot-Hernandez

🌍
hunahpu18
hunahpu18

🌍
Dewansh Thakur
Dewansh Thakur

🐛
konstantinstanmeyer
konstantinstanmeyer

📖
al6862
al6862

🐛 💻
Monalisa Maity
Monalisa Maity

💻
Abhinav Kumar
Abhinav Kumar

🐛
Abhinav Srinivas
Abhinav Srinivas

🐛 💻
Sawai Singh Rajpurohit
Sawai Singh Rajpurohit

📖 🐛 💻
Jack Dempsey
Jack Dempsey

🐛
al6862
al6862

🐛 💻
Monalisa Maity
Monalisa Maity

💻
Abhinav Kumar
Abhinav Kumar

🐛
Abhinav Srinivas
Abhinav Srinivas

🐛 💻
Sawai Singh Rajpurohit
Sawai Singh Rajpurohit

📖 🐛 💻
Jack Dempsey
Jack Dempsey

🐛
Aryan Thakor
Aryan Thakor

💻
Mostafa Ewis
Mostafa Ewis

🌍
Nabil Hassein
Nabil Hassein

🌍
AsukaMinato
AsukaMinato

🌍 💻
agrshch
agrshch

💻
SHIBAHARA Hiroki
SHIBAHARA Hiroki

💻 🌍
Aryan Thakor
Aryan Thakor

💻
Mostafa Ewis
Mostafa Ewis

🌍
Nabil Hassein
Nabil Hassein

🌍
AsukaMinato
AsukaMinato

🌍 💻
agrshch
agrshch

💻
SHIBAHARA Hiroki
SHIBAHARA Hiroki

💻 🌍
siddhant
siddhant

🐛 💻
Caleb Foss
Caleb Foss

🤔 👀 🔌 💡
chechenxu
chechenxu

💻
Peter Marsh
Peter Marsh

💻
Ahmet Kaya
Ahmet Kaya

🌍
oz
oz

💻
siddhant
siddhant

🐛 💻
Caleb Foss
Caleb Foss

🤔 👀 🔌 💡
chechenxu
chechenxu

💻
Peter Marsh
Peter Marsh

💻
Ahmet Kaya
Ahmet Kaya

🌍
oz
oz

💻
Munus Shih
Munus Shih

💻
Peiling Jiang
Peiling Jiang

💻 🎨 🌍
Decoy4ever
Decoy4ever

💻
Linda Paiste
Linda Paiste

🐛 💻 🎨 📖
shujulin
shujulin

🐛 🤔 🎨
J Wong
J Wong

💻 📖
Munus Shih
Munus Shih

💻
Peiling Jiang
Peiling Jiang

💻 🎨 🌍
Decoy4ever
Decoy4ever

💻
Linda Paiste
Linda Paiste

🐛 💻 🎨 📖
shujulin
shujulin

🐛 🤔 🎨
J Wong
J Wong

💻 📖
Austin Lee Slominski
Austin Lee Slominski

💻 📖 💡
Nick Briz
Nick Briz

👀
Ayush Shankar
Ayush Shankar

💻
zelf0
zelf0

📖
JT Nimoy
JT Nimoy

💻 🔌
Victor Morgan
Victor Morgan

📖
Austin Lee Slominski
Austin Lee Slominski

💻 📖 💡
Nick Briz
Nick Briz

👀
Ayush Shankar
Ayush Shankar

💻
zelf0
zelf0

📖
JT Nimoy
JT Nimoy

💻 🔌
Victor Morgan
Victor Morgan

📖
Sekani Warner
Sekani Warner

📖
e-Coucou
e-Coucou

🐛
Aaron Ni
Aaron Ni

📖
Onexi
Onexi

📖
Vijith Assar
Vijith Assar

💻 📖
Dorothy R. Santos
Dorothy R. Santos

📖 📋 🔍 📢
Sekani Warner
Sekani Warner

📖
e-Coucou
e-Coucou

🐛
Aaron Ni
Aaron Ni

📖
Onexi
Onexi

📖
Vijith Assar
Vijith Assar

💻 📖
Dorothy R. Santos
Dorothy R. Santos

📖 📋 🔍 📢
tonipizza
tonipizza

🔍 💵
Anna Carreras
Anna Carreras

💡 📢
takawo
takawo

💡 📋 📝
Spencer Faith
Spencer Faith

💻
Ayush Sharma
Ayush Sharma

💻
Aaron Casanova
Aaron Casanova

💻
tonipizza
tonipizza

🔍 💵
Anna Carreras
Anna Carreras

💡 📢
takawo
takawo

💡 📋 📝
Spencer Faith
Spencer Faith

💻
Ayush Sharma
Ayush Sharma

💻
Aaron Casanova
Aaron Casanova

💻
Adam Smith
Adam Smith

💻
Acha
Acha

💻 💡
Aditya Siddheshwar
Aditya Siddheshwar

💻
Adwaith D
Adwaith D

💻
æmon
æmon

💻
ajayTDM
ajayTDM

💻
Adam Smith
Adam Smith

💻
Acha
Acha

💻 💡
Aditya Siddheshwar
Aditya Siddheshwar

💻
Adwaith D
Adwaith D

💻
æmon
æmon

💻
ajayTDM
ajayTDM

💻
Akash
Akash

💻
AliLordLoss
AliLordLoss

💻
Lauren
Lauren

💻
anagondesign
anagondesign

💻
András Gárdos
András Gárdos

💻
AndrasGG
AndrasGG

💻
Akash
Akash

💻
AliLordLoss
AliLordLoss

💻
Lauren
Lauren

💻
anagondesign
anagondesign

💻
András Gárdos
András Gárdos

💻
AndrasGG
AndrasGG

💻
Aqmalp99
Aqmalp99

💻
Arbaaz
Arbaaz

💻
Arihant Parsoya
Arihant Parsoya

💻
ArshM17
ArshM17

💻
AsukaMinato
AsukaMinato

💻
Jared Donovan
Jared Donovan

💻 💡
Aqmalp99
Aqmalp99

💻
Arbaaz
Arbaaz

💻
Arihant Parsoya
Arihant Parsoya

💻
ArshM17
ArshM17

💻
AsukaMinato
AsukaMinato

💻
Jared Donovan
Jared Donovan

💻 💡
beau-muylle
beau-muylle

💻
Yana Agun Siswanto
Yana Agun Siswanto

💻
Benjamin Davies
Benjamin Davies

💻
BerfinA
BerfinA

💻
Bernice Wu
Bernice Wu

💻
Ben Scheiner
Ben Scheiner

💻
beau-muylle
beau-muylle

💻
Yana Agun Siswanto
Yana Agun Siswanto

💻
Benjamin Davies
Benjamin Davies

💻
BerfinA
BerfinA

💻
Bernice Wu
Bernice Wu

💻
Ben Scheiner
Ben Scheiner

💻
Bryan
Bryan

💻
Bulkan Evcimen
Bulkan Evcimen

💻
Brian Whitman
Brian Whitman

💻
cacoollib
cacoollib

💻
Caitlin
Caitlin

💻
Caleb Eggensperger
Caleb Eggensperger

💻
Bryan
Bryan

💻
Bulkan Evcimen
Bulkan Evcimen

💻
Brian Whitman
Brian Whitman

💻
cacoollib
cacoollib

💻
Caitlin
Caitlin

💻
Caleb Eggensperger
Caleb Eggensperger

💻
Cody Fuller
Cody Fuller

💻
Christopher John Ryan
Christopher John Ryan

💻
Constance Yu
Constance Yu

💻
Cosme Escobedo
Cosme Escobedo

💻
Dominic Jodoin
Dominic Jodoin

💻
Dabe Andre Enajada
Dabe Andre Enajada

💻
Cody Fuller
Cody Fuller

💻
Christopher John Ryan
Christopher John Ryan

💻
Constance Yu
Constance Yu

💻
Cosme Escobedo
Cosme Escobedo

💻
Dominic Jodoin
Dominic Jodoin

💻
Dabe Andre Enajada
Dabe Andre Enajada

💻
Dana Mulder
Dana Mulder

💻
Derrick McMillen
Derrick McMillen

💻
Dan Hoizner
Dan Hoizner

💻
digitalfrost
digitalfrost

💻
Thomas Diewald
Thomas Diewald

💻
dummyAccount22
dummyAccount22

💻
Dana Mulder
Dana Mulder

💻
Derrick McMillen
Derrick McMillen

💻
Dan Hoizner
Dan Hoizner

💻
digitalfrost
digitalfrost

💻
Thomas Diewald
Thomas Diewald

💻
dummyAccount22
dummyAccount22

💻
Dusk
Dusk

💻
Ed Brannin
Ed Brannin

💻
Ewan Johnstone
Ewan Johnstone

💻
elgin mclaren
elgin mclaren

💻
epramer-godaddy
epramer-godaddy

💻
Bob Ippolito
Bob Ippolito

💻
Dusk
Dusk

💻
Ed Brannin
Ed Brannin

💻
Ewan Johnstone
Ewan Johnstone

💻
elgin mclaren
elgin mclaren

💻
epramer-godaddy
epramer-godaddy

💻
Bob Ippolito
Bob Ippolito

💻
FAL
FAL

💻
Corey Farwell
Corey Farwell

💻
Shubham Rathore
Shubham Rathore

💻
Geraldo Neto
Geraldo Neto

💻
Gregor Martynus
Gregor Martynus

💻
Gracia-zhang
Gracia-zhang

💻
FAL
FAL

💻
Corey Farwell
Corey Farwell

💻
Shubham Rathore
Shubham Rathore

💻
Geraldo Neto
Geraldo Neto

💻
Gregor Martynus
Gregor Martynus

💻
Gracia-zhang
Gracia-zhang

💻
Brett Cooper
Brett Cooper

💻
Half Scheidl
Half Scheidl

💻
Ashris
Ashris

💻
Arijit
Arijit

💻
Urvashi
Urvashi

💻 💡
José Miguel Tajuelo Garrigós
José Miguel Tajuelo Garrigós

💻
Brett Cooper
Brett Cooper

💻
Half Scheidl
Half Scheidl

💻
Ashris
Ashris

💻
Arijit
Arijit

💻
Urvashi
Urvashi

💻 💡
José Miguel Tajuelo Garrigós
José Miguel Tajuelo Garrigós

💻
Jai Kotia
Jai Kotia

💻
Jatin Panjwani
Jatin Panjwani

💻
jeong
jeong

💻
Jesús Enrique Rascón
Jesús Enrique Rascón

💻
Joseph Hong
Joseph Hong

💻
Jithin KS
Jithin KS

💻 💡
Jai Kotia
Jai Kotia

💻
Jatin Panjwani
Jatin Panjwani

💻
jeong
jeong

💻
Jesús Enrique Rascón
Jesús Enrique Rascón

💻
Joseph Hong
Joseph Hong

💻
Jithin KS
Jithin KS

💻 💡
Jason Mandel
Jason Mandel

💻
JoeCastor
JoeCastor

💻
Juan Irache
Juan Irache

💻
juliane nagao
juliane nagao

💻
Chan Jun Shern
Chan Jun Shern

💻
Ashley Kang
Ashley Kang

💻
Jason Mandel
Jason Mandel

💻
JoeCastor
JoeCastor

💻
Juan Irache
Juan Irache

💻
juliane nagao
juliane nagao

💻
Chan Jun Shern
Chan Jun Shern

💻
Ashley Kang
Ashley Kang

💻
Darío Hereñú
Darío Hereñú

💻
Sithe Ncube
Sithe Ncube

💻
Laksh Singla
Laksh Singla

💻
Leslie Yip
Leslie Yip

💻
linnhallonqvist
linnhallonqvist

💻
Frederik Ring
Frederik Ring

💻
Darío Hereñú
Darío Hereñú

💻
Sithe Ncube
Sithe Ncube

💻
Laksh Singla
Laksh Singla

💻
Leslie Yip
Leslie Yip

💻
linnhallonqvist
linnhallonqvist

💻
Frederik Ring
Frederik Ring

💻
maddyfisher
maddyfisher

💻
Caleb Mazalevskis
Caleb Mazalevskis

💻
manpreet
manpreet

💻
David Aerne
David Aerne

💻
Naoto Hieda
Naoto Hieda

💻
min-kim42
min-kim42

💻
maddyfisher
maddyfisher

💻
Caleb Mazalevskis
Caleb Mazalevskis

💻
manpreet
manpreet

💻
David Aerne
David Aerne

💻
Naoto Hieda
Naoto Hieda

💻
min-kim42
min-kim42

💻
M
M

💻
Adam Král
Adam Král

💻
Ben Greenberg
Ben Greenberg

💻
Pratyay Banerjee
Pratyay Banerjee

💻
Nikhil
Nikhil

💻
Niki Ito
Niki Ito

💻
M
M

💻
Adam Král
Adam Král

💻
Ben Greenberg
Ben Greenberg

💻
Pratyay Banerjee
Pratyay Banerjee

💻
Nikhil
Nikhil

💻
Niki Ito
Niki Ito

💻
Nik Nyby
Nik Nyby

💻
nully0x
nully0x

💻
odm275
odm275

💻
Oleksii Bulba
Oleksii Bulba

💻
paollabd
paollabd

💻
Prateek Jain
Prateek Jain

💻
Nik Nyby
Nik Nyby

💻
nully0x
nully0x

💻
odm275
odm275

💻
Oleksii Bulba
Oleksii Bulba

💻
paollabd
paollabd

💻
Prateek Jain
Prateek Jain

💻
Ceesjan Luiten
Ceesjan Luiten

💻
NIINOMI
NIINOMI

💻
Ben Wendt
Ben Wendt

💻
Reijo Vosu
Reijo Vosu

💻
peter
peter

💻
Sachin Varghese
Sachin Varghese

💻
Ceesjan Luiten
Ceesjan Luiten

💻
NIINOMI
NIINOMI

💻
Ben Wendt
Ben Wendt

💻
Reijo Vosu
Reijo Vosu

💻
peter
peter

💻
Sachin Varghese
Sachin Varghese

💻
Sarah Groff Hennigh-Palermo
Sarah Groff Hennigh-Palermo

💻
Dwiferdio Seagal Putra
Dwiferdio Seagal Putra

💻
Abishake
Abishake

💻
sheamus
sheamus

💻
Liang Tang
Liang Tang

💻
Michael J Conrad
Michael J Conrad

💻
Sarah Groff Hennigh-Palermo
Sarah Groff Hennigh-Palermo

💻
Dwiferdio Seagal Putra
Dwiferdio Seagal Putra

💻
Abishake
Abishake

💻
sheamus
sheamus

💻
Liang Tang
Liang Tang

💻
Michael J Conrad
Michael J Conrad

💻
Samir Ghosh
Samir Ghosh

💻
Stalgia Grigg
Stalgia Grigg

💻
Stef Tervelde
Stef Tervelde

💻
stormCup
stormCup

💻
Cliff Su
Cliff Su

💻
sz245
sz245

💻
Samir Ghosh
Samir Ghosh

💻
Stalgia Grigg
Stalgia Grigg

💻
Stef Tervelde
Stef Tervelde

💻
stormCup
stormCup

💻
Cliff Su
Cliff Su

💻
sz245
sz245

💻
Alex Troesch
Alex Troesch

💻
Maciej Stankiewicz
Maciej Stankiewicz

💻
Alberto Di Biase
Alberto Di Biase

💻
Vedhant Agarwal
Vedhant Agarwal

💻
Varsha Verma
Varsha Verma

💻
vipulrawat
vipulrawat

💻
Alex Troesch
Alex Troesch

💻
Maciej Stankiewicz
Maciej Stankiewicz

💻
Alberto Di Biase
Alberto Di Biase

💻
Vedhant Agarwal
Vedhant Agarwal

💻
Varsha Verma
Varsha Verma

💻
vipulrawat
vipulrawat

💻
Erik Butcher
Erik Butcher

💻
Wade Marshall
Wade Marshall

💻
XTY
XTY

💻
Jenna
Jenna

💻
Yifan Mai
Yifan Mai

💻
Inhwa
Inhwa

💻
Erik Butcher
Erik Butcher

💻
Wade Marshall
Wade Marshall

💻
XTY
XTY

💻
Jenna
Jenna

💻
Yifan Mai
Yifan Mai

💻
Inhwa
Inhwa

💻
Yousef Abu-Salah
Yousef Abu-Salah

💻
Zoe Stenger
Zoe Stenger

💻
mcturner1995
mcturner1995

💻
Seonghyeon Kim
Seonghyeon Kim

💻 🌍
Gus Becker
Gus Becker

🚧 🤔 💬
senbaku
senbaku

💡 📝 🌍
Yousef Abu-Salah
Yousef Abu-Salah

💻
Zoe Stenger
Zoe Stenger

💻
mcturner1995
mcturner1995

💻
Seonghyeon Kim
Seonghyeon Kim

💻 🌍
Gus Becker
Gus Becker

🚧 🤔 💬
senbaku
senbaku

💡 📝 🌍
reona396
reona396

💡 🌍
Mauricio Verano Merino
Mauricio Verano Merino

📋 🔬 🧑‍🏫
RandomGamingDev
RandomGamingDev

💻 🐛
Wu Che Yu
Wu Che Yu

📋 📝 📹
Sarah Ciston
Sarah Ciston

🧑‍🏫 📖 📋
Tiago Hermano
Tiago Hermano

🌍 👀
reona396
reona396

💡 🌍
Mauricio Verano Merino
Mauricio Verano Merino

📋 🔬 🧑‍🏫
RandomGamingDev
RandomGamingDev

💻 🐛
Wu Che Yu
Wu Che Yu

📋 📝 📹
Sarah Ciston
Sarah Ciston

🧑‍🏫 📖 📋
Tiago Hermano
Tiago Hermano

🌍 👀
Unicar
Unicar

🌍 💡
Yolonanido
Yolonanido

📋
Raphaël de Courville
Raphaël de Courville

📋 📹 🤔 📣
Mike
Mike

💻 🐛
Ankush Banik
Ankush Banik

🐛 💻 📢 💬
tetunori
tetunori

📝 💻 💡 🔧
Unicar
Unicar

🌍 💡
Yolonanido
Yolonanido

📋
Raphaël de Courville
Raphaël de Courville

📋 📹 🤔 📣
Mike
Mike

💻 🐛
Ankush Banik
Ankush Banik

🐛 💻 📢 💬
tetunori
tetunori

📝 💻 💡 🔧
Emma Krantz
Emma Krantz

🐛 💻
Zac Tolle
Zac Tolle

️️️️♿️ 💻 🔧 💡
Dharshan
Dharshan

💻
Sandeep Kumar Bhagat
Sandeep Kumar Bhagat

🎨 💻
Gaurav Tiwary
Gaurav Tiwary

💻
Garima
Garima

💻
Emma Krantz
Emma Krantz

🐛 💻
Zac Tolle
Zac Tolle

️️️️♿️ 💻 🔧 💡
Dharshan
Dharshan

💻
Sandeep Kumar Bhagat
Sandeep Kumar Bhagat

🎨 💻
Gaurav Tiwary
Gaurav Tiwary

💻
Garima
Garima

💻
Lakshay Joshi
Lakshay Joshi

💻
perminder-17
perminder-17

💻 🐛 📖 💡 🤔 🔌 📆 📣 💬 🔬
Yash Pandey
Yash Pandey

🐛 💻
Aditya Deshpande
Aditya Deshpande

🐛 📖
Alejandro
Alejandro

🐛 💻
Diya Solanki
Diya Solanki

💻
Lakshay Joshi
Lakshay Joshi

💻
perminder-17
perminder-17

💻 🐛 📖 💡 🤔 🔌 📆 📣 💬 🔬
Yash Pandey
Yash Pandey

🐛 💻
Aditya Deshpande
Aditya Deshpande

🐛 📖
Alejandro
Alejandro

🐛 💻
Diya Solanki
Diya Solanki

💻
mhsh312
mhsh312

💻 🐛
wackbyte
wackbyte

📖
Ajeet Pratap Singh
Ajeet Pratap Singh

💻 🐛
Jai Vignesh J
Jai Vignesh J

💻
cab_kyabe
cab_kyabe

🐛 💻
Vishwas Srivastava
Vishwas Srivastava

💻
mhsh312
mhsh312

💻 🐛
wackbyte
wackbyte

📖
Ajeet Pratap Singh
Ajeet Pratap Singh

💻 🐛
Jai Vignesh J
Jai Vignesh J

💻
cab_kyabe
cab_kyabe

🐛 💻
Vishwas Srivastava
Vishwas Srivastava

💻
suhani6904
suhani6904

🌍
Nabeel (Dexter)
Nabeel (Dexter)

💻
Umang Utkarsh
Umang Utkarsh

📖 🌍
aditya123473892
aditya123473892

💻 🐛 📖
Harsh Range
Harsh Range

💻 🐛
Sudhanshu Tiwari
Sudhanshu Tiwari

💻
suhani6904
suhani6904

🌍
Nabeel (Dexter)
Nabeel (Dexter)

💻
Umang Utkarsh
Umang Utkarsh

📖 🌍
aditya123473892
aditya123473892

💻 🐛 📖
Harsh Range
Harsh Range

💻 🐛
Sudhanshu Tiwari
Sudhanshu Tiwari

💻
mohamedalisaifudeen
mohamedalisaifudeen

🐛
Aryan Singh
Aryan Singh

💻
nikhilkalburgi
nikhilkalburgi

🐛 📖
Samrudh Shetty
Samrudh Shetty

️️️️♿️
Mattia Micheletta Merlin
Mattia Micheletta Merlin

💡 💻 ⚠️
Armaan Gupta
Armaan Gupta

💻
mohamedalisaifudeen
mohamedalisaifudeen

🐛
Aryan Singh
Aryan Singh

💻
nikhilkalburgi
nikhilkalburgi

🐛 📖
Samrudh Shetty
Samrudh Shetty

️️️️♿️
Mattia Micheletta Merlin
Mattia Micheletta Merlin

💡 💻 ⚠️
Armaan Gupta
Armaan Gupta

💻
Harman Batheja
Harman Batheja

🌍 🐛
PracDuckling
PracDuckling

🐛 📖
Poulav Bhowmick
Poulav Bhowmick

🐛 📖
Keshav Malik
Keshav Malik

💻 📖 🐛
Deveshi Dwivedi
Deveshi Dwivedi

💻
Mohit Balwani
Mohit Balwani

💻
Harman Batheja
Harman Batheja

🌍 🐛
PracDuckling
PracDuckling

🐛 📖
Poulav Bhowmick
Poulav Bhowmick

🐛 📖
Keshav Malik
Keshav Malik

💻 📖 🐛
Deveshi Dwivedi
Deveshi Dwivedi

💻
Mohit Balwani
Mohit Balwani

💻
rahulrangers
rahulrangers

💻
Sudhanshu Tiwari
Sudhanshu Tiwari

🐛 💻
meezwhite
meezwhite

📖
pie999
pie999

📖
Muhammad Haroon
Muhammad Haroon

📖 💻
Nat Decker
Nat Decker

️️️️♿️ 📖
rahulrangers
rahulrangers

💻
Sudhanshu Tiwari
Sudhanshu Tiwari

🐛 💻
meezwhite
meezwhite

📖
pie999
pie999

📖
Muhammad Haroon
Muhammad Haroon

📖 💻
Nat Decker
Nat Decker

️️️️♿️ 📖
Miaoye Que
Miaoye Que

🌍 🚧
sphantom-code
sphantom-code

📖
Minwook Park
Minwook Park

🌍
Harrycheng233
Harrycheng233

🌍
Diana Galindo
Diana Galindo

🌍
Lingxiao Wang
Lingxiao Wang

🌍
Miaoye Que
Miaoye Que

🌍 🚧
sphantom-code
sphantom-code

📖
Minwook Park
Minwook Park

🌍
Harrycheng233
Harrycheng233

🌍
Diana Galindo
Diana Galindo

🌍
Lingxiao Wang
Lingxiao Wang

🌍
ml.008
ml.008

🌍
EmilioOcelotl
EmilioOcelotl

🌍
Teixido
Teixido

🌍
IENGROUND
IENGROUND

🌍
Orwiss
Orwiss

🌍
Aditya Rana
Aditya Rana

🌍
ml.008
ml.008

🌍
EmilioOcelotl
EmilioOcelotl

🌍
Teixido
Teixido

🌍
IENGROUND
IENGROUND

🌍
Orwiss
Orwiss

🌍
Aditya Rana
Aditya Rana

🌍
Eshaan Aggarwal
Eshaan Aggarwal

🌍
everything became blue
everything became blue

🌍
YewonCALLI
YewonCALLI

🌍
SejinOH
SejinOH

🌍 👀
Surbhi Pittie
Surbhi Pittie

🌍
nancy
nancy

🌍
Eshaan Aggarwal
Eshaan Aggarwal

🌍
everything became blue
everything became blue

🌍
YewonCALLI
YewonCALLI

🌍
SejinOH
SejinOH

🌍 👀
Surbhi Pittie
Surbhi Pittie

🌍
nancy
nancy

🌍
Akash Jaiswal
Akash Jaiswal

🌍
Jack B. Du
Jack B. Du

💡
togekisse
togekisse

🌍
tuan
tuan

🌍 🤔
Janis Sepúlveda
Janis Sepúlveda

🌍 🤔
viola
viola

🌍 🤔
Akash Jaiswal
Akash Jaiswal

🌍
Jack B. Du
Jack B. Du

💡
togekisse
togekisse

🌍
tuan
tuan

🌍 🤔
Janis Sepúlveda
Janis Sepúlveda

🌍 🤔
viola
viola

🌍 🤔
yu
yu

🌍 🤔
李坤霖
李坤霖

🐛
Leo Wang
Leo Wang

🌍
Hilary Lau
Hilary Lau

💻 ⚠️
Bobby Kazimiroff
Bobby Kazimiroff

📖
Nahuel Palumbo
Nahuel Palumbo

🐛 📖
yu
yu

🌍 🤔
李坤霖
李坤霖

🐛
Leo Wang
Leo Wang

🌍
Hilary Lau
Hilary Lau

💻 ⚠️
Bobby Kazimiroff
Bobby Kazimiroff

📖
Nahuel Palumbo
Nahuel Palumbo

🐛 📖
lottihill
lottihill

📖 🐛
Julio Lab
Julio Lab

📖
Jordan Sucher
Jordan Sucher

🐛 💻
iambiancafonseca
iambiancafonseca

📖
Vishal Sharma
Vishal Sharma

💻
PiyushChandra17
PiyushChandra17

💻 🐛 👀
lottihill
lottihill

📖 🐛
Julio Lab
Julio Lab

📖
Jordan Sucher
Jordan Sucher

🐛 💻
iambiancafonseca
iambiancafonseca

📖
Vishal Sharma
Vishal Sharma

💻
PiyushChandra17
PiyushChandra17

💻 🐛 👀
Daniel Grantham
Daniel Grantham

💻
Monica Powell
Monica Powell

📢 💡 📖 🐛
Rohan Julka
Rohan Julka

💻
Mr. Algorithm
Mr. Algorithm

📖
sambensim
sambensim

📖
NicholasGillen
NicholasGillen

📖
Daniel Grantham
Daniel Grantham

💻
Monica Powell
Monica Powell

📢 💡 📖 🐛
Rohan Julka
Rohan Julka

💻
Mr. Algorithm
Mr. Algorithm

📖
sambensim
sambensim

📖
NicholasGillen
NicholasGillen

📖
Abhinav kumar
Abhinav kumar

📖
chaski
chaski

🔬 💻 💡
Evorage
Evorage

🐛 💻
Daniel Marino
Daniel Marino

📖
Shahma Ansari
Shahma Ansari

🐛
Manan Arora
Manan Arora

📖
Abhinav kumar
Abhinav kumar

📖
chaski
chaski

🔬 💻 💡
Evorage
Evorage

🐛 💻
Daniel Marino
Daniel Marino

📖
Shahma Ansari
Shahma Ansari

🐛
Manan Arora
Manan Arora

📖
Serena20003
Serena20003

💻
Souvik Kumar
Souvik Kumar

📖
Abdiel Lopez
Abdiel Lopez

🧑‍🏫
Pim Tournaye
Pim Tournaye

💻
Martin Lorentzon
Martin Lorentzon

🐛
Rishi
Rishi

💻 🐛
Serena20003
Serena20003

💻
Souvik Kumar
Souvik Kumar

📖
Abdiel Lopez
Abdiel Lopez

🧑‍🏫
Pim Tournaye
Pim Tournaye

💻
Martin Lorentzon
Martin Lorentzon

🐛
Rishi
Rishi

💻 🐛
FORCHA PEARL
FORCHA PEARL

💻
c-dacanay
c-dacanay

🎨 📋 💡
mathewpan2
mathewpan2

💻
cog25
cog25

🌍
Aarati Akkapeddi
Aarati Akkapeddi

💻 🤔
Maya Arguelles
Maya Arguelles

💻
FORCHA PEARL
FORCHA PEARL

💻
c-dacanay
c-dacanay

🎨 📋 💡
mathewpan2
mathewpan2

💻
cog25
cog25

🌍
Aarati Akkapeddi
Aarati Akkapeddi

💻 🤔
Maya Arguelles
Maya Arguelles

💻
Shoury Singh
Shoury Singh

💻
Melody Sharp
Melody Sharp

🐛
Tibor Udvari
Tibor Udvari

💻
willallstet
willallstet

📖
Ashwani Dey
Ashwani Dey

📖
Ilona Brand
Ilona Brand

🐛
Shoury Singh
Shoury Singh

💻
Melody Sharp
Melody Sharp

🐛
Tibor Udvari
Tibor Udvari

💻
willallstet
willallstet

📖
Ashwani Dey
Ashwani Dey

📖
Ilona Brand
Ilona Brand

🐛
Antoinette Bumatay-Chan
Antoinette Bumatay-Chan

📖
benpalevsky
benpalevsky

📖
jeanette
jeanette

💻
William Hazard
William Hazard

💡
Vishesh Rawal
Vishesh Rawal

🐛 📖 💻
Callie
Callie

📖 💻
Antoinette Bumatay-Chan
Antoinette Bumatay-Chan

📖
benpalevsky
benpalevsky

📖
jeanette
jeanette

💻
William Hazard
William Hazard

💡
Vishesh Rawal
Vishesh Rawal

🐛 📖 💻
Callie
Callie

📖 💻
Jared Berghold
Jared Berghold

📖
computational mama
computational mama

💻
Fabian Morón Zirfas
Fabian Morón Zirfas

📖 💻
Luke Plowden
Luke Plowden

💻
Martin Leopold Groedl
Martin Leopold Groedl

🐛 💻
ashish singh
ashish singh

💻
Jared Berghold
Jared Berghold

📖
computational mama
computational mama

💻
Fabian Morón Zirfas
Fabian Morón Zirfas

📖 💻
Luke Plowden
Luke Plowden

💻
Martin Leopold Groedl
Martin Leopold Groedl

🐛 💻
ashish singh
ashish singh

💻
blackboxlogic
blackboxlogic

📖
ℤ

📖
dhanush
dhanush

📖
ma haidong
ma haidong

🐛 💻
Rishab Kumar Jha
Rishab Kumar Jha

🐛 💻
Rajas Samse
Rajas Samse

💻 📖
blackboxlogic
blackboxlogic

📖
ℤ

📖
dhanush
dhanush

📖
ma haidong
ma haidong

🐛 💻
Rishab Kumar Jha
Rishab Kumar Jha

🐛 💻
Rajas Samse
Rajas Samse

💻 📖
Jordan Philyaw
Jordan Philyaw

📖
oliver thurley
oliver thurley

📖 💻
Renjie Li
Renjie Li

📖 💻
Vaivaswat Dubey
Vaivaswat Dubey

💻
Xin Xin
Xin Xin

📋 📢 🧑‍🏫 🤔
Ashish Karn
Ashish Karn

💻
Jordan Philyaw
Jordan Philyaw

📖
oliver thurley
oliver thurley

📖 💻
Renjie Li
Renjie Li

📖 💻
Vaivaswat Dubey
Vaivaswat Dubey

💻
Xin Xin
Xin Xin

📋 📢 🧑‍🏫 🤔
Ashish Karn
Ashish Karn

💻
Darren Kessner
Darren Kessner

💡
Animesh Sinha
Animesh Sinha

💡
Kathryn Lichlyter
Kathryn Lichlyter

💡
Greg Albers
Greg Albers

💡
Marco Macarena
Marco Macarena

💡
Kristian Hamilton
Kristian Hamilton

💡
Darren Kessner
Darren Kessner

💡
Animesh Sinha
Animesh Sinha

💡
Kathryn Lichlyter
Kathryn Lichlyter

💡
Greg Albers
Greg Albers

💡
Marco Macarena
Marco Macarena

💡
Kristian Hamilton
Kristian Hamilton

💡
Keshav Gupta
Keshav Gupta

💡
Ritesh Patil
Ritesh Patil

💡
Gabriel Sroka
Gabriel Sroka

💡
Casey Conchinha
Casey Conchinha

💡
davidblitz
davidblitz

💡
crh82
crh82

💡
Keshav Gupta
Keshav Gupta

💡
Ritesh Patil
Ritesh Patil

💡
Gabriel Sroka
Gabriel Sroka

💡
Casey Conchinha
Casey Conchinha

💡
davidblitz
davidblitz

💡
crh82
crh82

💡
Aaron Welles
Aaron Welles
💡
Seyko
Seyko

💻
Xevi H. Aqeel
Xevi H. Aqeel

💡 🎨
Greg Stanton
Greg Stanton

🐛 💻 📖 💡 🤔 🔌 📆 📣 💬 🔬
Bojidar Marinov
Bojidar Marinov

💻 ⚠️
Chloe Yan
Chloe Yan

📖
Aaron Welles
Aaron Welles
💡
Seyko
Seyko

💻
Xevi H. Aqeel
Xevi H. Aqeel

💡 🎨
Greg Stanton
Greg Stanton

🐛 💻 📖 💡 🤔 🔌 📆 📣 💬 🔬
Bojidar Marinov
Bojidar Marinov

💻 ⚠️
Chloe Yan
Chloe Yan

📖
Mayank Verma
Mayank Verma

💻
Lauren Berrios
Lauren Berrios

🤔
roxi09
roxi09

🤔
Jackie Liu
Jackie Liu

🤔
Carrie Wang
Carrie Wang

🤔
Himanshu Kholiya
Himanshu Kholiya

💻
Mayank Verma
Mayank Verma

💻
Lauren Berrios
Lauren Berrios

🤔
roxi09
roxi09

🤔
Jackie Liu
Jackie Liu

🤔
Carrie Wang
Carrie Wang

🤔
Himanshu Kholiya
Himanshu Kholiya

💻
mclark414
mclark414

🤔
Mx. Ramsey
Mx. Ramsey

🤔
Franolich Design
Franolich Design

🐛 💻
Vik
Vik

💻 🐛 🌍
Qingfeng Huang
Qingfeng Huang

🌍
HughJacks
HughJacks

💻
mclark414
mclark414

🤔
Mx. Ramsey
Mx. Ramsey

🤔
Franolich Design
Franolich Design

🐛 💻
Vik
Vik

💻 🐛 🌍
Qingfeng Huang
Qingfeng Huang

🌍
HughJacks
HughJacks

💻
Jack L
Jack L

🐛 📖
Jack L
Jack L

🐛 📖
From c5ed76214920481a4aa6080981eede082c231cc1 Mon Sep 17 00:00:00 2001 From: LalitNarayanYadav Date: Thu, 15 May 2025 01:05:08 +0530 Subject: [PATCH 139/282] Update all-contributorsrc to set avatar image size to 64px --- .all-contributorsrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 21e77167e8..f5e8116b9c 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -4,7 +4,7 @@ "files": [ "README.md" ], - "imageSize": 120, + "imageSize": 64, "contributorsPerLine": 6, "commit": true, "contributors": [ From b3802c63815a928e0fbc696bd34f9569455b7e16 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 May 2025 22:17:25 +0000 Subject: [PATCH 140/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 949c66e5f2..5af9a232de 100644 --- a/README.md +++ b/README.md @@ -1135,6 +1135,7 @@ We recognize all types of contributions. This project follows the [all-contribut Jack L
Jack L

🐛 📖 + Claire Peng
Claire Peng

💻 🐛 From 69e96ec9cec9d25b3319068539efe8a90ba00ad1 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 May 2025 22:17:26 +0000 Subject: [PATCH 141/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 21e77167e8..620f984807 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6813,6 +6813,16 @@ "bug", "doc" ] + }, + { + "login": "clairep94", + "name": "Claire Peng", + "avatar_url": "https://avatars.githubusercontent.com/u/128436909?v=4", + "profile": "https://github.com/clairep94", + "contributions": [ + "code", + "bug" + ] } ], "repoType": "github", From 4d47eda660f4ab6b9c48152acfa0c7b18ef5b128 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Fri, 16 May 2025 19:48:22 +0000 Subject: [PATCH 142/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5af9a232de..aef9bbd0b2 100644 --- a/README.md +++ b/README.md @@ -1136,6 +1136,7 @@ We recognize all types of contributions. This project follows the [all-contribut Jack L
Jack L

🐛 📖 Claire Peng
Claire Peng

💻 🐛 + Jay Dev Jha
Jay Dev Jha

💻 From 0b64247b0a4a3ce701e31453d48bd75eddb08f24 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Fri, 16 May 2025 19:48:23 +0000 Subject: [PATCH 143/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 620f984807..07d94a5e08 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6823,6 +6823,15 @@ "code", "bug" ] + }, + { + "login": "IIITM-Jay", + "name": "Jay Dev Jha", + "avatar_url": "https://avatars.githubusercontent.com/u/65283880?v=4", + "profile": "https://github.com/IIITM-Jay", + "contributions": [ + "code" + ] } ], "repoType": "github", From 89e85e06aa2eaec75908779d23b7e5237c2a6609 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 18 May 2025 18:50:42 +0000 Subject: [PATCH 144/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index aef9bbd0b2..36d361561f 100644 --- a/README.md +++ b/README.md @@ -1137,6 +1137,7 @@ We recognize all types of contributions. This project follows the [all-contribut Jack L
Jack L

🐛 📖 Claire Peng
Claire Peng

💻 🐛 Jay Dev Jha
Jay Dev Jha

💻 + Yugal Kaushik
Yugal Kaushik

💻 📖 From 6d524664ff29fda7dc42393e2f456f7684885efa Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 18 May 2025 18:50:43 +0000 Subject: [PATCH 145/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 07d94a5e08..9497d133ae 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6832,6 +6832,16 @@ "contributions": [ "code" ] + }, + { + "login": "yugalkaushik", + "name": "Yugal Kaushik", + "avatar_url": "https://avatars.githubusercontent.com/u/138966980?v=4", + "profile": "https://yugalkaushik.vercel.app", + "contributions": [ + "code", + "doc" + ] } ], "repoType": "github", From fea414d517051dab396fc8bd14608330803cd79d Mon Sep 17 00:00:00 2001 From: ksen0 Date: Mon, 19 May 2025 17:03:08 +0100 Subject: [PATCH 146/282] Add LalitNarayanYadav for doc --- .all-contributorsrc | 9 +++++++++ README.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 9497d133ae..aa6b2bcd90 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6842,6 +6842,15 @@ "code", "doc" ] + }, + { + "login": "LalitNarayanYadav", + "name": "Lalit Narayan Yadav", + "avatar_url": "https://avatars.githubusercontent.com/u/162928571?v=4", + "profile": "https://github.com/LalitNarayanYadav", + "contributions": [ + "doc" + ] } ], "repoType": "github", diff --git a/README.md b/README.md index 36d361561f..610cb11b3b 100644 --- a/README.md +++ b/README.md @@ -1138,6 +1138,7 @@ We recognize all types of contributions. This project follows the [all-contribut Claire Peng
Claire Peng

💻 🐛 Jay Dev Jha
Jay Dev Jha

💻 Yugal Kaushik
Yugal Kaushik

💻 📖 + Lalit Narayan Yadav
Lalit Narayan Yadav

📖 From 6195f88d34c3f016c32b1bc9fe0d4e3c1a58a727 Mon Sep 17 00:00:00 2001 From: Ben Gilbert Date: Mon, 26 May 2025 00:26:18 +0100 Subject: [PATCH 147/282] Remove second call of _updateWindowSize() https://github.com/processing/p5.js/commit/173e09552c698cb2ec5e107d42280edfc9c75995 in https://github.com/processing/p5.js/pull/7785 accidently added a second call to `this._updateWindowSize();` --- src/core/main.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/core/main.js b/src/core/main.js index 4e9684dc80..b58f4de936 100644 --- a/src/core/main.js +++ b/src/core/main.js @@ -657,9 +657,6 @@ class p5 { } }; - // ensure correct reporting of window dimensions - this._updateWindowSize(); - const friendlyBindGlobal = this._createFriendlyGlobalFunctionBinder(); // If the user has created a global setup or draw function, @@ -699,6 +696,7 @@ class p5 { p5._checkForUserDefinedFunctions(this); } + // ensure correct reporting of window dimensions this._updateWindowSize(); // call any registered init functions From 493d693c0d95a561d2ff8cf9e3476f1d721da92b Mon Sep 17 00:00:00 2001 From: kit <1304340+ksen0@users.noreply.github.com> Date: Mon, 26 May 2025 10:30:40 +0200 Subject: [PATCH 148/282] Revert "fix: push() ignoring the ColorMode #7402" --- src/core/p5.Renderer.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/core/p5.Renderer.js b/src/core/p5.Renderer.js index 41417b3606..21ce3bd64b 100644 --- a/src/core/p5.Renderer.js +++ b/src/core/p5.Renderer.js @@ -86,9 +86,7 @@ class Renderer extends p5.Element { _textAlign: this._textAlign, _textBaseline: this._textBaseline, _textStyle: this._textStyle, - _textWrap: this._textWrap, - _colorMode: this._colorMode, - _colorMaxes: this._colorMaxes.slice() + _textWrap: this._textWrap } }; } From 28a7825bf8b307d91b36d1ec428aa26e2e309701 Mon Sep 17 00:00:00 2001 From: omahs <73983677+omahs@users.noreply.github.com> Date: Sun, 1 Jun 2025 10:42:56 +0200 Subject: [PATCH 149/282] Fix typos --- contributor_docs/project_wrapups/DIVYANSHU_RAJ_GSOC_20.md | 2 +- contributor_docs/project_wrapups/munusshih_gsoc_2023.md | 2 +- lib/addons/p5.sound.js | 6 +++--- src/accessibility/outputs.js | 2 +- src/core/friendly_errors/sketch_reader.js | 2 +- src/webgl/shaders/lighting.glsl | 2 +- tasks/build/browserify.js | 2 +- tasks/build/combineModules.js | 2 +- test/unit/core/environment.js | 2 +- test/unit/core/error_helpers.js | 2 +- test/unit/core/rendering.js | 4 ++-- 11 files changed, 14 insertions(+), 14 deletions(-) diff --git a/contributor_docs/project_wrapups/DIVYANSHU_RAJ_GSOC_20.md b/contributor_docs/project_wrapups/DIVYANSHU_RAJ_GSOC_20.md index d4117393fd..41c377675e 100644 --- a/contributor_docs/project_wrapups/DIVYANSHU_RAJ_GSOC_20.md +++ b/contributor_docs/project_wrapups/DIVYANSHU_RAJ_GSOC_20.md @@ -53,7 +53,7 @@ The introduction of es6 classes into the JS world , was a great relief for devel when it comes to AUDIO GRAPHS , where one node is connected to so many other nodes and inherit property from its parent nodes , a more robust and cleaner implementation of Nodes was required and ES6 classes rocked the way . -Following PR REVAMPED the p5.sound's AUDIO NODES from ``funtion syntax`` to ``ES6 classes syntax`` +Following PR REVAMPED the p5.sound's AUDIO NODES from ``function syntax`` to ``ES6 classes syntax`` [#502](https://github.com/processing/p5.js-sound/pull/502) [#503](https://github.com/processing/p5.js-sound/pull/503) diff --git a/contributor_docs/project_wrapups/munusshih_gsoc_2023.md b/contributor_docs/project_wrapups/munusshih_gsoc_2023.md index 238f673deb..8a2712b32e 100644 --- a/contributor_docs/project_wrapups/munusshih_gsoc_2023.md +++ b/contributor_docs/project_wrapups/munusshih_gsoc_2023.md @@ -69,7 +69,7 @@ In conclusion, I am grateful for my time working with p5.js typography during GS ## Features Requested ```jsx -If they're not dependent/relevant, we should do seperate PRs. +If they're not dependent/relevant, we should do separate PRs. ``` | Topic | Status | Coded? | PR? | Pushed? | diff --git a/lib/addons/p5.sound.js b/lib/addons/p5.sound.js index a8a7e3f450..f7216fca04 100644 --- a/lib/addons/p5.sound.js +++ b/lib/addons/p5.sound.js @@ -8308,7 +8308,7 @@ function reverb_setPrototypeOf(o, p) { reverb_setPrototypeOf = Object.setPrototy /** * Reverb adds depth to a sound through a large number of decaying * echoes. It creates the perception that sound is occurring in a - * physical space. The p5.Reverb has paramters for Time (how long does the + * physical space. The p5.Reverb has parameters for Time (how long does the * reverb last) and decayRate (how much the sound decays with each echo) * that can be set with the .set() or .process() methods. The p5.Convolver * extends p5.Reverb allowing you to recreate the sound of actual physical @@ -9727,7 +9727,7 @@ function () { soundLoop_classCallCheck(this, SoundLoop); /** - * Getters and Setters, setting any paramter will result in a change in the clock's + * Getters and Setters, setting any parameter will result in a change in the clock's * frequency, that will be reflected after the next callback * beats per minute (defaults to 60) * @property {Number} bpm @@ -10110,7 +10110,7 @@ function (_Effect) { this.set(attack, knee, ratio, threshold, release); } /** - * Set the paramters of a compressor. + * Set the parameters of a compressor. * @method set * @for p5.Compressor * @param {Number} attack The amount of time (in seconds) to reduce the gain by 10dB, diff --git a/src/accessibility/outputs.js b/src/accessibility/outputs.js index 1680f18e31..d712c008bc 100644 --- a/src/accessibility/outputs.js +++ b/src/accessibility/outputs.js @@ -461,7 +461,7 @@ p5.prototype._accsOutput = function(f, args) { if (f === 'line') { //make color stroke include.color = this.ingredients.colors.stroke; - //get lenght + //get length include.length = Math.round(this.dist(args[0], args[1], args[2], args[3])); //get position of end points let p1 = this._getPos(args[0], [1]); diff --git a/src/core/friendly_errors/sketch_reader.js b/src/core/friendly_errors/sketch_reader.js index 01e0076edc..b70e86bf96 100644 --- a/src/core/friendly_errors/sketch_reader.js +++ b/src/core/friendly_errors/sketch_reader.js @@ -202,7 +202,7 @@ if (typeof IS_MINIFIED !== 'undefined') { /** * Converts code written by the user to an array - * every element of which is a seperate line of code. + * every element of which is a separate line of code. * * @method codeToLines * @private diff --git a/src/webgl/shaders/lighting.glsl b/src/webgl/shaders/lighting.glsl index b66ac083d1..4110fcf2a4 100644 --- a/src/webgl/shaders/lighting.glsl +++ b/src/webgl/shaders/lighting.glsl @@ -108,7 +108,7 @@ vec2 mapTextureToNormal( vec3 v ){ vec3 calculateImageDiffuse(vec3 vNormal, vec3 vViewPosition, float metallic){ - // make 2 seperate builds + // make 2 separate builds vec3 worldCameraPosition = vec3(0.0, 0.0, 0.0); // hardcoded world camera position vec3 worldNormal = normalize(vNormal * uCameraRotation); vec2 newTexCoor = mapTextureToNormal( worldNormal ); diff --git a/tasks/build/browserify.js b/tasks/build/browserify.js index 2d3fa59245..0af45c985a 100644 --- a/tasks/build/browserify.js +++ b/tasks/build/browserify.js @@ -37,7 +37,7 @@ module.exports = function(grunt) { if (isDev) { globalVars['P5_DEV_BUILD'] = () => true; } - // Invoke Browserify programatically to bundle the code + // Invoke Browserify programmatically to bundle the code let browserified = browserify(srcFilePath, { standalone: 'p5', insertGlobalVars: globalVars diff --git a/tasks/build/combineModules.js b/tasks/build/combineModules.js index 17db3f898b..6fb699a66c 100644 --- a/tasks/build/combineModules.js +++ b/tasks/build/combineModules.js @@ -52,7 +52,7 @@ module.exports = function(grunt) { // Target file path const libFilePath = path.resolve('lib/modules/' + filename); - // Invoke Browserify programatically to bundle the code + // Invoke Browserify programmatically to bundle the code let browseified = browserify(tempFilePath, { standalone: 'p5' }); diff --git a/test/unit/core/environment.js b/test/unit/core/environment.js index 4ab600a0e9..ed40189581 100644 --- a/test/unit/core/environment.js +++ b/test/unit/core/environment.js @@ -41,7 +41,7 @@ suite('Environment', function() { frames += 1; assert.equal(myp5.frameCount, frames); if (frames === start + 5) { - // Test 5 seperate redraws + // Test 5 separate redraws myp5.noLoop(); setTimeout(myp5.redraw.bind(myp5), 10); setTimeout(myp5.redraw.bind(myp5), 20); diff --git a/test/unit/core/error_helpers.js b/test/unit/core/error_helpers.js index 75ad06e31f..50f5d2bd55 100644 --- a/test/unit/core/error_helpers.js +++ b/test/unit/core/error_helpers.js @@ -522,7 +522,7 @@ suite('Error Helpers', function() { }); }); -// seperating in another suite because these don't need to initialize myp5 +// separating in another suite because these don't need to initialize myp5 // for each test. Instead they initialize p5 in the iframe. These tests are // also slower than the above ones. suite('Global Error Handling', function() { diff --git a/test/unit/core/rendering.js b/test/unit/core/rendering.js index 2f917a2ace..8e932761ed 100644 --- a/test/unit/core/rendering.js +++ b/test/unit/core/rendering.js @@ -174,14 +174,14 @@ suite('Rendering', function() { webglMethod + '() should throw a WEBGL assertion Error', (function(webglMethod) { return function() { - var validateParamters = myp5.validateParameters; + var validateParameters = myp5.validateParameters; myp5.validateParameters = false; try { expect(function() { myp5[webglMethod].call(myp5); }).to.throw(Error, /is only supported in WEBGL mode/); } finally { - myp5.validateParameters = validateParamters; + myp5.validateParameters = validateParameters; } }; })(webglMethod) From 0af0b73cb609f7c335fb6a79de91ac14b6469e3b Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 1 Jun 2025 15:45:39 +0000 Subject: [PATCH 150/282] docs: update README.md [skip ci] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6f4b71cce8..2368d609f6 100644 --- a/README.md +++ b/README.md @@ -1134,12 +1134,12 @@ We recognize all types of contributions. This project follows the [all-contribut HughJacks
HughJacks

💻 - Jack L
Jack L

🐛 📖 Jack L
Jack L

🐛 📖 Claire Peng
Claire Peng

💻 🐛 Jay Dev Jha
Jay Dev Jha

💻 Yugal Kaushik
Yugal Kaushik

💻 📖 Lalit Narayan Yadav
Lalit Narayan Yadav

📖 + Irina Mengqi Wang
Irina Mengqi Wang

💡 From ade62e4a5eb96fc40a9e8ad608272d4819de1173 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 1 Jun 2025 15:45:45 +0000 Subject: [PATCH 151/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index c4cc53ddeb..5c1ea30326 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6851,6 +6851,15 @@ "contributions": [ "doc" ] + }, + { + "login": "irina-wang", + "name": "Irina Mengqi Wang", + "avatar_url": "https://avatars.githubusercontent.com/u/59970384?v=4", + "profile": "https://github.com/irina-wang", + "contributions": [ + "example" + ] } ], "repoType": "github", From a2341d6248e223c479f93f9360e53c935c520ff5 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 1 Jun 2025 15:53:19 +0000 Subject: [PATCH 152/282] docs: update README.md [skip ci] --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 2368d609f6..9c0b3af306 100644 --- a/README.md +++ b/README.md @@ -1141,6 +1141,9 @@ We recognize all types of contributions. This project follows the [all-contribut Lalit Narayan Yadav
Lalit Narayan Yadav

📖 Irina Mengqi Wang
Irina Mengqi Wang

💡 + + Jenny Biette Kowalski
Jenny Biette Kowalski

🤔 + From b1a61a210a3a4f3b1088a5fa312b952bea9547f8 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 1 Jun 2025 15:53:20 +0000 Subject: [PATCH 153/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 5c1ea30326..adff062def 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6860,6 +6860,15 @@ "contributions": [ "example" ] + }, + { + "login": "jennybkowalski", + "name": "Jenny Biette Kowalski", + "avatar_url": "https://avatars.githubusercontent.com/u/11235412?v=4", + "profile": "http://jennybkowalski.com", + "contributions": [ + "ideas" + ] } ], "repoType": "github", From 52dea28242975e2cc9b7b77d4e3712fb7715f0a6 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 1 Jun 2025 15:56:36 +0000 Subject: [PATCH 154/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9c0b3af306..79561f41be 100644 --- a/README.md +++ b/README.md @@ -1143,6 +1143,7 @@ We recognize all types of contributions. This project follows the [all-contribut Jenny Biette Kowalski
Jenny Biette Kowalski

🤔 + Laith Alwazani
Laith Alwazani

🤔 From 1e56a202e5a64315037a1b039a9b2cd7115ecec4 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 1 Jun 2025 15:56:37 +0000 Subject: [PATCH 155/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index adff062def..3485aa0eb2 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6869,6 +6869,15 @@ "contributions": [ "ideas" ] + }, + { + "login": "Wlaith", + "name": "Laith Alwazani", + "avatar_url": "https://avatars.githubusercontent.com/u/98265005?v=4", + "profile": "https://github.com/wlaith", + "contributions": [ + "ideas" + ] } ], "repoType": "github", From c92f1ac86e35aed002298055521ab5be3510cab9 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 1 Jun 2025 15:59:16 +0000 Subject: [PATCH 156/282] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 79561f41be..525835aaf3 100644 --- a/README.md +++ b/README.md @@ -1144,6 +1144,7 @@ We recognize all types of contributions. This project follows the [all-contribut Jenny Biette Kowalski
Jenny Biette Kowalski

🤔 Laith Alwazani
Laith Alwazani

🤔 + jep
jep

🤔 From 74331e833256b5380f0c334e449e7a226e0a0e17 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 1 Jun 2025 15:59:17 +0000 Subject: [PATCH 157/282] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 3485aa0eb2..48b90d2c99 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6878,6 +6878,15 @@ "contributions": [ "ideas" ] + }, + { + "login": "jep-a", + "name": "jep", + "avatar_url": "https://avatars.githubusercontent.com/u/20326207?v=4", + "profile": "https://github.com/jep-a", + "contributions": [ + "ideas" + ] } ], "repoType": "github", From fff7a8aaf830fe47ced564518aaad54b082229d4 Mon Sep 17 00:00:00 2001 From: ksen0 Date: Tue, 3 Jun 2025 00:17:51 +0200 Subject: [PATCH 158/282] Add @dpanshug for doc --- .all-contributorsrc | 9 +++++++++ README.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 48b90d2c99..1114714537 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6887,6 +6887,15 @@ "contributions": [ "ideas" ] + }, + { + "login": "dpanshug", + "name": "Dipanshu Gupta", + "avatar_url": "https://avatars.githubusercontent.com/u/97534722?v=4", + "profile": "https://github.com/dpanshug", + "contributions": [ + "doc" + ] } ], "repoType": "github", diff --git a/README.md b/README.md index 525835aaf3..ef45a87a39 100644 --- a/README.md +++ b/README.md @@ -1145,6 +1145,7 @@ We recognize all types of contributions. This project follows the [all-contribut Jenny Biette Kowalski
Jenny Biette Kowalski

🤔 Laith Alwazani
Laith Alwazani

🤔 jep
jep

🤔 + Dipanshu Gupta
Dipanshu Gupta

📖 From d7797caae4bdfaf367266c77e5d1c69f44979a70 Mon Sep 17 00:00:00 2001 From: ksen0 Date: Tue, 3 Jun 2025 11:34:41 +0200 Subject: [PATCH 159/282] Add stewards list and updating action --- .github/workflows/stewards-update.yml | 33 +++++++++++++++++ stewards.yml | 53 +++++++++++++++++++++++++++ utils/stewards-table.js | 53 +++++++++++++++++++++++++++ 3 files changed, 139 insertions(+) create mode 100644 .github/workflows/stewards-update.yml create mode 100644 stewards.yml create mode 100644 utils/stewards-table.js diff --git a/.github/workflows/stewards-update.yml b/.github/workflows/stewards-update.yml new file mode 100644 index 0000000000..ed6ad9668f --- /dev/null +++ b/.github/workflows/stewards-update.yml @@ -0,0 +1,33 @@ +name: Update Steward Table in README + +on: + push: + branches: [main] + paths: + - stewards.yml + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install dependencies + run: npm install js-yaml + + - name: Run table generator + run: node utils/stewards-table.js + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v5 + with: + commit-message: "Update README table from stewards.yml" + branch: update-readme-table + title: 'chore: update README table from stewards.yml' + body: 'This PR updates the README.md table to refelct changes in stewards.yml.' + add: README.md diff --git a/stewards.yml b/stewards.yml new file mode 100644 index 0000000000..8e86a17676 --- /dev/null +++ b/stewards.yml @@ -0,0 +1,53 @@ + +calebfoss: + - Accessibility + +davepagurek: + - Core + - Maintainers + - Graphics: + - WebGL + +dhowe: + - Typography + +qianqianye: + - Maintainers + +ogbabydiesal: + - p5.sound.js + +limzykenneth: + - Maintainers + - DevOps + - Documentation + - Color + - i18n: + - zh + +perminder-17: + - Graphics: + - WebGL + - Documentation + - Maintainers + +lukeplowden: + - Graphics: + - WebGL + - p5.strands + +ksen0: + - Maintainers + - p5.js-website + +Divyansh013: + - i18n: + - hi + +GregStanton: + - Math + - Shapes + +holomorfo: + - Math + diff --git a/utils/stewards-table.js b/utils/stewards-table.js new file mode 100644 index 0000000000..632202c033 --- /dev/null +++ b/utils/stewards-table.js @@ -0,0 +1,53 @@ +const yaml = require('js-yaml'); +const fs = require('fs'); + +const yamlData = fs.readFileSync('stewards.yml', 'utf8'); +const parsed = yaml.load(yamlData); + +const areaMap = {}; +const maintainers = new Set(); +const supportedi18n = new Set(['hi', 'ko', 'zh', 'es']); + +for (const [user, roles] of Object.entries(parsed)) { + roles.forEach(role => { + if (typeof role === 'string') { + if (role.toLowerCase() === 'maintainers') { + maintainers.add(user); + } + areaMap[role] = areaMap[role] || new Set(); + areaMap[role].add(`@${user}`); + } else { + for (const [main, subs] of Object.entries(role)) { + subs.forEach(sub => { + if (main === 'i18n' && !supportedi18n.has(sub)) return; + const key = `${main} (${sub})`; + areaMap[key] = areaMap[key] || new Set(); + areaMap[key].add(`@${user}`); + }); + } + } + }); +} + +const header = '| Area | Steward(s) |'; +const divider = '|------|-------------|'; + +const sortedEntries = Object.entries(areaMap).sort(([aKey], [bKey]) => { + if (aKey === 'Maintainers') return -1; + if (bKey === 'Maintainers') return 1; + return aKey.localeCompare(bKey); +}); + +const rows = sortedEntries.map(([area, users]) => `| ${area} | ${[...users].sort().map( + u => `[@${u}](https://github.com/${u})` +).join(', ')} |`).join('\n'); +const newTable = [header, divider, rows].join('\n'); + +let readme = fs.readFileSync('README.md', 'utf8'); + +readme = readme.replace( + /\| *Area *\|.*\n\|[-| ]+\|\n(?:\|.*\|\n?)*/g, + newTable + '\n' +); + +fs.writeFileSync('README.md', readme); From 7b80ec54baedf5676338b43abbf4f22d0992b502 Mon Sep 17 00:00:00 2001 From: ksen0 Date: Tue, 3 Jun 2025 12:19:55 +0200 Subject: [PATCH 160/282] Udpate stewardship guidelines --- contributor_docs/steward_guidelines.md | 59 +++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/contributor_docs/steward_guidelines.md b/contributor_docs/steward_guidelines.md index 98cbdbebdc..8226d5e8f1 100644 --- a/contributor_docs/steward_guidelines.md +++ b/contributor_docs/steward_guidelines.md @@ -2,11 +2,15 @@ # Steward Guidelines -Whether you have just joined us as a steward, are a seasoned maintainer of p5.js, or are somewhere in between, this guide contains information as well as tips and tricks that will help you effectively contribute to p5.js. Most of what is written here are guidelines unless otherwise stated, which means you can adapt the practices shown here to suit your workflow. +Whether you are new to p5.js contribution, are already active on the p5.js GitHub repositories, or are somewhere in between, this guide contains information about p5.js stewardship. If you are not sure what to expect from stewards, or if you considering how to volunteer or get started as a steward, read on! ## Table of Contents +- [Stewardship] + - [Community Care](#community-care) + - [Areas](#areas) + - [Becoming a Steward](#becoming-a-steward) - [Issues](#issues) - [Bug report](#bug-report) - [Feature request](#feature-request) @@ -28,6 +32,59 @@ Whether you have just joined us as a steward, are a seasoned maintainer of p5.js --- +## Stewardship + +### Community Care + +An open source ethos includes [accessibility, education, collaboration, transparency, and agency](https://www.opensourceethos.net/). To live and practice these values while we write code together needs a lot of community care. These are the community care practices that are part of our definition of stewardship: + +1. Welcoming new contributors to GitHub through **friendly comments** and helpful **code reviews** +2. Helping to **facilitate feature discussions** and resolve technical disagreements +3. Suporting **releases** of the p5.js software through bug reporting, bug fixing, feature completion + +The rest of these guidelines provide some tips and tricks that will help you effectively contribute to p5.js, and to helpfully guide others' contributions. Most of what is written here are guidelines unless otherwise stated, which means you can adapt the practices shown here to suit your workflow. + +Everyone is invited to help steward the community when you can! We are happy to see contributors welcome new contributors, review others' code, and provide API design feedback. There are also some concrete roles: + +1. Contributors are able to make Issues, PRs, Comments, and Code Reviews. +2. Maintainers are also able to merge PRs and admin other parts of the codebase. + +Stewards sit in-between: they can make Issues, PRs, Comments, and Code Reviews, but when they are stewarding a particular area, they can also be tagged by other contributors to help with discussion and review. + +As a contributor, you can check the current stewards in the p5.js repository's README file and tag relevant stewards - but please be mindful of our contributor guidelines, which emphasize patience and mindfulness that most of the technical work on an open-source project is volunteer. + +As a steward, we hope that you regularly chime in on code reviews on Issues or PRs that you did not make, if they are in your area and if you are able to provide helpful guidance! + +### Areas + +There are different areas of work that stewards can be responsible for. These areas match the GitHub Labels in most cases, with a couple of exceptions. Below is the list of areas. + +- Accessibility: This area specifically refers to digital and web accessibility, including, for example, screen reader suport via API like `describe(..)` as well as accessibility support on the reference website +- Core: Refers to core p5.js API, including rendering and environment +- DevOps: Refers to build process, unit testing, +- Documentation: includes both reference in the core codebase that is exposed on the website, the contributor docs, and other website content +- i18n (Internationalization): Includes writing and reviewing translations, specifically for the supported languages on the reference website (`es`, `hi`, `ko`, `zh`) +- Graphics: Contains subareas of WebGL and [p5.strands](https://beta.p5js.org/tutorials/intro-to-p5-strands/) +- Color: Includes Color, ColorMode, accessibility improvements around color usage, colro in 2D and 3D, and so on +- Typography: Refers to all topics on handling text and font +- Math: Includes both external Math API and internal performance improvements +- Shapes: Includes working with custom shapes in both 1.11.x and 2.x versions of p5.js +- Maintainers: this is not an area, but rather the group of contributors who have the ability to merge PRs +- p5.sound.js: The [new p5.sound.js](https://github.com/processing/p5.sound.js) addon library +- p5.js-website: Non-content aspects of the [reference website](https://p5js.org/) - for example, its structure, automations, technical improvements and so on. + +These focus areas may change over time depending on the needs of the project - so if you are going through the process of applying to be a steward, you are welcome to proposals new areas! + +### Becoming a Steward + +There are two ways to become a steward: + +1. Nomination by maintainers or other stewards - this can happen in conversation over Discord or GitHub, and a maintainer may reach out to you +2. Application by creating a PR to update `stewards.yml` with your GitHub @ and proposed areas. Please keep in mind each area should have 1-3 stewards. We are always looking for **translation stewards**! Once you make your application PR, other maintainers or stewards may ask for additional supporting material, like making a PR related to the areas you're interested in, or participating in some related discussion. + +To remain a steward, you must contribute as a steward to at least 1 of the 2 most recent minor (e.g., 2.1.0 or 1.11.0 - when the middle number changes) or major releases (e.g., 2.0 - when the leftmsot number changes). This means supporting other contributors through discussion or code review. + +To step down from stewardship, you can make a PR to remove yourself from `stewards.yml`. You are always welcome to take a pause and reapply in the future! ## Issues From cbfce123135d6b76eb4952138091321e677672f3 Mon Sep 17 00:00:00 2001 From: kit <1304340+ksen0@users.noreply.github.com> Date: Tue, 3 Jun 2025 12:26:16 +0200 Subject: [PATCH 161/282] Update steward_guidelines.md --- contributor_docs/steward_guidelines.md | 36 ++++++++++++-------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/contributor_docs/steward_guidelines.md b/contributor_docs/steward_guidelines.md index 8226d5e8f1..4186318289 100644 --- a/contributor_docs/steward_guidelines.md +++ b/contributor_docs/steward_guidelines.md @@ -7,7 +7,7 @@ Whether you are new to p5.js contribution, are already active on the p5.js GitHu ## Table of Contents -- [Stewardship] +- [Stewardship](#stewardship) - [Community Care](#community-care) - [Areas](#areas) - [Becoming a Steward](#becoming-a-steward) @@ -59,19 +59,19 @@ As a steward, we hope that you regularly chime in on code reviews on Issues or P There are different areas of work that stewards can be responsible for. These areas match the GitHub Labels in most cases, with a couple of exceptions. Below is the list of areas. -- Accessibility: This area specifically refers to digital and web accessibility, including, for example, screen reader suport via API like `describe(..)` as well as accessibility support on the reference website -- Core: Refers to core p5.js API, including rendering and environment -- DevOps: Refers to build process, unit testing, -- Documentation: includes both reference in the core codebase that is exposed on the website, the contributor docs, and other website content -- i18n (Internationalization): Includes writing and reviewing translations, specifically for the supported languages on the reference website (`es`, `hi`, `ko`, `zh`) -- Graphics: Contains subareas of WebGL and [p5.strands](https://beta.p5js.org/tutorials/intro-to-p5-strands/) -- Color: Includes Color, ColorMode, accessibility improvements around color usage, colro in 2D and 3D, and so on -- Typography: Refers to all topics on handling text and font -- Math: Includes both external Math API and internal performance improvements -- Shapes: Includes working with custom shapes in both 1.11.x and 2.x versions of p5.js -- Maintainers: this is not an area, but rather the group of contributors who have the ability to merge PRs -- p5.sound.js: The [new p5.sound.js](https://github.com/processing/p5.sound.js) addon library -- p5.js-website: Non-content aspects of the [reference website](https://p5js.org/) - for example, its structure, automations, technical improvements and so on. +- **Accessibility**: This area specifically refers to digital and web accessibility, including, for example, screen reader suport via API like `describe(..)` as well as accessibility support on the reference website +- **Core**: Refers to core p5.js API, including rendering and environment +- **DevOps**: Refers to build process, unit testing, +- **Documentation**: includes both reference in the core codebase that is exposed on the website, the contributor docs, and other website content +- i18n (Internationalization / **Translation**): Includes writing and reviewing translations, particularly for `es`, `hi`, `ko`, `zh` +- **Graphics**: Contains subareas of WebGL and [p5.strands](https://beta.p5js.org/tutorials/intro-to-p5-strands/) +- **Color**: Includes Color, ColorMode, accessibility improvements around color usage, colro in 2D and 3D, and so on +- **Typography**: Refers to all topics on handling text and font +- **Math**: Includes both external Math API and internal performance improvements +- **Shapes**: Includes working with custom shapes in both 1.11.x and 2.x versions of p5.js +- **Maintainers**: This group can merge PRs +- **p5.sound.js**: The [new p5.sound.js](https://github.com/processing/p5.sound.js) addon library +- **p5.js-website**: Non-content aspects of the [reference website](https://p5js.org/) - for example, its structure, automations, technical improvements and so on. These focus areas may change over time depending on the needs of the project - so if you are going through the process of applying to be a steward, you are welcome to proposals new areas! @@ -79,12 +79,10 @@ These focus areas may change over time depending on the needs of the project - s There are two ways to become a steward: -1. Nomination by maintainers or other stewards - this can happen in conversation over Discord or GitHub, and a maintainer may reach out to you -2. Application by creating a PR to update `stewards.yml` with your GitHub @ and proposed areas. Please keep in mind each area should have 1-3 stewards. We are always looking for **translation stewards**! Once you make your application PR, other maintainers or stewards may ask for additional supporting material, like making a PR related to the areas you're interested in, or participating in some related discussion. +1. _Nomination_ by maintainers or other stewards, such as in conversation over Discord, Discourse, or GitHub. +2. _Application_ by creating a PR to update `stewards.yml` with your GitHub @ and proposed areas. Please keep in mind each area should have 1-3 stewards. We are always looking for **translation stewards**! Once you make your application PR, other maintainers or stewards may ask for additional supporting material, like making a PR related to the areas you're interested in, or participating in some related discussion. -To remain a steward, you must contribute as a steward to at least 1 of the 2 most recent minor (e.g., 2.1.0 or 1.11.0 - when the middle number changes) or major releases (e.g., 2.0 - when the leftmsot number changes). This means supporting other contributors through discussion or code review. - -To step down from stewardship, you can make a PR to remove yourself from `stewards.yml`. You are always welcome to take a pause and reapply in the future! +To remain a steward, you must contribute as a steward to at least 1 of the 2 most recent minor (e.g., 2.1.0 or 1.11.0 - when the middle number changes). These are not as frequent as patches (e.g., 2.0.3 to 2.0.4 - when the rightmost number changes), and in practice this means that stewards are expected to be active every 4-6 months or so, supporting other contributors through discussion or code review - not necessarily writing code. To step down from stewardship, you can make a PR to remove yourself from `stewards.yml`. You are always welcome to take a pause and reapply in the future! ## Issues From d9959fced1b56635e36abc668a246f3e66996de7 Mon Sep 17 00:00:00 2001 From: ksen0 Date: Tue, 3 Jun 2025 12:59:36 +0200 Subject: [PATCH 162/282] Update stewards.yml --- stewards.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/stewards.yml b/stewards.yml index 8e86a17676..907c5e73d1 100644 --- a/stewards.yml +++ b/stewards.yml @@ -1,3 +1,6 @@ +aferriss: + - Graphics: + - WebGL calebfoss: - Accessibility From a8a8dd206f2e0ad0a31f9541439e1c0d9346d40f Mon Sep 17 00:00:00 2001 From: kit <1304340+ksen0@users.noreply.github.com> Date: Tue, 3 Jun 2025 13:00:20 +0200 Subject: [PATCH 163/282] Update contributor_docs/steward_guidelines.md Co-authored-by: Dave Pagurek --- contributor_docs/steward_guidelines.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contributor_docs/steward_guidelines.md b/contributor_docs/steward_guidelines.md index 4186318289..10847fb047 100644 --- a/contributor_docs/steward_guidelines.md +++ b/contributor_docs/steward_guidelines.md @@ -82,7 +82,7 @@ There are two ways to become a steward: 1. _Nomination_ by maintainers or other stewards, such as in conversation over Discord, Discourse, or GitHub. 2. _Application_ by creating a PR to update `stewards.yml` with your GitHub @ and proposed areas. Please keep in mind each area should have 1-3 stewards. We are always looking for **translation stewards**! Once you make your application PR, other maintainers or stewards may ask for additional supporting material, like making a PR related to the areas you're interested in, or participating in some related discussion. -To remain a steward, you must contribute as a steward to at least 1 of the 2 most recent minor (e.g., 2.1.0 or 1.11.0 - when the middle number changes). These are not as frequent as patches (e.g., 2.0.3 to 2.0.4 - when the rightmost number changes), and in practice this means that stewards are expected to be active every 4-6 months or so, supporting other contributors through discussion or code review - not necessarily writing code. To step down from stewardship, you can make a PR to remove yourself from `stewards.yml`. You are always welcome to take a pause and reapply in the future! +To remain a steward, you must contribute as a steward to at least 1 of the 2 most recent minor releases (e.g., 2.1.0 or 1.11.0 - when the middle number changes). These are not as frequent as patches (e.g., 2.0.3 to 2.0.4 - when the rightmost number changes), and in practice this means that stewards are expected to be active every 4-6 months or so, supporting other contributors through discussion or code review - not necessarily writing code. To step down from stewardship, you can make a PR to remove yourself from `stewards.yml`. You are always welcome to take a pause and reapply in the future! ## Issues From a2ca6d0f503d4c1206e5d80c7210c78ff6b2c54b Mon Sep 17 00:00:00 2001 From: kit <1304340+ksen0@users.noreply.github.com> Date: Tue, 3 Jun 2025 14:56:15 +0200 Subject: [PATCH 164/282] Update contributor_docs/steward_guidelines.md Co-authored-by: Kenneth Lim --- contributor_docs/steward_guidelines.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contributor_docs/steward_guidelines.md b/contributor_docs/steward_guidelines.md index 10847fb047..6eb1c0e430 100644 --- a/contributor_docs/steward_guidelines.md +++ b/contributor_docs/steward_guidelines.md @@ -40,7 +40,7 @@ An open source ethos includes [accessibility, education, collaboration, transpar 1. Welcoming new contributors to GitHub through **friendly comments** and helpful **code reviews** 2. Helping to **facilitate feature discussions** and resolve technical disagreements -3. Suporting **releases** of the p5.js software through bug reporting, bug fixing, feature completion +3. Suporting releases of the p5.js software through **supporting** bug fixing and feature completion The rest of these guidelines provide some tips and tricks that will help you effectively contribute to p5.js, and to helpfully guide others' contributions. Most of what is written here are guidelines unless otherwise stated, which means you can adapt the practices shown here to suit your workflow. From 8e3902804b56b8ccb94158b36e20bbf0e73ee8a1 Mon Sep 17 00:00:00 2001 From: kit <1304340+ksen0@users.noreply.github.com> Date: Tue, 3 Jun 2025 14:56:25 +0200 Subject: [PATCH 165/282] Update contributor_docs/steward_guidelines.md Co-authored-by: Kenneth Lim --- contributor_docs/steward_guidelines.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contributor_docs/steward_guidelines.md b/contributor_docs/steward_guidelines.md index 6eb1c0e430..fcb96ee2c1 100644 --- a/contributor_docs/steward_guidelines.md +++ b/contributor_docs/steward_guidelines.md @@ -49,7 +49,7 @@ Everyone is invited to help steward the community when you can! We are happy to 1. Contributors are able to make Issues, PRs, Comments, and Code Reviews. 2. Maintainers are also able to merge PRs and admin other parts of the codebase. -Stewards sit in-between: they can make Issues, PRs, Comments, and Code Reviews, but when they are stewarding a particular area, they can also be tagged by other contributors to help with discussion and review. +Stewards can also be contributors: they can make Issues and PRs as contributors, while they also take on responsibility, when they are stewarding a particular area, to comment on issues and do code reviews, especially when tagged by other contributors to help with discussion and review. As a contributor, you can check the current stewards in the p5.js repository's README file and tag relevant stewards - but please be mindful of our contributor guidelines, which emphasize patience and mindfulness that most of the technical work on an open-source project is volunteer. From 842e9c49d60fc6545a7cae158b05ebdcdfe4d816 Mon Sep 17 00:00:00 2001 From: ksen0 Date: Tue, 3 Jun 2025 15:02:41 +0200 Subject: [PATCH 166/282] Clarified to the stewardship responsibilities list --- contributor_docs/steward_guidelines.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contributor_docs/steward_guidelines.md b/contributor_docs/steward_guidelines.md index fcb96ee2c1..f85d903671 100644 --- a/contributor_docs/steward_guidelines.md +++ b/contributor_docs/steward_guidelines.md @@ -39,8 +39,8 @@ Whether you are new to p5.js contribution, are already active on the p5.js GitHu An open source ethos includes [accessibility, education, collaboration, transparency, and agency](https://www.opensourceethos.net/). To live and practice these values while we write code together needs a lot of community care. These are the community care practices that are part of our definition of stewardship: 1. Welcoming new contributors to GitHub through **friendly comments** and helpful **code reviews** -2. Helping to **facilitate feature discussions** and resolve technical disagreements -3. Suporting releases of the p5.js software through **supporting** bug fixing and feature completion +2. Helping to **facilitate feature discussions** and resolve technical disagreements. For example, this means making connections to other past discussion, or offering input from prior relevant experience. Suggesting features or working on them is contribution, rather than stewardship. +3. Participating in releases of the p5.js software through **supporting** bug fixing and feature completion. For example, this means guiding other contributors and reviewing their PRs. Fixing bugs is contribution, rather than stewardship. The rest of these guidelines provide some tips and tricks that will help you effectively contribute to p5.js, and to helpfully guide others' contributions. Most of what is written here are guidelines unless otherwise stated, which means you can adapt the practices shown here to suit your workflow. @@ -59,11 +59,11 @@ As a steward, we hope that you regularly chime in on code reviews on Issues or P There are different areas of work that stewards can be responsible for. These areas match the GitHub Labels in most cases, with a couple of exceptions. Below is the list of areas. -- **Accessibility**: This area specifically refers to digital and web accessibility, including, for example, screen reader suport via API like `describe(..)` as well as accessibility support on the reference website +- **Accessibility**: This area specifically refers to digital and web accessibility, including, for example, screen reader support via API like `describe(..)` as well as accessibility support on the reference website - **Core**: Refers to core p5.js API, including rendering and environment -- **DevOps**: Refers to build process, unit testing, +- **DevOps**: Refers to build process, unit testing, and other aspects of the development experience - **Documentation**: includes both reference in the core codebase that is exposed on the website, the contributor docs, and other website content -- i18n (Internationalization / **Translation**): Includes writing and reviewing translations, particularly for `es`, `hi`, `ko`, `zh` +- i18n (Internationalization / **Translation**): Includes reviewing translations, particularly for `es`, `hi`, `ko`, `zh` - **Graphics**: Contains subareas of WebGL and [p5.strands](https://beta.p5js.org/tutorials/intro-to-p5-strands/) - **Color**: Includes Color, ColorMode, accessibility improvements around color usage, colro in 2D and 3D, and so on - **Typography**: Refers to all topics on handling text and font From ac35cc1f13f01ab1a1020a8fdeaa0528483f6050 Mon Sep 17 00:00:00 2001 From: sukrucildirr Date: Wed, 4 Jun 2025 14:07:24 +0300 Subject: [PATCH 167/282] Update reference.js --- docs/yuidoc-p5-theme/assets/js/reference.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/yuidoc-p5-theme/assets/js/reference.js b/docs/yuidoc-p5-theme/assets/js/reference.js index 455d4425d9..bfcfe7c281 100644 --- a/docs/yuidoc-p5-theme/assets/js/reference.js +++ b/docs/yuidoc-p5-theme/assets/js/reference.js @@ -1317,7 +1317,7 @@ define('typeahead',[], function() { wordsOnly: false, caseSensitive: false }; - return function hightlight(o) { + return function highlight(o) { var regex; o = _.mixin({}, defaults, o); if (!o.node || !o.pattern) { @@ -1325,8 +1325,8 @@ define('typeahead',[], function() { } o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ]; regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly); - traverse(o.node, hightlightTextNode); - function hightlightTextNode(textNode) { + traverse(o.node, highlightTextNode); + function highlightTextNode(textNode) { var match, patternNode; if (match = regex.exec(textNode.data)) { wrapperNode = doc.createElement(o.tagName); @@ -1338,14 +1338,14 @@ define('typeahead',[], function() { } return !!match; } - function traverse(el, hightlightTextNode) { + function traverse(el, highlightTextNode) { var childNode, TEXT_NODE_TYPE = 3; for (var i = 0; i < el.childNodes.length; i++) { childNode = el.childNodes[i]; if (childNode.nodeType === TEXT_NODE_TYPE) { - i += hightlightTextNode(childNode) ? 1 : 0; + i += highlightTextNode(childNode) ? 1 : 0; } else { - traverse(childNode, hightlightTextNode); + traverse(childNode, highlightTextNode); } } } @@ -3104,7 +3104,7 @@ var prettyPrint; * recognized. * * Shortcut is an optional string of characters, any of which, if the first - * character, gurantee that this pattern and only this pattern matches. + * character, guarantee that this pattern and only this pattern matches. * * @param {Array} shortcutStylePatterns patterns that always start with * a known character. Must have a shortcut string. @@ -3387,12 +3387,12 @@ var prettyPrint; // preprocessor directives. // This definition of punctuation does not include # in the list of - // follow-on exclusions, so # will not be broken before if preceeded + // follow-on exclusions, so # will not be broken before if preceded // by a punctuation character. We could try to exclude # after // [|&;<>] but that doesn't seem to cause many major problems. // If that does turn out to be a problem, we should change the below // when hc is truthy to include # in the run of punctuation characters - // only when not followint [|&;<>]. + // only when not following [|&;<>]. '^.[^\\s\\w.$@\'"`/\\\\]*'; if (options['regexLiterals']) { punctuation += '(?!\s*\/)'; @@ -4546,7 +4546,7 @@ define('pageView',[ 'libraryView' ], function(App, searchView, listView, itemView, menuView, libraryView) { - // Store the original title parts so we can substitue different endings. + // Store the original title parts so we can substitute different endings. var _originalDocumentTitle = window.document.title; var pageView = Backbone.View.extend({ From c5378be6c24ec46c67f792b0730e2f3992901791 Mon Sep 17 00:00:00 2001 From: sukrucildirr Date: Wed, 4 Jun 2025 14:09:20 +0300 Subject: [PATCH 168/282] Update reference.js.map --- docs/yuidoc-p5-theme/assets/js/reference.js.map | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/yuidoc-p5-theme/assets/js/reference.js.map b/docs/yuidoc-p5-theme/assets/js/reference.js.map index abfb0b3794..acd5500701 100644 --- a/docs/yuidoc-p5-theme/assets/js/reference.js.map +++ b/docs/yuidoc-p5-theme/assets/js/reference.js.map @@ -33,22 +33,22 @@ "/**\n * @license RequireJS text 2.0.10 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.\n * Available via the MIT or new BSD license.\n * see: http://github.com/requirejs/text for details\n */\n/*jslint regexp: true */\n/*global require, XMLHttpRequest, ActiveXObject,\n define, window, process, Packages,\n java, location, Components, FileUtils */\n\ndefine('text',['module'], function (module) {\n 'use strict';\n\n var text, fs, Cc, Ci, xpcIsWindows,\n progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'],\n xmlRegExp = /^\\s*<\\?xml(\\s)+version=[\\'\\\"](\\d)*.(\\d)*[\\'\\\"](\\s)*\\?>/im,\n bodyRegExp = /]*>\\s*([\\s\\S]+)\\s*<\\/body>/im,\n hasLocation = typeof location !== 'undefined' && location.href,\n defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\\:/, ''),\n defaultHostName = hasLocation && location.hostname,\n defaultPort = hasLocation && (location.port || undefined),\n buildMap = {},\n masterConfig = (module.config && module.config()) || {};\n\n text = {\n version: '2.0.10',\n\n strip: function (content) {\n //Strips declarations so that external SVG and XML\n //documents can be added to a document without worry. Also, if the string\n //is an HTML document, only the part inside the body tag is returned.\n if (content) {\n content = content.replace(xmlRegExp, \"\");\n var matches = content.match(bodyRegExp);\n if (matches) {\n content = matches[1];\n }\n } else {\n content = \"\";\n }\n return content;\n },\n\n jsEscape: function (content) {\n return content.replace(/(['\\\\])/g, '\\\\$1')\n .replace(/[\\f]/g, \"\\\\f\")\n .replace(/[\\b]/g, \"\\\\b\")\n .replace(/[\\n]/g, \"\\\\n\")\n .replace(/[\\t]/g, \"\\\\t\")\n .replace(/[\\r]/g, \"\\\\r\")\n .replace(/[\\u2028]/g, \"\\\\u2028\")\n .replace(/[\\u2029]/g, \"\\\\u2029\");\n },\n\n createXhr: masterConfig.createXhr || function () {\n //Would love to dump the ActiveX crap in here. Need IE 6 to die first.\n var xhr, i, progId;\n if (typeof XMLHttpRequest !== \"undefined\") {\n return new XMLHttpRequest();\n } else if (typeof ActiveXObject !== \"undefined\") {\n for (i = 0; i < 3; i += 1) {\n progId = progIds[i];\n try {\n xhr = new ActiveXObject(progId);\n } catch (e) {}\n\n if (xhr) {\n progIds = [progId]; // so faster next time\n break;\n }\n }\n }\n\n return xhr;\n },\n\n /**\n * Parses a resource name into its component parts. Resource names\n * look like: module/name.ext!strip, where the !strip part is\n * optional.\n * @param {String} name the resource name\n * @returns {Object} with properties \"moduleName\", \"ext\" and \"strip\"\n * where strip is a boolean.\n */\n parseName: function (name) {\n var modName, ext, temp,\n strip = false,\n index = name.indexOf(\".\"),\n isRelative = name.indexOf('./') === 0 ||\n name.indexOf('../') === 0;\n\n if (index !== -1 && (!isRelative || index > 1)) {\n modName = name.substring(0, index);\n ext = name.substring(index + 1, name.length);\n } else {\n modName = name;\n }\n\n temp = ext || modName;\n index = temp.indexOf(\"!\");\n if (index !== -1) {\n //Pull off the strip arg.\n strip = temp.substring(index + 1) === \"strip\";\n temp = temp.substring(0, index);\n if (ext) {\n ext = temp;\n } else {\n modName = temp;\n }\n }\n\n return {\n moduleName: modName,\n ext: ext,\n strip: strip\n };\n },\n\n xdRegExp: /^((\\w+)\\:)?\\/\\/([^\\/\\\\]+)/,\n\n /**\n * Is an URL on another domain. Only works for browser use, returns\n * false in non-browser environments. Only used to know if an\n * optimized .js version of a text resource should be loaded\n * instead.\n * @param {String} url\n * @returns Boolean\n */\n useXhr: function (url, protocol, hostname, port) {\n var uProtocol, uHostName, uPort,\n match = text.xdRegExp.exec(url);\n if (!match) {\n return true;\n }\n uProtocol = match[2];\n uHostName = match[3];\n\n uHostName = uHostName.split(':');\n uPort = uHostName[1];\n uHostName = uHostName[0];\n\n return (!uProtocol || uProtocol === protocol) &&\n (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) &&\n ((!uPort && !uHostName) || uPort === port);\n },\n\n finishLoad: function (name, strip, content, onLoad) {\n content = strip ? text.strip(content) : content;\n if (masterConfig.isBuild) {\n buildMap[name] = content;\n }\n onLoad(content);\n },\n\n load: function (name, req, onLoad, config) {\n //Name has format: some.module.filext!strip\n //The strip part is optional.\n //if strip is present, then that means only get the string contents\n //inside a body tag in an HTML string. For XML/SVG content it means\n //removing the declarations so the content can be inserted\n //into the current doc without problems.\n\n // Do not bother with the work if a build and text will\n // not be inlined.\n if (config.isBuild && !config.inlineText) {\n onLoad();\n return;\n }\n\n masterConfig.isBuild = config.isBuild;\n\n var parsed = text.parseName(name),\n nonStripName = parsed.moduleName +\n (parsed.ext ? '.' + parsed.ext : ''),\n url = req.toUrl(nonStripName),\n useXhr = (masterConfig.useXhr) ||\n text.useXhr;\n\n // Do not load if it is an empty: url\n if (url.indexOf('empty:') === 0) {\n onLoad();\n return;\n }\n\n //Load the text. Use XHR if possible and in a browser.\n if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) {\n text.get(url, function (content) {\n text.finishLoad(name, parsed.strip, content, onLoad);\n }, function (err) {\n if (onLoad.error) {\n onLoad.error(err);\n }\n });\n } else {\n //Need to fetch the resource across domains. Assume\n //the resource has been optimized into a JS module. Fetch\n //by the module name + extension, but do not include the\n //!strip part to avoid file system issues.\n req([nonStripName], function (content) {\n text.finishLoad(parsed.moduleName + '.' + parsed.ext,\n parsed.strip, content, onLoad);\n });\n }\n },\n\n write: function (pluginName, moduleName, write, config) {\n if (buildMap.hasOwnProperty(moduleName)) {\n var content = text.jsEscape(buildMap[moduleName]);\n write.asModule(pluginName + \"!\" + moduleName,\n \"define(function () { return '\" +\n content +\n \"';});\\n\");\n }\n },\n\n writeFile: function (pluginName, moduleName, req, write, config) {\n var parsed = text.parseName(moduleName),\n extPart = parsed.ext ? '.' + parsed.ext : '',\n nonStripName = parsed.moduleName + extPart,\n //Use a '.js' file name so that it indicates it is a\n //script that can be loaded across domains.\n fileName = req.toUrl(parsed.moduleName + extPart) + '.js';\n\n //Leverage own load() method to load plugin value, but only\n //write out values that do not have the strip argument,\n //to avoid any potential issues with ! in file names.\n text.load(nonStripName, req, function (value) {\n //Use own write() method to construct full module value.\n //But need to create shell that translates writeFile's\n //write() to the right interface.\n var textWrite = function (contents) {\n return write(fileName, contents);\n };\n textWrite.asModule = function (moduleName, contents) {\n return write.asModule(moduleName, fileName, contents);\n };\n\n text.write(pluginName, nonStripName, textWrite, config);\n }, config);\n }\n };\n\n if (masterConfig.env === 'node' || (!masterConfig.env &&\n typeof process !== \"undefined\" &&\n process.versions &&\n !!process.versions.node &&\n !process.versions['node-webkit'])) {\n //Using special require.nodeRequire, something added by r.js.\n fs = require.nodeRequire('fs');\n\n text.get = function (url, callback, errback) {\n try {\n var file = fs.readFileSync(url, 'utf8');\n //Remove BOM (Byte Mark Order) from utf8 files if it is there.\n if (file.indexOf('\\uFEFF') === 0) {\n file = file.substring(1);\n }\n callback(file);\n } catch (e) {\n errback(e);\n }\n };\n } else if (masterConfig.env === 'xhr' || (!masterConfig.env &&\n text.createXhr())) {\n text.get = function (url, callback, errback, headers) {\n var xhr = text.createXhr(), header;\n xhr.open('GET', url, true);\n\n //Allow plugins direct access to xhr headers\n if (headers) {\n for (header in headers) {\n if (headers.hasOwnProperty(header)) {\n xhr.setRequestHeader(header.toLowerCase(), headers[header]);\n }\n }\n }\n\n //Allow overrides specified in config\n if (masterConfig.onXhr) {\n masterConfig.onXhr(xhr, url);\n }\n\n xhr.onreadystatechange = function (evt) {\n var status, err;\n //Do not explicitly handle errors, those should be\n //visible via console output in the browser.\n if (xhr.readyState === 4) {\n status = xhr.status;\n if (status > 399 && status < 600) {\n //An http 4xx or 5xx error. Signal an error.\n err = new Error(url + ' HTTP status: ' + status);\n err.xhr = xhr;\n errback(err);\n } else {\n callback(xhr.responseText);\n }\n\n if (masterConfig.onXhrComplete) {\n masterConfig.onXhrComplete(xhr, url);\n }\n }\n };\n xhr.send(null);\n };\n } else if (masterConfig.env === 'rhino' || (!masterConfig.env &&\n typeof Packages !== 'undefined' && typeof java !== 'undefined')) {\n //Why Java, why is this so awkward?\n text.get = function (url, callback) {\n var stringBuffer, line,\n encoding = \"utf-8\",\n file = new java.io.File(url),\n lineSeparator = java.lang.System.getProperty(\"line.separator\"),\n input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),\n content = '';\n try {\n stringBuffer = new java.lang.StringBuffer();\n line = input.readLine();\n\n // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324\n // http://www.unicode.org/faq/utf_bom.html\n\n // Note that when we use utf-8, the BOM should appear as \"EF BB BF\", but it doesn't due to this bug in the JDK:\n // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058\n if (line && line.length() && line.charAt(0) === 0xfeff) {\n // Eat the BOM, since we've already found the encoding on this file,\n // and we plan to concatenating this buffer with others; the BOM should\n // only appear at the top of a file.\n line = line.substring(1);\n }\n\n if (line !== null) {\n stringBuffer.append(line);\n }\n\n while ((line = input.readLine()) !== null) {\n stringBuffer.append(lineSeparator);\n stringBuffer.append(line);\n }\n //Make sure we return a JavaScript string and not a Java string.\n content = String(stringBuffer.toString()); //String\n } finally {\n input.close();\n }\n callback(content);\n };\n } else if (masterConfig.env === 'xpconnect' || (!masterConfig.env &&\n typeof Components !== 'undefined' && Components.classes &&\n Components.interfaces)) {\n //Avert your gaze!\n Cc = Components.classes,\n Ci = Components.interfaces;\n Components.utils['import']('resource://gre/modules/FileUtils.jsm');\n xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc);\n\n text.get = function (url, callback) {\n var inStream, convertStream, fileObj,\n readData = {};\n\n if (xpcIsWindows) {\n url = url.replace(/\\//g, '\\\\');\n }\n\n fileObj = new FileUtils.File(url);\n\n //XPCOM, you so crazy\n try {\n inStream = Cc['@mozilla.org/network/file-input-stream;1']\n .createInstance(Ci.nsIFileInputStream);\n inStream.init(fileObj, 1, 0, false);\n\n convertStream = Cc['@mozilla.org/intl/converter-input-stream;1']\n .createInstance(Ci.nsIConverterInputStream);\n convertStream.init(inStream, \"utf-8\", inStream.available(),\n Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);\n\n convertStream.readString(inStream.available(), readData);\n convertStream.close();\n inStream.close();\n callback(readData.value);\n } catch (e) {\n throw new Error((fileObj && fileObj.path || '') + ': ' + e);\n }\n };\n }\n return text;\n});\n\n", "\ndefine('text!tpl/search.html',[],function () { return '

search

\\n
\\n \" value=\"\" placeholder=\"<%=placeholder%>\" aria-label=\"search reference\">\\n \\n
\\n\\n';});\n\n", "\ndefine('text!tpl/search_suggestion.html',[],function () { return '

\" class=\"search-suggestion\">\\n\\n <%=name%>\\n\\n \\n <% if (final) { %>\\n constant\\n <% } else if (itemtype) { %>\\n <%=itemtype%> \\n <% } %>\\n\\n <% if (className) { %>\\n in <%=className%>\\n <% } %>\\n\\n <% if (typeof is_constructor !== \\'undefined\\' && is_constructor) { %>\\n constructor\\n <% } %>\\n \\n\\n

';});\n\n", - "/*!\n * typeahead.js 0.10.2\n * https://github.com/twitter/typeahead.js\n * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT\n */\ndefine('typeahead',[], function() {\n\n//(function($) {\n\n\n var _ = {\n isMsie: function() {\n return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\\d+(.\\d+)?)/i)[2] : false;\n },\n isBlankString: function(str) {\n return !str || /^\\s*$/.test(str);\n },\n escapeRegExChars: function(str) {\n return str.replace(/[\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|]/g, \"\\\\$&\");\n },\n isString: function(obj) {\n return typeof obj === \"string\";\n },\n isNumber: function(obj) {\n return typeof obj === \"number\";\n },\n isArray: $.isArray,\n isFunction: $.isFunction,\n isObject: $.isPlainObject,\n isUndefined: function(obj) {\n return typeof obj === \"undefined\";\n },\n bind: $.proxy,\n each: function(collection, cb) {\n $.each(collection, reverseArgs);\n function reverseArgs(index, value) {\n return cb(value, index);\n }\n },\n map: $.map,\n filter: $.grep,\n every: function(obj, test) {\n var result = true;\n if (!obj) {\n return result;\n }\n $.each(obj, function(key, val) {\n if (!(result = test.call(null, val, key, obj))) {\n return false;\n }\n });\n return !!result;\n },\n some: function(obj, test) {\n var result = false;\n if (!obj) {\n return result;\n }\n $.each(obj, function(key, val) {\n if (result = test.call(null, val, key, obj)) {\n return false;\n }\n });\n return !!result;\n },\n mixin: $.extend,\n getUniqueId: function() {\n var counter = 0;\n return function() {\n return counter++;\n };\n }(),\n templatify: function templatify(obj) {\n return $.isFunction(obj) ? obj : template;\n function template() {\n return String(obj);\n }\n },\n defer: function(fn) {\n setTimeout(fn, 0);\n },\n debounce: function(func, wait, immediate) {\n var timeout, result;\n return function() {\n var context = this, args = arguments, later, callNow;\n later = function() {\n timeout = null;\n if (!immediate) {\n result = func.apply(context, args);\n }\n };\n callNow = immediate && !timeout;\n clearTimeout(timeout);\n timeout = setTimeout(later, wait);\n if (callNow) {\n result = func.apply(context, args);\n }\n return result;\n };\n },\n throttle: function(func, wait) {\n var context, args, timeout, result, previous, later;\n previous = 0;\n later = function() {\n previous = new Date();\n timeout = null;\n result = func.apply(context, args);\n };\n return function() {\n var now = new Date(), remaining = wait - (now - previous);\n context = this;\n args = arguments;\n if (remaining <= 0) {\n clearTimeout(timeout);\n timeout = null;\n previous = now;\n result = func.apply(context, args);\n } else if (!timeout) {\n timeout = setTimeout(later, remaining);\n }\n return result;\n };\n },\n noop: function() {}\n };\n var VERSION = \"0.10.2\";\n var tokenizers = function(root) {\n return {\n nonword: nonword,\n whitespace: whitespace,\n obj: {\n nonword: getObjTokenizer(nonword),\n whitespace: getObjTokenizer(whitespace)\n }\n };\n function whitespace(s) {\n return s.split(/\\s+/);\n }\n function nonword(s) {\n return s.split(/\\W+/);\n }\n function getObjTokenizer(tokenizer) {\n return function setKey(key) {\n return function tokenize(o) {\n return tokenizer(o[key]);\n };\n };\n }\n }();\n var LruCache = function() {\n function LruCache(maxSize) {\n this.maxSize = maxSize || 100;\n this.size = 0;\n this.hash = {};\n this.list = new List();\n }\n _.mixin(LruCache.prototype, {\n set: function set(key, val) {\n var tailItem = this.list.tail, node;\n if (this.size >= this.maxSize) {\n this.list.remove(tailItem);\n delete this.hash[tailItem.key];\n }\n if (node = this.hash[key]) {\n node.val = val;\n this.list.moveToFront(node);\n } else {\n node = new Node(key, val);\n this.list.add(node);\n this.hash[key] = node;\n this.size++;\n }\n },\n get: function get(key) {\n var node = this.hash[key];\n if (node) {\n this.list.moveToFront(node);\n return node.val;\n }\n }\n });\n function List() {\n this.head = this.tail = null;\n }\n _.mixin(List.prototype, {\n add: function add(node) {\n if (this.head) {\n node.next = this.head;\n this.head.prev = node;\n }\n this.head = node;\n this.tail = this.tail || node;\n },\n remove: function remove(node) {\n node.prev ? node.prev.next = node.next : this.head = node.next;\n node.next ? node.next.prev = node.prev : this.tail = node.prev;\n },\n moveToFront: function(node) {\n this.remove(node);\n this.add(node);\n }\n });\n function Node(key, val) {\n this.key = key;\n this.val = val;\n this.prev = this.next = null;\n }\n return LruCache;\n }();\n var PersistentStorage = function() {\n var ls, methods;\n try {\n ls = window.localStorage;\n ls.setItem(\"~~~\", \"!\");\n ls.removeItem(\"~~~\");\n } catch (err) {\n ls = null;\n }\n function PersistentStorage(namespace) {\n this.prefix = [ \"__\", namespace, \"__\" ].join(\"\");\n this.ttlKey = \"__ttl__\";\n this.keyMatcher = new RegExp(\"^\" + this.prefix);\n }\n if (ls && window.JSON) {\n methods = {\n _prefix: function(key) {\n return this.prefix + key;\n },\n _ttlKey: function(key) {\n return this._prefix(key) + this.ttlKey;\n },\n get: function(key) {\n if (this.isExpired(key)) {\n this.remove(key);\n }\n return decode(ls.getItem(this._prefix(key)));\n },\n set: function(key, val, ttl) {\n if (_.isNumber(ttl)) {\n ls.setItem(this._ttlKey(key), encode(now() + ttl));\n } else {\n ls.removeItem(this._ttlKey(key));\n }\n return ls.setItem(this._prefix(key), encode(val));\n },\n remove: function(key) {\n ls.removeItem(this._ttlKey(key));\n ls.removeItem(this._prefix(key));\n return this;\n },\n clear: function() {\n var i, key, keys = [], len = ls.length;\n for (i = 0; i < len; i++) {\n if ((key = ls.key(i)).match(this.keyMatcher)) {\n keys.push(key.replace(this.keyMatcher, \"\"));\n }\n }\n for (i = keys.length; i--; ) {\n this.remove(keys[i]);\n }\n return this;\n },\n isExpired: function(key) {\n var ttl = decode(ls.getItem(this._ttlKey(key)));\n return _.isNumber(ttl) && now() > ttl ? true : false;\n }\n };\n } else {\n methods = {\n get: _.noop,\n set: _.noop,\n remove: _.noop,\n clear: _.noop,\n isExpired: _.noop\n };\n }\n _.mixin(PersistentStorage.prototype, methods);\n return PersistentStorage;\n function now() {\n return new Date().getTime();\n }\n function encode(val) {\n return JSON.stringify(_.isUndefined(val) ? null : val);\n }\n function decode(val) {\n return JSON.parse(val);\n }\n }();\n var Transport = function() {\n var pendingRequestsCount = 0, pendingRequests = {}, maxPendingRequests = 6, requestCache = new LruCache(10);\n function Transport(o) {\n o = o || {};\n this._send = o.transport ? callbackToDeferred(o.transport) : $.ajax;\n this._get = o.rateLimiter ? o.rateLimiter(this._get) : this._get;\n }\n Transport.setMaxPendingRequests = function setMaxPendingRequests(num) {\n maxPendingRequests = num;\n };\n Transport.resetCache = function clearCache() {\n requestCache = new LruCache(10);\n };\n _.mixin(Transport.prototype, {\n _get: function(url, o, cb) {\n var that = this, jqXhr;\n if (jqXhr = pendingRequests[url]) {\n jqXhr.done(done).fail(fail);\n } else if (pendingRequestsCount < maxPendingRequests) {\n pendingRequestsCount++;\n pendingRequests[url] = this._send(url, o).done(done).fail(fail).always(always);\n } else {\n this.onDeckRequestArgs = [].slice.call(arguments, 0);\n }\n function done(resp) {\n cb && cb(null, resp);\n requestCache.set(url, resp);\n }\n function fail() {\n cb && cb(true);\n }\n function always() {\n pendingRequestsCount--;\n delete pendingRequests[url];\n if (that.onDeckRequestArgs) {\n that._get.apply(that, that.onDeckRequestArgs);\n that.onDeckRequestArgs = null;\n }\n }\n },\n get: function(url, o, cb) {\n var resp;\n if (_.isFunction(o)) {\n cb = o;\n o = {};\n }\n if (resp = requestCache.get(url)) {\n _.defer(function() {\n cb && cb(null, resp);\n });\n } else {\n this._get(url, o, cb);\n }\n return !!resp;\n }\n });\n return Transport;\n function callbackToDeferred(fn) {\n return function customSendWrapper(url, o) {\n var deferred = $.Deferred();\n fn(url, o, onSuccess, onError);\n return deferred;\n function onSuccess(resp) {\n _.defer(function() {\n deferred.resolve(resp);\n });\n }\n function onError(err) {\n _.defer(function() {\n deferred.reject(err);\n });\n }\n };\n }\n }();\n var SearchIndex = function() {\n function SearchIndex(o) {\n o = o || {};\n if (!o.datumTokenizer || !o.queryTokenizer) {\n $.error(\"datumTokenizer and queryTokenizer are both required\");\n }\n this.datumTokenizer = o.datumTokenizer;\n this.queryTokenizer = o.queryTokenizer;\n this.reset();\n }\n _.mixin(SearchIndex.prototype, {\n bootstrap: function bootstrap(o) {\n this.datums = o.datums;\n this.trie = o.trie;\n },\n add: function(data) {\n var that = this;\n data = _.isArray(data) ? data : [ data ];\n _.each(data, function(datum) {\n var id, tokens;\n id = that.datums.push(datum) - 1;\n tokens = normalizeTokens(that.datumTokenizer(datum));\n _.each(tokens, function(token) {\n var node, chars, ch;\n node = that.trie;\n chars = token.split(\"\");\n while (ch = chars.shift()) {\n node = node.children[ch] || (node.children[ch] = newNode());\n node.ids.push(id);\n }\n });\n });\n },\n get: function get(query) {\n var that = this, tokens, matches;\n tokens = normalizeTokens(this.queryTokenizer(query));\n _.each(tokens, function(token) {\n var node, chars, ch, ids;\n if (matches && matches.length === 0) {\n return false;\n }\n node = that.trie;\n chars = token.split(\"\");\n while (node && (ch = chars.shift())) {\n node = node.children[ch];\n }\n if (node && chars.length === 0) {\n ids = node.ids.slice(0);\n matches = matches ? getIntersection(matches, ids) : ids;\n } else {\n matches = [];\n return false;\n }\n });\n return matches ? _.map(unique(matches), function(id) {\n return that.datums[id];\n }) : [];\n },\n reset: function reset() {\n this.datums = [];\n this.trie = newNode();\n },\n serialize: function serialize() {\n return {\n datums: this.datums,\n trie: this.trie\n };\n }\n });\n return SearchIndex;\n function normalizeTokens(tokens) {\n tokens = _.filter(tokens, function(token) {\n return !!token;\n });\n tokens = _.map(tokens, function(token) {\n return token.toLowerCase();\n });\n return tokens;\n }\n function newNode() {\n return {\n ids: [],\n children: {}\n };\n }\n function unique(array) {\n var seen = {}, uniques = [];\n for (var i = 0; i < array.length; i++) {\n if (!seen[array[i]]) {\n seen[array[i]] = true;\n uniques.push(array[i]);\n }\n }\n return uniques;\n }\n function getIntersection(arrayA, arrayB) {\n var ai = 0, bi = 0, intersection = [];\n arrayA = arrayA.sort(compare);\n arrayB = arrayB.sort(compare);\n while (ai < arrayA.length && bi < arrayB.length) {\n if (arrayA[ai] < arrayB[bi]) {\n ai++;\n } else if (arrayA[ai] > arrayB[bi]) {\n bi++;\n } else {\n intersection.push(arrayA[ai]);\n ai++;\n bi++;\n }\n }\n return intersection;\n function compare(a, b) {\n return a - b;\n }\n }\n }();\n var oParser = function() {\n return {\n local: getLocal,\n prefetch: getPrefetch,\n remote: getRemote\n };\n function getLocal(o) {\n return o.local || null;\n }\n function getPrefetch(o) {\n var prefetch, defaults;\n defaults = {\n url: null,\n thumbprint: \"\",\n ttl: 24 * 60 * 60 * 1e3,\n filter: null,\n ajax: {}\n };\n if (prefetch = o.prefetch || null) {\n prefetch = _.isString(prefetch) ? {\n url: prefetch\n } : prefetch;\n prefetch = _.mixin(defaults, prefetch);\n prefetch.thumbprint = VERSION + prefetch.thumbprint;\n prefetch.ajax.type = prefetch.ajax.type || \"GET\";\n prefetch.ajax.dataType = prefetch.ajax.dataType || \"json\";\n !prefetch.url && $.error(\"prefetch requires url to be set\");\n }\n return prefetch;\n }\n function getRemote(o) {\n var remote, defaults;\n defaults = {\n url: null,\n wildcard: \"%QUERY\",\n replace: null,\n rateLimitBy: \"debounce\",\n rateLimitWait: 300,\n send: null,\n filter: null,\n ajax: {}\n };\n if (remote = o.remote || null) {\n remote = _.isString(remote) ? {\n url: remote\n } : remote;\n remote = _.mixin(defaults, remote);\n remote.rateLimiter = /^throttle$/i.test(remote.rateLimitBy) ? byThrottle(remote.rateLimitWait) : byDebounce(remote.rateLimitWait);\n remote.ajax.type = remote.ajax.type || \"GET\";\n remote.ajax.dataType = remote.ajax.dataType || \"json\";\n delete remote.rateLimitBy;\n delete remote.rateLimitWait;\n !remote.url && $.error(\"remote requires url to be set\");\n }\n return remote;\n function byDebounce(wait) {\n return function(fn) {\n return _.debounce(fn, wait);\n };\n }\n function byThrottle(wait) {\n return function(fn) {\n return _.throttle(fn, wait);\n };\n }\n }\n }();\n (function(root) {\n var old, keys;\n old = root.Bloodhound;\n keys = {\n data: \"data\",\n protocol: \"protocol\",\n thumbprint: \"thumbprint\"\n };\n root.Bloodhound = Bloodhound;\n function Bloodhound(o) {\n if (!o || !o.local && !o.prefetch && !o.remote) {\n $.error(\"one of local, prefetch, or remote is required\");\n }\n this.limit = o.limit || 5;\n this.sorter = getSorter(o.sorter);\n this.dupDetector = o.dupDetector || ignoreDuplicates;\n this.local = oParser.local(o);\n this.prefetch = oParser.prefetch(o);\n this.remote = oParser.remote(o);\n this.cacheKey = this.prefetch ? this.prefetch.cacheKey || this.prefetch.url : null;\n this.index = new SearchIndex({\n datumTokenizer: o.datumTokenizer,\n queryTokenizer: o.queryTokenizer\n });\n this.storage = this.cacheKey ? new PersistentStorage(this.cacheKey) : null;\n }\n Bloodhound.noConflict = function noConflict() {\n root.Bloodhound = old;\n return Bloodhound;\n };\n Bloodhound.tokenizers = tokenizers;\n _.mixin(Bloodhound.prototype, {\n _loadPrefetch: function loadPrefetch(o) {\n var that = this, serialized, deferred;\n if (serialized = this._readFromStorage(o.thumbprint)) {\n this.index.bootstrap(serialized);\n deferred = $.Deferred().resolve();\n } else {\n deferred = $.ajax(o.url, o.ajax).done(handlePrefetchResponse);\n }\n return deferred;\n function handlePrefetchResponse(resp) {\n that.clear();\n that.add(o.filter ? o.filter(resp) : resp);\n that._saveToStorage(that.index.serialize(), o.thumbprint, o.ttl);\n }\n },\n _getFromRemote: function getFromRemote(query, cb) {\n var that = this, url, uriEncodedQuery;\n query = query || \"\";\n uriEncodedQuery = encodeURIComponent(query);\n url = this.remote.replace ? this.remote.replace(this.remote.url, query) : this.remote.url.replace(this.remote.wildcard, uriEncodedQuery);\n return this.transport.get(url, this.remote.ajax, handleRemoteResponse);\n function handleRemoteResponse(err, resp) {\n err ? cb([]) : cb(that.remote.filter ? that.remote.filter(resp) : resp);\n }\n },\n _saveToStorage: function saveToStorage(data, thumbprint, ttl) {\n if (this.storage) {\n this.storage.set(keys.data, data, ttl);\n this.storage.set(keys.protocol, location.protocol, ttl);\n this.storage.set(keys.thumbprint, thumbprint, ttl);\n }\n },\n _readFromStorage: function readFromStorage(thumbprint) {\n var stored = {}, isExpired;\n if (this.storage) {\n stored.data = this.storage.get(keys.data);\n stored.protocol = this.storage.get(keys.protocol);\n stored.thumbprint = this.storage.get(keys.thumbprint);\n }\n isExpired = stored.thumbprint !== thumbprint || stored.protocol !== location.protocol;\n return stored.data && !isExpired ? stored.data : null;\n },\n _initialize: function initialize() {\n var that = this, local = this.local, deferred;\n deferred = this.prefetch ? this._loadPrefetch(this.prefetch) : $.Deferred().resolve();\n local && deferred.done(addLocalToIndex);\n this.transport = this.remote ? new Transport(this.remote) : null;\n return this.initPromise = deferred.promise();\n function addLocalToIndex() {\n that.add(_.isFunction(local) ? local() : local);\n }\n },\n initialize: function initialize(force) {\n return !this.initPromise || force ? this._initialize() : this.initPromise;\n },\n add: function add(data) {\n this.index.add(data);\n },\n get: function get(query, cb) {\n var that = this, matches = [], cacheHit = false;\n matches = this.index.get(query);\n matches = this.sorter(matches).slice(0, this.limit);\n if (matches.length < this.limit && this.transport) {\n cacheHit = this._getFromRemote(query, returnRemoteMatches);\n }\n if (!cacheHit) {\n (matches.length > 0 || !this.transport) && cb && cb(matches);\n }\n function returnRemoteMatches(remoteMatches) {\n var matchesWithBackfill = matches.slice(0);\n _.each(remoteMatches, function(remoteMatch) {\n var isDuplicate;\n isDuplicate = _.some(matchesWithBackfill, function(match) {\n return that.dupDetector(remoteMatch, match);\n });\n !isDuplicate && matchesWithBackfill.push(remoteMatch);\n return matchesWithBackfill.length < that.limit;\n });\n cb && cb(that.sorter(matchesWithBackfill));\n }\n },\n clear: function clear() {\n this.index.reset();\n },\n clearPrefetchCache: function clearPrefetchCache() {\n this.storage && this.storage.clear();\n },\n clearRemoteCache: function clearRemoteCache() {\n this.transport && Transport.resetCache();\n },\n ttAdapter: function ttAdapter() {\n return _.bind(this.get, this);\n }\n });\n return Bloodhound;\n function getSorter(sortFn) {\n return _.isFunction(sortFn) ? sort : noSort;\n function sort(array) {\n return array.sort(sortFn);\n }\n function noSort(array) {\n return array;\n }\n }\n function ignoreDuplicates() {\n return false;\n }\n })(this);\n var html = {\n wrapper: '',\n dropdown: '',\n dataset: '
',\n suggestions: '',\n suggestion: '
'\n };\n var css = {\n wrapper: {\n position: \"relative\",\n display: \"inline-block\"\n },\n hint: {\n position: \"absolute\",\n top: \"0\",\n left: \"0\",\n borderColor: \"transparent\",\n boxShadow: \"none\"\n },\n input: {\n position: \"relative\",\n verticalAlign: \"top\",\n backgroundColor: \"transparent\"\n },\n inputWithNoHint: {\n position: \"relative\",\n verticalAlign: \"top\"\n },\n dropdown: {\n position: \"absolute\",\n top: \"100%\",\n left: \"0\",\n zIndex: \"100\",\n display: \"none\"\n },\n suggestions: {\n display: \"block\"\n },\n suggestion: {\n whiteSpace: \"nowrap\",\n cursor: \"pointer\"\n },\n suggestionChild: {\n whiteSpace: \"normal\"\n },\n ltr: {\n left: \"0\",\n right: \"auto\"\n },\n rtl: {\n left: \"auto\",\n right: \" 0\"\n }\n };\n if (_.isMsie()) {\n _.mixin(css.input, {\n backgroundImage: \"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)\"\n });\n }\n if (_.isMsie() && _.isMsie() <= 7) {\n _.mixin(css.input, {\n marginTop: \"-1px\"\n });\n }\n var EventBus = function() {\n var namespace = \"typeahead:\";\n function EventBus(o) {\n if (!o || !o.el) {\n $.error(\"EventBus initialized without el\");\n }\n this.$el = $(o.el);\n }\n _.mixin(EventBus.prototype, {\n trigger: function(type) {\n var args = [].slice.call(arguments, 1);\n this.$el.trigger(namespace + type, args);\n }\n });\n return EventBus;\n }();\n var EventEmitter = function() {\n var splitter = /\\s+/, nextTick = getNextTick();\n return {\n onSync: onSync,\n onAsync: onAsync,\n off: off,\n trigger: trigger\n };\n function on(method, types, cb, context) {\n var type;\n if (!cb) {\n return this;\n }\n types = types.split(splitter);\n cb = context ? bindContext(cb, context) : cb;\n this._callbacks = this._callbacks || {};\n while (type = types.shift()) {\n this._callbacks[type] = this._callbacks[type] || {\n sync: [],\n async: []\n };\n this._callbacks[type][method].push(cb);\n }\n return this;\n }\n function onAsync(types, cb, context) {\n return on.call(this, \"async\", types, cb, context);\n }\n function onSync(types, cb, context) {\n return on.call(this, \"sync\", types, cb, context);\n }\n function off(types) {\n var type;\n if (!this._callbacks) {\n return this;\n }\n types = types.split(splitter);\n while (type = types.shift()) {\n delete this._callbacks[type];\n }\n return this;\n }\n function trigger(types) {\n var type, callbacks, args, syncFlush, asyncFlush;\n if (!this._callbacks) {\n return this;\n }\n types = types.split(splitter);\n args = [].slice.call(arguments, 1);\n while ((type = types.shift()) && (callbacks = this._callbacks[type])) {\n syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args));\n asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args));\n syncFlush() && nextTick(asyncFlush);\n }\n return this;\n }\n function getFlush(callbacks, context, args) {\n return flush;\n function flush() {\n var cancelled;\n for (var i = 0; !cancelled && i < callbacks.length; i += 1) {\n cancelled = callbacks[i].apply(context, args) === false;\n }\n return !cancelled;\n }\n }\n function getNextTick() {\n var nextTickFn;\n if (window.setImmediate) {\n nextTickFn = function nextTickSetImmediate(fn) {\n setImmediate(function() {\n fn();\n });\n };\n } else {\n nextTickFn = function nextTickSetTimeout(fn) {\n setTimeout(function() {\n fn();\n }, 0);\n };\n }\n return nextTickFn;\n }\n function bindContext(fn, context) {\n return fn.bind ? fn.bind(context) : function() {\n fn.apply(context, [].slice.call(arguments, 0));\n };\n }\n }();\n var highlight = function(doc) {\n var defaults = {\n node: null,\n pattern: null,\n tagName: \"strong\",\n className: null,\n wordsOnly: false,\n caseSensitive: false\n };\n return function hightlight(o) {\n var regex;\n o = _.mixin({}, defaults, o);\n if (!o.node || !o.pattern) {\n return;\n }\n o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ];\n regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly);\n traverse(o.node, hightlightTextNode);\n function hightlightTextNode(textNode) {\n var match, patternNode;\n if (match = regex.exec(textNode.data)) {\n wrapperNode = doc.createElement(o.tagName);\n o.className && (wrapperNode.className = o.className);\n patternNode = textNode.splitText(match.index);\n patternNode.splitText(match[0].length);\n wrapperNode.appendChild(patternNode.cloneNode(true));\n textNode.parentNode.replaceChild(wrapperNode, patternNode);\n }\n return !!match;\n }\n function traverse(el, hightlightTextNode) {\n var childNode, TEXT_NODE_TYPE = 3;\n for (var i = 0; i < el.childNodes.length; i++) {\n childNode = el.childNodes[i];\n if (childNode.nodeType === TEXT_NODE_TYPE) {\n i += hightlightTextNode(childNode) ? 1 : 0;\n } else {\n traverse(childNode, hightlightTextNode);\n }\n }\n }\n };\n function getRegex(patterns, caseSensitive, wordsOnly) {\n var escapedPatterns = [], regexStr;\n for (var i = 0; i < patterns.length; i++) {\n escapedPatterns.push(_.escapeRegExChars(patterns[i]));\n }\n regexStr = wordsOnly ? \"\\\\b(\" + escapedPatterns.join(\"|\") + \")\\\\b\" : \"(\" + escapedPatterns.join(\"|\") + \")\";\n return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, \"i\");\n }\n }(window.document);\n var Input = function() {\n var specialKeyCodeMap;\n specialKeyCodeMap = {\n 9: \"tab\",\n 27: \"esc\",\n 37: \"left\",\n 39: \"right\",\n 13: \"enter\",\n 38: \"up\",\n 40: \"down\"\n };\n function Input(o) {\n var that = this, onBlur, onFocus, onKeydown, onInput;\n o = o || {};\n if (!o.input) {\n $.error(\"input is missing\");\n }\n onBlur = _.bind(this._onBlur, this);\n onFocus = _.bind(this._onFocus, this);\n onKeydown = _.bind(this._onKeydown, this);\n onInput = _.bind(this._onInput, this);\n this.$hint = $(o.hint);\n this.$input = $(o.input).on(\"blur.tt\", onBlur).on(\"focus.tt\", onFocus).on(\"keydown.tt\", onKeydown);\n if (this.$hint.length === 0) {\n this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop;\n }\n if (!_.isMsie()) {\n this.$input.on(\"input.tt\", onInput);\n } else {\n this.$input.on(\"keydown.tt keypress.tt cut.tt paste.tt\", function($e) {\n if (specialKeyCodeMap[$e.which || $e.keyCode]) {\n return;\n }\n _.defer(_.bind(that._onInput, that, $e));\n });\n }\n this.query = this.$input.val();\n this.$overflowHelper = buildOverflowHelper(this.$input);\n }\n Input.normalizeQuery = function(str) {\n return (str || \"\").replace(/^\\s*/g, \"\").replace(/\\s{2,}/g, \" \");\n };\n _.mixin(Input.prototype, EventEmitter, {\n _onBlur: function onBlur() {\n this.resetInputValue();\n this.trigger(\"blurred\");\n },\n _onFocus: function onFocus() {\n this.trigger(\"focused\");\n },\n _onKeydown: function onKeydown($e) {\n var keyName = specialKeyCodeMap[$e.which || $e.keyCode];\n this._managePreventDefault(keyName, $e);\n if (keyName && this._shouldTrigger(keyName, $e)) {\n this.trigger(keyName + \"Keyed\", $e);\n }\n },\n _onInput: function onInput() {\n this._checkInputValue();\n },\n _managePreventDefault: function managePreventDefault(keyName, $e) {\n var preventDefault, hintValue, inputValue;\n switch (keyName) {\n case \"tab\":\n hintValue = this.getHint();\n inputValue = this.getInputValue();\n preventDefault = hintValue && hintValue !== inputValue && !withModifier($e);\n break;\n\n case \"up\":\n case \"down\":\n preventDefault = !withModifier($e);\n break;\n\n default:\n preventDefault = false;\n }\n preventDefault && $e.preventDefault();\n },\n _shouldTrigger: function shouldTrigger(keyName, $e) {\n var trigger;\n switch (keyName) {\n case \"tab\":\n trigger = !withModifier($e);\n break;\n\n default:\n trigger = true;\n }\n return trigger;\n },\n _checkInputValue: function checkInputValue() {\n var inputValue, areEquivalent, hasDifferentWhitespace;\n inputValue = this.getInputValue();\n areEquivalent = areQueriesEquivalent(inputValue, this.query);\n hasDifferentWhitespace = areEquivalent ? this.query.length !== inputValue.length : false;\n if (!areEquivalent) {\n this.trigger(\"queryChanged\", this.query = inputValue);\n } else if (hasDifferentWhitespace) {\n this.trigger(\"whitespaceChanged\", this.query);\n }\n },\n focus: function focus() {\n this.$input.focus();\n },\n blur: function blur() {\n this.$input.blur();\n },\n getQuery: function getQuery() {\n return this.query;\n },\n setQuery: function setQuery(query) {\n this.query = query;\n },\n getInputValue: function getInputValue() {\n return this.$input.val();\n },\n setInputValue: function setInputValue(value, silent) {\n this.$input.val(value);\n silent ? this.clearHint() : this._checkInputValue();\n },\n resetInputValue: function resetInputValue() {\n this.setInputValue(this.query, true);\n },\n getHint: function getHint() {\n return this.$hint.val();\n },\n setHint: function setHint(value) {\n this.$hint.val(value);\n },\n clearHint: function clearHint() {\n this.setHint(\"\");\n },\n clearHintIfInvalid: function clearHintIfInvalid() {\n var val, hint, valIsPrefixOfHint, isValid;\n val = this.getInputValue();\n hint = this.getHint();\n valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0;\n isValid = val !== \"\" && valIsPrefixOfHint && !this.hasOverflow();\n !isValid && this.clearHint();\n },\n getLanguageDirection: function getLanguageDirection() {\n return (this.$input.css(\"direction\") || \"ltr\").toLowerCase();\n },\n hasOverflow: function hasOverflow() {\n var constraint = this.$input.width() - 2;\n this.$overflowHelper.text(this.getInputValue());\n return this.$overflowHelper.width() >= constraint;\n },\n isCursorAtEnd: function() {\n var valueLength, selectionStart, range;\n valueLength = this.$input.val().length;\n selectionStart = this.$input[0].selectionStart;\n if (_.isNumber(selectionStart)) {\n return selectionStart === valueLength;\n } else if (document.selection) {\n range = document.selection.createRange();\n range.moveStart(\"character\", -valueLength);\n return valueLength === range.text.length;\n }\n return true;\n },\n destroy: function destroy() {\n this.$hint.off(\".tt\");\n this.$input.off(\".tt\");\n this.$hint = this.$input = this.$overflowHelper = null;\n }\n });\n return Input;\n function buildOverflowHelper($input) {\n return $('
').css({\n                position: \"absolute\",\n                visibility: \"hidden\",\n                whiteSpace: \"pre\",\n                fontFamily: $input.css(\"font-family\"),\n                fontSize: $input.css(\"font-size\"),\n                fontStyle: $input.css(\"font-style\"),\n                fontVariant: $input.css(\"font-variant\"),\n                fontWeight: $input.css(\"font-weight\"),\n                wordSpacing: $input.css(\"word-spacing\"),\n                letterSpacing: $input.css(\"letter-spacing\"),\n                textIndent: $input.css(\"text-indent\"),\n                textRendering: $input.css(\"text-rendering\"),\n                textTransform: $input.css(\"text-transform\")\n            }).insertAfter($input);\n        }\n        function areQueriesEquivalent(a, b) {\n            return Input.normalizeQuery(a) === Input.normalizeQuery(b);\n        }\n        function withModifier($e) {\n            return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey;\n        }\n    }();\n    var Dataset = function() {\n        var datasetKey = \"ttDataset\", valueKey = \"ttValue\", datumKey = \"ttDatum\";\n        function Dataset(o) {\n            o = o || {};\n            o.templates = o.templates || {};\n            if (!o.source) {\n                $.error(\"missing source\");\n            }\n            if (o.name && !isValidName(o.name)) {\n                $.error(\"invalid dataset name: \" + o.name);\n            }\n            this.query = null;\n            this.highlight = !!o.highlight;\n            this.name = o.name || _.getUniqueId();\n            this.source = o.source;\n            this.displayFn = getDisplayFn(o.display || o.displayKey);\n            this.templates = getTemplates(o.templates, this.displayFn);\n            this.$el = $(html.dataset.replace(\"%CLASS%\", this.name));\n        }\n        Dataset.extractDatasetName = function extractDatasetName(el) {\n            return $(el).data(datasetKey);\n        };\n        Dataset.extractValue = function extractDatum(el) {\n            return $(el).data(valueKey);\n        };\n        Dataset.extractDatum = function extractDatum(el) {\n            return $(el).data(datumKey);\n        };\n        _.mixin(Dataset.prototype, EventEmitter, {\n            _render: function render(query, suggestions) {\n                if (!this.$el) {\n                    return;\n                }\n                var that = this, hasSuggestions;\n                this.$el.empty();\n                hasSuggestions = suggestions && suggestions.length;\n                if (!hasSuggestions && this.templates.empty) {\n                    this.$el.html(getEmptyHtml()).prepend(that.templates.header ? getHeaderHtml() : null).append(that.templates.footer ? getFooterHtml() : null);\n                } else if (hasSuggestions) {\n                    this.$el.html(getSuggestionsHtml()).prepend(that.templates.header ? getHeaderHtml() : null).append(that.templates.footer ? getFooterHtml() : null);\n                }\n                this.trigger(\"rendered\");\n                function getEmptyHtml() {\n                    return that.templates.empty({\n                        query: query,\n                        isEmpty: true\n                    });\n                }\n                function getSuggestionsHtml() {\n                    var $suggestions, nodes;\n                    $suggestions = $(html.suggestions).css(css.suggestions);\n                    nodes = _.map(suggestions, getSuggestionNode);\n                    $suggestions.append.apply($suggestions, nodes);\n                    that.highlight && highlight({\n                        node: $suggestions[0],\n                        pattern: query\n                    });\n                    return $suggestions;\n                    function getSuggestionNode(suggestion) {\n                        var $el;\n                        $el = $(html.suggestion).append(that.templates.suggestion(suggestion)).data(datasetKey, that.name).data(valueKey, that.displayFn(suggestion)).data(datumKey, suggestion);\n                        $el.children().each(function() {\n                            $(this).css(css.suggestionChild);\n                        });\n                        return $el;\n                    }\n                }\n                function getHeaderHtml() {\n                    return that.templates.header({\n                        query: query,\n                        isEmpty: !hasSuggestions\n                    });\n                }\n                function getFooterHtml() {\n                    return that.templates.footer({\n                        query: query,\n                        isEmpty: !hasSuggestions\n                    });\n                }\n            },\n            getRoot: function getRoot() {\n                return this.$el;\n            },\n            update: function update(query) {\n                var that = this;\n                this.query = query;\n                this.canceled = false;\n                this.source(query, render);\n                function render(suggestions) {\n                    if (!that.canceled && query === that.query) {\n                        that._render(query, suggestions);\n                    }\n                }\n            },\n            cancel: function cancel() {\n                this.canceled = true;\n            },\n            clear: function clear() {\n                this.cancel();\n                this.$el.empty();\n                this.trigger(\"rendered\");\n            },\n            isEmpty: function isEmpty() {\n                return this.$el.is(\":empty\");\n            },\n            destroy: function destroy() {\n                this.$el = null;\n            }\n        });\n        return Dataset;\n        function getDisplayFn(display) {\n            display = display || \"value\";\n            return _.isFunction(display) ? display : displayFn;\n            function displayFn(obj) {\n                return obj[display];\n            }\n        }\n        function getTemplates(templates, displayFn) {\n            return {\n                empty: templates.empty && _.templatify(templates.empty),\n                header: templates.header && _.templatify(templates.header),\n                footer: templates.footer && _.templatify(templates.footer),\n                suggestion: templates.suggestion || suggestionTemplate\n            };\n            function suggestionTemplate(context) {\n                return \"

\" + displayFn(context) + \"

\";\n }\n }\n function isValidName(str) {\n return /^[_a-zA-Z0-9-]+$/.test(str);\n }\n }();\n var Dropdown = function() {\n function Dropdown(o) {\n var that = this, onSuggestionClick, onSuggestionMouseEnter, onSuggestionMouseLeave;\n o = o || {};\n if (!o.menu) {\n $.error(\"menu is required\");\n }\n this.isOpen = false;\n this.isEmpty = true;\n this.datasets = _.map(o.datasets, initializeDataset);\n onSuggestionClick = _.bind(this._onSuggestionClick, this);\n onSuggestionMouseEnter = _.bind(this._onSuggestionMouseEnter, this);\n onSuggestionMouseLeave = _.bind(this._onSuggestionMouseLeave, this);\n this.$menu = $(o.menu).on(\"click.tt\", \".tt-suggestion\", onSuggestionClick).on(\"mouseenter.tt\", \".tt-suggestion\", onSuggestionMouseEnter).on(\"mouseleave.tt\", \".tt-suggestion\", onSuggestionMouseLeave);\n _.each(this.datasets, function(dataset) {\n that.$menu.append(dataset.getRoot());\n dataset.onSync(\"rendered\", that._onRendered, that);\n });\n }\n _.mixin(Dropdown.prototype, EventEmitter, {\n _onSuggestionClick: function onSuggestionClick($e) {\n this.trigger(\"suggestionClicked\", $($e.currentTarget));\n },\n _onSuggestionMouseEnter: function onSuggestionMouseEnter($e) {\n this._removeCursor();\n this._setCursor($($e.currentTarget), true);\n },\n _onSuggestionMouseLeave: function onSuggestionMouseLeave() {\n this._removeCursor();\n },\n _onRendered: function onRendered() {\n this.isEmpty = _.every(this.datasets, isDatasetEmpty);\n this.isEmpty ? this._hide() : this.isOpen && this._show();\n this.trigger(\"datasetRendered\");\n function isDatasetEmpty(dataset) {\n return dataset.isEmpty();\n }\n },\n _hide: function() {\n this.$menu.hide();\n },\n _show: function() {\n this.$menu.css(\"display\", \"block\");\n },\n _getSuggestions: function getSuggestions() {\n return this.$menu.find(\".tt-suggestion\");\n },\n _getCursor: function getCursor() {\n return this.$menu.find(\".tt-cursor\").first();\n },\n _setCursor: function setCursor($el, silent) {\n $el.first().addClass(\"tt-cursor\");\n !silent && this.trigger(\"cursorMoved\");\n },\n _removeCursor: function removeCursor() {\n this._getCursor().removeClass(\"tt-cursor\");\n },\n _moveCursor: function moveCursor(increment) {\n var $suggestions, $oldCursor, newCursorIndex, $newCursor;\n if (!this.isOpen) {\n return;\n }\n $oldCursor = this._getCursor();\n $suggestions = this._getSuggestions();\n this._removeCursor();\n newCursorIndex = $suggestions.index($oldCursor) + increment;\n newCursorIndex = (newCursorIndex + 1) % ($suggestions.length + 1) - 1;\n if (newCursorIndex === -1) {\n this.trigger(\"cursorRemoved\");\n return;\n } else if (newCursorIndex < -1) {\n newCursorIndex = $suggestions.length - 1;\n }\n this._setCursor($newCursor = $suggestions.eq(newCursorIndex));\n this._ensureVisible($newCursor);\n },\n _ensureVisible: function ensureVisible($el) {\n var elTop, elBottom, menuScrollTop, menuHeight;\n elTop = $el.position().top;\n elBottom = elTop + $el.outerHeight(true);\n menuScrollTop = this.$menu.scrollTop();\n menuHeight = this.$menu.height() + parseInt(this.$menu.css(\"paddingTop\"), 10) + parseInt(this.$menu.css(\"paddingBottom\"), 10);\n if (elTop < 0) {\n this.$menu.scrollTop(menuScrollTop + elTop);\n } else if (menuHeight < elBottom) {\n this.$menu.scrollTop(menuScrollTop + (elBottom - menuHeight));\n }\n },\n close: function close() {\n if (this.isOpen) {\n this.isOpen = false;\n this._removeCursor();\n this._hide();\n this.trigger(\"closed\");\n }\n },\n open: function open() {\n if (!this.isOpen) {\n this.isOpen = true;\n !this.isEmpty && this._show();\n this.trigger(\"opened\");\n }\n },\n setLanguageDirection: function setLanguageDirection(dir) {\n this.$menu.css(dir === \"ltr\" ? css.ltr : css.rtl);\n },\n moveCursorUp: function moveCursorUp() {\n this._moveCursor(-1);\n },\n moveCursorDown: function moveCursorDown() {\n this._moveCursor(+1);\n },\n getDatumForSuggestion: function getDatumForSuggestion($el) {\n var datum = null;\n if ($el.length) {\n datum = {\n raw: Dataset.extractDatum($el),\n value: Dataset.extractValue($el),\n datasetName: Dataset.extractDatasetName($el)\n };\n }\n return datum;\n },\n getDatumForCursor: function getDatumForCursor() {\n return this.getDatumForSuggestion(this._getCursor().first());\n },\n getDatumForTopSuggestion: function getDatumForTopSuggestion() {\n return this.getDatumForSuggestion(this._getSuggestions().first());\n },\n update: function update(query) {\n _.each(this.datasets, updateDataset);\n function updateDataset(dataset) {\n dataset.update(query);\n }\n },\n empty: function empty() {\n _.each(this.datasets, clearDataset);\n this.isEmpty = true;\n function clearDataset(dataset) {\n dataset.clear();\n }\n },\n isVisible: function isVisible() {\n return this.isOpen && !this.isEmpty;\n },\n destroy: function destroy() {\n this.$menu.off(\".tt\");\n this.$menu = null;\n _.each(this.datasets, destroyDataset);\n function destroyDataset(dataset) {\n dataset.destroy();\n }\n }\n });\n return Dropdown;\n function initializeDataset(oDataset) {\n return new Dataset(oDataset);\n }\n }();\n var Typeahead = function() {\n var attrsKey = \"ttAttrs\";\n function Typeahead(o) {\n var $menu, $input, $hint;\n o = o || {};\n if (!o.input) {\n $.error(\"missing input\");\n }\n this.isActivated = false;\n this.autoselect = !!o.autoselect;\n this.minLength = _.isNumber(o.minLength) ? o.minLength : 1;\n this.$node = buildDomStructure(o.input, o.withHint);\n $menu = this.$node.find(\".tt-dropdown-menu\");\n $input = this.$node.find(\".tt-input\");\n $hint = this.$node.find(\".tt-hint\");\n $input.on(\"blur.tt\", function($e) {\n var active, isActive, hasActive;\n active = document.activeElement;\n isActive = $menu.is(active);\n hasActive = $menu.has(active).length > 0;\n if (_.isMsie() && (isActive || hasActive)) {\n $e.preventDefault();\n $e.stopImmediatePropagation();\n _.defer(function() {\n $input.focus();\n });\n }\n });\n $menu.on(\"mousedown.tt\", function($e) {\n $e.preventDefault();\n });\n this.eventBus = o.eventBus || new EventBus({\n el: $input\n });\n this.dropdown = new Dropdown({\n menu: $menu,\n datasets: o.datasets\n }).onSync(\"suggestionClicked\", this._onSuggestionClicked, this).onSync(\"cursorMoved\", this._onCursorMoved, this).onSync(\"cursorRemoved\", this._onCursorRemoved, this).onSync(\"opened\", this._onOpened, this).onSync(\"closed\", this._onClosed, this).onAsync(\"datasetRendered\", this._onDatasetRendered, this);\n this.input = new Input({\n input: $input,\n hint: $hint\n }).onSync(\"focused\", this._onFocused, this).onSync(\"blurred\", this._onBlurred, this).onSync(\"enterKeyed\", this._onEnterKeyed, this).onSync(\"tabKeyed\", this._onTabKeyed, this).onSync(\"escKeyed\", this._onEscKeyed, this).onSync(\"upKeyed\", this._onUpKeyed, this).onSync(\"downKeyed\", this._onDownKeyed, this).onSync(\"leftKeyed\", this._onLeftKeyed, this).onSync(\"rightKeyed\", this._onRightKeyed, this).onSync(\"queryChanged\", this._onQueryChanged, this).onSync(\"whitespaceChanged\", this._onWhitespaceChanged, this);\n this._setLanguageDirection();\n }\n _.mixin(Typeahead.prototype, {\n _onSuggestionClicked: function onSuggestionClicked(type, $el) {\n var datum;\n if (datum = this.dropdown.getDatumForSuggestion($el)) {\n this._select(datum);\n }\n },\n _onCursorMoved: function onCursorMoved() {\n var datum = this.dropdown.getDatumForCursor();\n this.input.setInputValue(datum.value, true);\n this.eventBus.trigger(\"cursorchanged\", datum.raw, datum.datasetName);\n },\n _onCursorRemoved: function onCursorRemoved() {\n this.input.resetInputValue();\n this._updateHint();\n },\n _onDatasetRendered: function onDatasetRendered() {\n this._updateHint();\n },\n _onOpened: function onOpened() {\n this._updateHint();\n this.eventBus.trigger(\"opened\");\n },\n _onClosed: function onClosed() {\n this.input.clearHint();\n this.eventBus.trigger(\"closed\");\n },\n _onFocused: function onFocused() {\n this.isActivated = true;\n this.dropdown.open();\n },\n _onBlurred: function onBlurred() {\n this.isActivated = false;\n this.dropdown.empty();\n this.dropdown.close();\n this.setVal(\"\", true); //LM\n },\n _onEnterKeyed: function onEnterKeyed(type, $e) {\n var cursorDatum, topSuggestionDatum;\n cursorDatum = this.dropdown.getDatumForCursor();\n topSuggestionDatum = this.dropdown.getDatumForTopSuggestion();\n if (cursorDatum) {\n this._select(cursorDatum);\n $e.preventDefault();\n } else if (this.autoselect && topSuggestionDatum) {\n this._select(topSuggestionDatum);\n $e.preventDefault();\n }\n },\n _onTabKeyed: function onTabKeyed(type, $e) {\n var datum;\n if (datum = this.dropdown.getDatumForCursor()) {\n this._select(datum);\n $e.preventDefault();\n } else {\n this._autocomplete(true);\n }\n },\n _onEscKeyed: function onEscKeyed() {\n this.dropdown.close();\n this.input.resetInputValue();\n },\n _onUpKeyed: function onUpKeyed() {\n var query = this.input.getQuery();\n this.dropdown.isEmpty && query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.moveCursorUp();\n this.dropdown.open();\n },\n _onDownKeyed: function onDownKeyed() {\n var query = this.input.getQuery();\n this.dropdown.isEmpty && query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.moveCursorDown();\n this.dropdown.open();\n },\n _onLeftKeyed: function onLeftKeyed() {\n this.dir === \"rtl\" && this._autocomplete();\n },\n _onRightKeyed: function onRightKeyed() {\n this.dir === \"ltr\" && this._autocomplete();\n },\n _onQueryChanged: function onQueryChanged(e, query) {\n this.input.clearHintIfInvalid();\n query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.empty();\n this.dropdown.open();\n this._setLanguageDirection();\n },\n _onWhitespaceChanged: function onWhitespaceChanged() {\n this._updateHint();\n this.dropdown.open();\n },\n _setLanguageDirection: function setLanguageDirection() {\n var dir;\n if (this.dir !== (dir = this.input.getLanguageDirection())) {\n this.dir = dir;\n this.$node.css(\"direction\", dir);\n this.dropdown.setLanguageDirection(dir);\n }\n },\n _updateHint: function updateHint() {\n var datum, val, query, escapedQuery, frontMatchRegEx, match;\n datum = this.dropdown.getDatumForTopSuggestion();\n if (datum && this.dropdown.isVisible() && !this.input.hasOverflow()) {\n val = this.input.getInputValue();\n query = Input.normalizeQuery(val);\n escapedQuery = _.escapeRegExChars(query);\n frontMatchRegEx = new RegExp(\"^(?:\" + escapedQuery + \")(.+$)\", \"i\");\n match = frontMatchRegEx.exec(datum.value);\n match ? this.input.setHint(val + match[1]) : this.input.clearHint();\n } else {\n this.input.clearHint();\n }\n },\n _autocomplete: function autocomplete(laxCursor) {\n var hint, query, isCursorAtEnd, datum;\n hint = this.input.getHint();\n query = this.input.getQuery();\n isCursorAtEnd = laxCursor || this.input.isCursorAtEnd();\n if (hint && query !== hint && isCursorAtEnd) {\n datum = this.dropdown.getDatumForTopSuggestion();\n datum && this.input.setInputValue(datum.value);\n this.eventBus.trigger(\"autocompleted\", datum.raw, datum.datasetName);\n }\n },\n _select: function select(datum) {\n this.input.setQuery(datum.value);\n this.input.setInputValue(datum.value, true);\n this._setLanguageDirection();\n this.eventBus.trigger(\"selected\", datum.raw, datum.datasetName);\n this.dropdown.close();\n _.defer(_.bind(this.dropdown.empty, this.dropdown));\n },\n open: function open() {\n this.dropdown.open();\n },\n close: function close() {\n this.dropdown.close();\n },\n setVal: function setVal(val) {\n if (this.isActivated) {\n this.input.setInputValue(val);\n } else {\n this.input.setQuery(val);\n this.input.setInputValue(val, true);\n }\n this._setLanguageDirection();\n },\n getVal: function getVal() {\n return this.input.getQuery();\n },\n destroy: function destroy() {\n this.input.destroy();\n this.dropdown.destroy();\n destroyDomStructure(this.$node);\n this.$node = null;\n }\n });\n return Typeahead;\n function buildDomStructure(input, withHint) {\n var $input, $wrapper, $dropdown, $hint;\n $input = $(input);\n $wrapper = $(html.wrapper).css(css.wrapper);\n $dropdown = $(html.dropdown).css(css.dropdown);\n $hint = $input.clone().css(css.hint).css(getBackgroundStyles($input));\n $hint.val(\"\").removeData().addClass(\"tt-hint\").removeAttr(\"id name placeholder\").prop(\"disabled\", true).attr({\n autocomplete: \"off\",\n spellcheck: \"false\"\n });\n $input.data(attrsKey, {\n dir: $input.attr(\"dir\"),\n autocomplete: $input.attr(\"autocomplete\"),\n spellcheck: $input.attr(\"spellcheck\"),\n style: $input.attr(\"style\")\n });\n $input.addClass(\"tt-input\").attr({\n autocomplete: \"off\",\n spellcheck: false\n }).css(withHint ? css.input : css.inputWithNoHint);\n try {\n !$input.attr(\"dir\") && $input.attr(\"dir\", \"auto\");\n } catch (e) {}\n return $input.wrap($wrapper).parent().prepend(withHint ? $hint : null).append($dropdown);\n }\n function getBackgroundStyles($el) {\n return {\n backgroundAttachment: $el.css(\"background-attachment\"),\n backgroundClip: $el.css(\"background-clip\"),\n backgroundColor: $el.css(\"background-color\"),\n backgroundImage: $el.css(\"background-image\"),\n backgroundOrigin: $el.css(\"background-origin\"),\n backgroundPosition: $el.css(\"background-position\"),\n backgroundRepeat: $el.css(\"background-repeat\"),\n backgroundSize: $el.css(\"background-size\")\n };\n }\n function destroyDomStructure($node) {\n var $input = $node.find(\".tt-input\");\n _.each($input.data(attrsKey), function(val, key) {\n _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val);\n });\n $input.detach().removeData(attrsKey).removeClass(\"tt-input\").insertAfter($node);\n $node.remove();\n }\n }();\n (function() {\n var old, typeaheadKey, methods;\n old = $.fn.typeahead;\n typeaheadKey = \"ttTypeahead\";\n methods = {\n initialize: function initialize(o, datasets) {\n datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1);\n o = o || {};\n return this.each(attach);\n function attach() {\n var $input = $(this), eventBus, typeahead;\n _.each(datasets, function(d) {\n d.highlight = !!o.highlight;\n });\n typeahead = new Typeahead({\n input: $input,\n eventBus: eventBus = new EventBus({\n el: $input\n }),\n withHint: _.isUndefined(o.hint) ? true : !!o.hint,\n minLength: o.minLength,\n autoselect: o.autoselect,\n datasets: datasets\n });\n $input.data(typeaheadKey, typeahead);\n }\n },\n open: function open() {\n return this.each(openTypeahead);\n function openTypeahead() {\n var $input = $(this), typeahead;\n if (typeahead = $input.data(typeaheadKey)) {\n typeahead.open();\n }\n }\n },\n close: function close() {\n return this.each(closeTypeahead);\n function closeTypeahead() {\n var $input = $(this), typeahead;\n if (typeahead = $input.data(typeaheadKey)) {\n typeahead.close();\n }\n }\n },\n val: function val(newVal) {\n return !arguments.length ? getVal(this.first()) : this.each(setVal);\n function setVal() {\n var $input = $(this), typeahead;\n if (typeahead = $input.data(typeaheadKey)) {\n typeahead.setVal(newVal);\n }\n }\n function getVal($input) {\n var typeahead, query;\n if (typeahead = $input.data(typeaheadKey)) {\n query = typeahead.getVal();\n }\n return query;\n }\n },\n destroy: function destroy() {\n return this.each(unattach);\n function unattach() {\n var $input = $(this), typeahead;\n if (typeahead = $input.data(typeaheadKey)) {\n typeahead.destroy();\n $input.removeData(typeaheadKey);\n }\n }\n }\n };\n $.fn.typeahead = function(method) {\n if (methods[method]) {\n return methods[method].apply(this, [].slice.call(arguments, 1));\n } else {\n return methods.initialize.apply(this, arguments);\n }\n };\n $.fn.typeahead.noConflict = function noConflict() {\n $.fn.typeahead = old;\n return this;\n };\n })();\n \n \n \n//})(window.jQuery);\n\n\n});\n", + "/*!\n * typeahead.js 0.10.2\n * https://github.com/twitter/typeahead.js\n * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT\n */\ndefine('typeahead',[], function() {\n\n//(function($) {\n\n\n var _ = {\n isMsie: function() {\n return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\\d+(.\\d+)?)/i)[2] : false;\n },\n isBlankString: function(str) {\n return !str || /^\\s*$/.test(str);\n },\n escapeRegExChars: function(str) {\n return str.replace(/[\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|]/g, \"\\\\$&\");\n },\n isString: function(obj) {\n return typeof obj === \"string\";\n },\n isNumber: function(obj) {\n return typeof obj === \"number\";\n },\n isArray: $.isArray,\n isFunction: $.isFunction,\n isObject: $.isPlainObject,\n isUndefined: function(obj) {\n return typeof obj === \"undefined\";\n },\n bind: $.proxy,\n each: function(collection, cb) {\n $.each(collection, reverseArgs);\n function reverseArgs(index, value) {\n return cb(value, index);\n }\n },\n map: $.map,\n filter: $.grep,\n every: function(obj, test) {\n var result = true;\n if (!obj) {\n return result;\n }\n $.each(obj, function(key, val) {\n if (!(result = test.call(null, val, key, obj))) {\n return false;\n }\n });\n return !!result;\n },\n some: function(obj, test) {\n var result = false;\n if (!obj) {\n return result;\n }\n $.each(obj, function(key, val) {\n if (result = test.call(null, val, key, obj)) {\n return false;\n }\n });\n return !!result;\n },\n mixin: $.extend,\n getUniqueId: function() {\n var counter = 0;\n return function() {\n return counter++;\n };\n }(),\n templatify: function templatify(obj) {\n return $.isFunction(obj) ? obj : template;\n function template() {\n return String(obj);\n }\n },\n defer: function(fn) {\n setTimeout(fn, 0);\n },\n debounce: function(func, wait, immediate) {\n var timeout, result;\n return function() {\n var context = this, args = arguments, later, callNow;\n later = function() {\n timeout = null;\n if (!immediate) {\n result = func.apply(context, args);\n }\n };\n callNow = immediate && !timeout;\n clearTimeout(timeout);\n timeout = setTimeout(later, wait);\n if (callNow) {\n result = func.apply(context, args);\n }\n return result;\n };\n },\n throttle: function(func, wait) {\n var context, args, timeout, result, previous, later;\n previous = 0;\n later = function() {\n previous = new Date();\n timeout = null;\n result = func.apply(context, args);\n };\n return function() {\n var now = new Date(), remaining = wait - (now - previous);\n context = this;\n args = arguments;\n if (remaining <= 0) {\n clearTimeout(timeout);\n timeout = null;\n previous = now;\n result = func.apply(context, args);\n } else if (!timeout) {\n timeout = setTimeout(later, remaining);\n }\n return result;\n };\n },\n noop: function() {}\n };\n var VERSION = \"0.10.2\";\n var tokenizers = function(root) {\n return {\n nonword: nonword,\n whitespace: whitespace,\n obj: {\n nonword: getObjTokenizer(nonword),\n whitespace: getObjTokenizer(whitespace)\n }\n };\n function whitespace(s) {\n return s.split(/\\s+/);\n }\n function nonword(s) {\n return s.split(/\\W+/);\n }\n function getObjTokenizer(tokenizer) {\n return function setKey(key) {\n return function tokenize(o) {\n return tokenizer(o[key]);\n };\n };\n }\n }();\n var LruCache = function() {\n function LruCache(maxSize) {\n this.maxSize = maxSize || 100;\n this.size = 0;\n this.hash = {};\n this.list = new List();\n }\n _.mixin(LruCache.prototype, {\n set: function set(key, val) {\n var tailItem = this.list.tail, node;\n if (this.size >= this.maxSize) {\n this.list.remove(tailItem);\n delete this.hash[tailItem.key];\n }\n if (node = this.hash[key]) {\n node.val = val;\n this.list.moveToFront(node);\n } else {\n node = new Node(key, val);\n this.list.add(node);\n this.hash[key] = node;\n this.size++;\n }\n },\n get: function get(key) {\n var node = this.hash[key];\n if (node) {\n this.list.moveToFront(node);\n return node.val;\n }\n }\n });\n function List() {\n this.head = this.tail = null;\n }\n _.mixin(List.prototype, {\n add: function add(node) {\n if (this.head) {\n node.next = this.head;\n this.head.prev = node;\n }\n this.head = node;\n this.tail = this.tail || node;\n },\n remove: function remove(node) {\n node.prev ? node.prev.next = node.next : this.head = node.next;\n node.next ? node.next.prev = node.prev : this.tail = node.prev;\n },\n moveToFront: function(node) {\n this.remove(node);\n this.add(node);\n }\n });\n function Node(key, val) {\n this.key = key;\n this.val = val;\n this.prev = this.next = null;\n }\n return LruCache;\n }();\n var PersistentStorage = function() {\n var ls, methods;\n try {\n ls = window.localStorage;\n ls.setItem(\"~~~\", \"!\");\n ls.removeItem(\"~~~\");\n } catch (err) {\n ls = null;\n }\n function PersistentStorage(namespace) {\n this.prefix = [ \"__\", namespace, \"__\" ].join(\"\");\n this.ttlKey = \"__ttl__\";\n this.keyMatcher = new RegExp(\"^\" + this.prefix);\n }\n if (ls && window.JSON) {\n methods = {\n _prefix: function(key) {\n return this.prefix + key;\n },\n _ttlKey: function(key) {\n return this._prefix(key) + this.ttlKey;\n },\n get: function(key) {\n if (this.isExpired(key)) {\n this.remove(key);\n }\n return decode(ls.getItem(this._prefix(key)));\n },\n set: function(key, val, ttl) {\n if (_.isNumber(ttl)) {\n ls.setItem(this._ttlKey(key), encode(now() + ttl));\n } else {\n ls.removeItem(this._ttlKey(key));\n }\n return ls.setItem(this._prefix(key), encode(val));\n },\n remove: function(key) {\n ls.removeItem(this._ttlKey(key));\n ls.removeItem(this._prefix(key));\n return this;\n },\n clear: function() {\n var i, key, keys = [], len = ls.length;\n for (i = 0; i < len; i++) {\n if ((key = ls.key(i)).match(this.keyMatcher)) {\n keys.push(key.replace(this.keyMatcher, \"\"));\n }\n }\n for (i = keys.length; i--; ) {\n this.remove(keys[i]);\n }\n return this;\n },\n isExpired: function(key) {\n var ttl = decode(ls.getItem(this._ttlKey(key)));\n return _.isNumber(ttl) && now() > ttl ? true : false;\n }\n };\n } else {\n methods = {\n get: _.noop,\n set: _.noop,\n remove: _.noop,\n clear: _.noop,\n isExpired: _.noop\n };\n }\n _.mixin(PersistentStorage.prototype, methods);\n return PersistentStorage;\n function now() {\n return new Date().getTime();\n }\n function encode(val) {\n return JSON.stringify(_.isUndefined(val) ? null : val);\n }\n function decode(val) {\n return JSON.parse(val);\n }\n }();\n var Transport = function() {\n var pendingRequestsCount = 0, pendingRequests = {}, maxPendingRequests = 6, requestCache = new LruCache(10);\n function Transport(o) {\n o = o || {};\n this._send = o.transport ? callbackToDeferred(o.transport) : $.ajax;\n this._get = o.rateLimiter ? o.rateLimiter(this._get) : this._get;\n }\n Transport.setMaxPendingRequests = function setMaxPendingRequests(num) {\n maxPendingRequests = num;\n };\n Transport.resetCache = function clearCache() {\n requestCache = new LruCache(10);\n };\n _.mixin(Transport.prototype, {\n _get: function(url, o, cb) {\n var that = this, jqXhr;\n if (jqXhr = pendingRequests[url]) {\n jqXhr.done(done).fail(fail);\n } else if (pendingRequestsCount < maxPendingRequests) {\n pendingRequestsCount++;\n pendingRequests[url] = this._send(url, o).done(done).fail(fail).always(always);\n } else {\n this.onDeckRequestArgs = [].slice.call(arguments, 0);\n }\n function done(resp) {\n cb && cb(null, resp);\n requestCache.set(url, resp);\n }\n function fail() {\n cb && cb(true);\n }\n function always() {\n pendingRequestsCount--;\n delete pendingRequests[url];\n if (that.onDeckRequestArgs) {\n that._get.apply(that, that.onDeckRequestArgs);\n that.onDeckRequestArgs = null;\n }\n }\n },\n get: function(url, o, cb) {\n var resp;\n if (_.isFunction(o)) {\n cb = o;\n o = {};\n }\n if (resp = requestCache.get(url)) {\n _.defer(function() {\n cb && cb(null, resp);\n });\n } else {\n this._get(url, o, cb);\n }\n return !!resp;\n }\n });\n return Transport;\n function callbackToDeferred(fn) {\n return function customSendWrapper(url, o) {\n var deferred = $.Deferred();\n fn(url, o, onSuccess, onError);\n return deferred;\n function onSuccess(resp) {\n _.defer(function() {\n deferred.resolve(resp);\n });\n }\n function onError(err) {\n _.defer(function() {\n deferred.reject(err);\n });\n }\n };\n }\n }();\n var SearchIndex = function() {\n function SearchIndex(o) {\n o = o || {};\n if (!o.datumTokenizer || !o.queryTokenizer) {\n $.error(\"datumTokenizer and queryTokenizer are both required\");\n }\n this.datumTokenizer = o.datumTokenizer;\n this.queryTokenizer = o.queryTokenizer;\n this.reset();\n }\n _.mixin(SearchIndex.prototype, {\n bootstrap: function bootstrap(o) {\n this.datums = o.datums;\n this.trie = o.trie;\n },\n add: function(data) {\n var that = this;\n data = _.isArray(data) ? data : [ data ];\n _.each(data, function(datum) {\n var id, tokens;\n id = that.datums.push(datum) - 1;\n tokens = normalizeTokens(that.datumTokenizer(datum));\n _.each(tokens, function(token) {\n var node, chars, ch;\n node = that.trie;\n chars = token.split(\"\");\n while (ch = chars.shift()) {\n node = node.children[ch] || (node.children[ch] = newNode());\n node.ids.push(id);\n }\n });\n });\n },\n get: function get(query) {\n var that = this, tokens, matches;\n tokens = normalizeTokens(this.queryTokenizer(query));\n _.each(tokens, function(token) {\n var node, chars, ch, ids;\n if (matches && matches.length === 0) {\n return false;\n }\n node = that.trie;\n chars = token.split(\"\");\n while (node && (ch = chars.shift())) {\n node = node.children[ch];\n }\n if (node && chars.length === 0) {\n ids = node.ids.slice(0);\n matches = matches ? getIntersection(matches, ids) : ids;\n } else {\n matches = [];\n return false;\n }\n });\n return matches ? _.map(unique(matches), function(id) {\n return that.datums[id];\n }) : [];\n },\n reset: function reset() {\n this.datums = [];\n this.trie = newNode();\n },\n serialize: function serialize() {\n return {\n datums: this.datums,\n trie: this.trie\n };\n }\n });\n return SearchIndex;\n function normalizeTokens(tokens) {\n tokens = _.filter(tokens, function(token) {\n return !!token;\n });\n tokens = _.map(tokens, function(token) {\n return token.toLowerCase();\n });\n return tokens;\n }\n function newNode() {\n return {\n ids: [],\n children: {}\n };\n }\n function unique(array) {\n var seen = {}, uniques = [];\n for (var i = 0; i < array.length; i++) {\n if (!seen[array[i]]) {\n seen[array[i]] = true;\n uniques.push(array[i]);\n }\n }\n return uniques;\n }\n function getIntersection(arrayA, arrayB) {\n var ai = 0, bi = 0, intersection = [];\n arrayA = arrayA.sort(compare);\n arrayB = arrayB.sort(compare);\n while (ai < arrayA.length && bi < arrayB.length) {\n if (arrayA[ai] < arrayB[bi]) {\n ai++;\n } else if (arrayA[ai] > arrayB[bi]) {\n bi++;\n } else {\n intersection.push(arrayA[ai]);\n ai++;\n bi++;\n }\n }\n return intersection;\n function compare(a, b) {\n return a - b;\n }\n }\n }();\n var oParser = function() {\n return {\n local: getLocal,\n prefetch: getPrefetch,\n remote: getRemote\n };\n function getLocal(o) {\n return o.local || null;\n }\n function getPrefetch(o) {\n var prefetch, defaults;\n defaults = {\n url: null,\n thumbprint: \"\",\n ttl: 24 * 60 * 60 * 1e3,\n filter: null,\n ajax: {}\n };\n if (prefetch = o.prefetch || null) {\n prefetch = _.isString(prefetch) ? {\n url: prefetch\n } : prefetch;\n prefetch = _.mixin(defaults, prefetch);\n prefetch.thumbprint = VERSION + prefetch.thumbprint;\n prefetch.ajax.type = prefetch.ajax.type || \"GET\";\n prefetch.ajax.dataType = prefetch.ajax.dataType || \"json\";\n !prefetch.url && $.error(\"prefetch requires url to be set\");\n }\n return prefetch;\n }\n function getRemote(o) {\n var remote, defaults;\n defaults = {\n url: null,\n wildcard: \"%QUERY\",\n replace: null,\n rateLimitBy: \"debounce\",\n rateLimitWait: 300,\n send: null,\n filter: null,\n ajax: {}\n };\n if (remote = o.remote || null) {\n remote = _.isString(remote) ? {\n url: remote\n } : remote;\n remote = _.mixin(defaults, remote);\n remote.rateLimiter = /^throttle$/i.test(remote.rateLimitBy) ? byThrottle(remote.rateLimitWait) : byDebounce(remote.rateLimitWait);\n remote.ajax.type = remote.ajax.type || \"GET\";\n remote.ajax.dataType = remote.ajax.dataType || \"json\";\n delete remote.rateLimitBy;\n delete remote.rateLimitWait;\n !remote.url && $.error(\"remote requires url to be set\");\n }\n return remote;\n function byDebounce(wait) {\n return function(fn) {\n return _.debounce(fn, wait);\n };\n }\n function byThrottle(wait) {\n return function(fn) {\n return _.throttle(fn, wait);\n };\n }\n }\n }();\n (function(root) {\n var old, keys;\n old = root.Bloodhound;\n keys = {\n data: \"data\",\n protocol: \"protocol\",\n thumbprint: \"thumbprint\"\n };\n root.Bloodhound = Bloodhound;\n function Bloodhound(o) {\n if (!o || !o.local && !o.prefetch && !o.remote) {\n $.error(\"one of local, prefetch, or remote is required\");\n }\n this.limit = o.limit || 5;\n this.sorter = getSorter(o.sorter);\n this.dupDetector = o.dupDetector || ignoreDuplicates;\n this.local = oParser.local(o);\n this.prefetch = oParser.prefetch(o);\n this.remote = oParser.remote(o);\n this.cacheKey = this.prefetch ? this.prefetch.cacheKey || this.prefetch.url : null;\n this.index = new SearchIndex({\n datumTokenizer: o.datumTokenizer,\n queryTokenizer: o.queryTokenizer\n });\n this.storage = this.cacheKey ? new PersistentStorage(this.cacheKey) : null;\n }\n Bloodhound.noConflict = function noConflict() {\n root.Bloodhound = old;\n return Bloodhound;\n };\n Bloodhound.tokenizers = tokenizers;\n _.mixin(Bloodhound.prototype, {\n _loadPrefetch: function loadPrefetch(o) {\n var that = this, serialized, deferred;\n if (serialized = this._readFromStorage(o.thumbprint)) {\n this.index.bootstrap(serialized);\n deferred = $.Deferred().resolve();\n } else {\n deferred = $.ajax(o.url, o.ajax).done(handlePrefetchResponse);\n }\n return deferred;\n function handlePrefetchResponse(resp) {\n that.clear();\n that.add(o.filter ? o.filter(resp) : resp);\n that._saveToStorage(that.index.serialize(), o.thumbprint, o.ttl);\n }\n },\n _getFromRemote: function getFromRemote(query, cb) {\n var that = this, url, uriEncodedQuery;\n query = query || \"\";\n uriEncodedQuery = encodeURIComponent(query);\n url = this.remote.replace ? this.remote.replace(this.remote.url, query) : this.remote.url.replace(this.remote.wildcard, uriEncodedQuery);\n return this.transport.get(url, this.remote.ajax, handleRemoteResponse);\n function handleRemoteResponse(err, resp) {\n err ? cb([]) : cb(that.remote.filter ? that.remote.filter(resp) : resp);\n }\n },\n _saveToStorage: function saveToStorage(data, thumbprint, ttl) {\n if (this.storage) {\n this.storage.set(keys.data, data, ttl);\n this.storage.set(keys.protocol, location.protocol, ttl);\n this.storage.set(keys.thumbprint, thumbprint, ttl);\n }\n },\n _readFromStorage: function readFromStorage(thumbprint) {\n var stored = {}, isExpired;\n if (this.storage) {\n stored.data = this.storage.get(keys.data);\n stored.protocol = this.storage.get(keys.protocol);\n stored.thumbprint = this.storage.get(keys.thumbprint);\n }\n isExpired = stored.thumbprint !== thumbprint || stored.protocol !== location.protocol;\n return stored.data && !isExpired ? stored.data : null;\n },\n _initialize: function initialize() {\n var that = this, local = this.local, deferred;\n deferred = this.prefetch ? this._loadPrefetch(this.prefetch) : $.Deferred().resolve();\n local && deferred.done(addLocalToIndex);\n this.transport = this.remote ? new Transport(this.remote) : null;\n return this.initPromise = deferred.promise();\n function addLocalToIndex() {\n that.add(_.isFunction(local) ? local() : local);\n }\n },\n initialize: function initialize(force) {\n return !this.initPromise || force ? this._initialize() : this.initPromise;\n },\n add: function add(data) {\n this.index.add(data);\n },\n get: function get(query, cb) {\n var that = this, matches = [], cacheHit = false;\n matches = this.index.get(query);\n matches = this.sorter(matches).slice(0, this.limit);\n if (matches.length < this.limit && this.transport) {\n cacheHit = this._getFromRemote(query, returnRemoteMatches);\n }\n if (!cacheHit) {\n (matches.length > 0 || !this.transport) && cb && cb(matches);\n }\n function returnRemoteMatches(remoteMatches) {\n var matchesWithBackfill = matches.slice(0);\n _.each(remoteMatches, function(remoteMatch) {\n var isDuplicate;\n isDuplicate = _.some(matchesWithBackfill, function(match) {\n return that.dupDetector(remoteMatch, match);\n });\n !isDuplicate && matchesWithBackfill.push(remoteMatch);\n return matchesWithBackfill.length < that.limit;\n });\n cb && cb(that.sorter(matchesWithBackfill));\n }\n },\n clear: function clear() {\n this.index.reset();\n },\n clearPrefetchCache: function clearPrefetchCache() {\n this.storage && this.storage.clear();\n },\n clearRemoteCache: function clearRemoteCache() {\n this.transport && Transport.resetCache();\n },\n ttAdapter: function ttAdapter() {\n return _.bind(this.get, this);\n }\n });\n return Bloodhound;\n function getSorter(sortFn) {\n return _.isFunction(sortFn) ? sort : noSort;\n function sort(array) {\n return array.sort(sortFn);\n }\n function noSort(array) {\n return array;\n }\n }\n function ignoreDuplicates() {\n return false;\n }\n })(this);\n var html = {\n wrapper: '',\n dropdown: '',\n dataset: '
',\n suggestions: '',\n suggestion: '
'\n };\n var css = {\n wrapper: {\n position: \"relative\",\n display: \"inline-block\"\n },\n hint: {\n position: \"absolute\",\n top: \"0\",\n left: \"0\",\n borderColor: \"transparent\",\n boxShadow: \"none\"\n },\n input: {\n position: \"relative\",\n verticalAlign: \"top\",\n backgroundColor: \"transparent\"\n },\n inputWithNoHint: {\n position: \"relative\",\n verticalAlign: \"top\"\n },\n dropdown: {\n position: \"absolute\",\n top: \"100%\",\n left: \"0\",\n zIndex: \"100\",\n display: \"none\"\n },\n suggestions: {\n display: \"block\"\n },\n suggestion: {\n whiteSpace: \"nowrap\",\n cursor: \"pointer\"\n },\n suggestionChild: {\n whiteSpace: \"normal\"\n },\n ltr: {\n left: \"0\",\n right: \"auto\"\n },\n rtl: {\n left: \"auto\",\n right: \" 0\"\n }\n };\n if (_.isMsie()) {\n _.mixin(css.input, {\n backgroundImage: \"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)\"\n });\n }\n if (_.isMsie() && _.isMsie() <= 7) {\n _.mixin(css.input, {\n marginTop: \"-1px\"\n });\n }\n var EventBus = function() {\n var namespace = \"typeahead:\";\n function EventBus(o) {\n if (!o || !o.el) {\n $.error(\"EventBus initialized without el\");\n }\n this.$el = $(o.el);\n }\n _.mixin(EventBus.prototype, {\n trigger: function(type) {\n var args = [].slice.call(arguments, 1);\n this.$el.trigger(namespace + type, args);\n }\n });\n return EventBus;\n }();\n var EventEmitter = function() {\n var splitter = /\\s+/, nextTick = getNextTick();\n return {\n onSync: onSync,\n onAsync: onAsync,\n off: off,\n trigger: trigger\n };\n function on(method, types, cb, context) {\n var type;\n if (!cb) {\n return this;\n }\n types = types.split(splitter);\n cb = context ? bindContext(cb, context) : cb;\n this._callbacks = this._callbacks || {};\n while (type = types.shift()) {\n this._callbacks[type] = this._callbacks[type] || {\n sync: [],\n async: []\n };\n this._callbacks[type][method].push(cb);\n }\n return this;\n }\n function onAsync(types, cb, context) {\n return on.call(this, \"async\", types, cb, context);\n }\n function onSync(types, cb, context) {\n return on.call(this, \"sync\", types, cb, context);\n }\n function off(types) {\n var type;\n if (!this._callbacks) {\n return this;\n }\n types = types.split(splitter);\n while (type = types.shift()) {\n delete this._callbacks[type];\n }\n return this;\n }\n function trigger(types) {\n var type, callbacks, args, syncFlush, asyncFlush;\n if (!this._callbacks) {\n return this;\n }\n types = types.split(splitter);\n args = [].slice.call(arguments, 1);\n while ((type = types.shift()) && (callbacks = this._callbacks[type])) {\n syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args));\n asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args));\n syncFlush() && nextTick(asyncFlush);\n }\n return this;\n }\n function getFlush(callbacks, context, args) {\n return flush;\n function flush() {\n var cancelled;\n for (var i = 0; !cancelled && i < callbacks.length; i += 1) {\n cancelled = callbacks[i].apply(context, args) === false;\n }\n return !cancelled;\n }\n }\n function getNextTick() {\n var nextTickFn;\n if (window.setImmediate) {\n nextTickFn = function nextTickSetImmediate(fn) {\n setImmediate(function() {\n fn();\n });\n };\n } else {\n nextTickFn = function nextTickSetTimeout(fn) {\n setTimeout(function() {\n fn();\n }, 0);\n };\n }\n return nextTickFn;\n }\n function bindContext(fn, context) {\n return fn.bind ? fn.bind(context) : function() {\n fn.apply(context, [].slice.call(arguments, 0));\n };\n }\n }();\n var highlight = function(doc) {\n var defaults = {\n node: null,\n pattern: null,\n tagName: \"strong\",\n className: null,\n wordsOnly: false,\n caseSensitive: false\n };\n return function highlight(o) {\n var regex;\n o = _.mixin({}, defaults, o);\n if (!o.node || !o.pattern) {\n return;\n }\n o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ];\n regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly);\n traverse(o.node, highlightTextNode);\n function highlightTextNode(textNode) {\n var match, patternNode;\n if (match = regex.exec(textNode.data)) {\n wrapperNode = doc.createElement(o.tagName);\n o.className && (wrapperNode.className = o.className);\n patternNode = textNode.splitText(match.index);\n patternNode.splitText(match[0].length);\n wrapperNode.appendChild(patternNode.cloneNode(true));\n textNode.parentNode.replaceChild(wrapperNode, patternNode);\n }\n return !!match;\n }\n function traverse(el, highlightTextNode) {\n var childNode, TEXT_NODE_TYPE = 3;\n for (var i = 0; i < el.childNodes.length; i++) {\n childNode = el.childNodes[i];\n if (childNode.nodeType === TEXT_NODE_TYPE) {\n i += highlightTextNode(childNode) ? 1 : 0;\n } else {\n traverse(childNode, highlightTextNode);\n }\n }\n }\n };\n function getRegex(patterns, caseSensitive, wordsOnly) {\n var escapedPatterns = [], regexStr;\n for (var i = 0; i < patterns.length; i++) {\n escapedPatterns.push(_.escapeRegExChars(patterns[i]));\n }\n regexStr = wordsOnly ? \"\\\\b(\" + escapedPatterns.join(\"|\") + \")\\\\b\" : \"(\" + escapedPatterns.join(\"|\") + \")\";\n return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, \"i\");\n }\n }(window.document);\n var Input = function() {\n var specialKeyCodeMap;\n specialKeyCodeMap = {\n 9: \"tab\",\n 27: \"esc\",\n 37: \"left\",\n 39: \"right\",\n 13: \"enter\",\n 38: \"up\",\n 40: \"down\"\n };\n function Input(o) {\n var that = this, onBlur, onFocus, onKeydown, onInput;\n o = o || {};\n if (!o.input) {\n $.error(\"input is missing\");\n }\n onBlur = _.bind(this._onBlur, this);\n onFocus = _.bind(this._onFocus, this);\n onKeydown = _.bind(this._onKeydown, this);\n onInput = _.bind(this._onInput, this);\n this.$hint = $(o.hint);\n this.$input = $(o.input).on(\"blur.tt\", onBlur).on(\"focus.tt\", onFocus).on(\"keydown.tt\", onKeydown);\n if (this.$hint.length === 0) {\n this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop;\n }\n if (!_.isMsie()) {\n this.$input.on(\"input.tt\", onInput);\n } else {\n this.$input.on(\"keydown.tt keypress.tt cut.tt paste.tt\", function($e) {\n if (specialKeyCodeMap[$e.which || $e.keyCode]) {\n return;\n }\n _.defer(_.bind(that._onInput, that, $e));\n });\n }\n this.query = this.$input.val();\n this.$overflowHelper = buildOverflowHelper(this.$input);\n }\n Input.normalizeQuery = function(str) {\n return (str || \"\").replace(/^\\s*/g, \"\").replace(/\\s{2,}/g, \" \");\n };\n _.mixin(Input.prototype, EventEmitter, {\n _onBlur: function onBlur() {\n this.resetInputValue();\n this.trigger(\"blurred\");\n },\n _onFocus: function onFocus() {\n this.trigger(\"focused\");\n },\n _onKeydown: function onKeydown($e) {\n var keyName = specialKeyCodeMap[$e.which || $e.keyCode];\n this._managePreventDefault(keyName, $e);\n if (keyName && this._shouldTrigger(keyName, $e)) {\n this.trigger(keyName + \"Keyed\", $e);\n }\n },\n _onInput: function onInput() {\n this._checkInputValue();\n },\n _managePreventDefault: function managePreventDefault(keyName, $e) {\n var preventDefault, hintValue, inputValue;\n switch (keyName) {\n case \"tab\":\n hintValue = this.getHint();\n inputValue = this.getInputValue();\n preventDefault = hintValue && hintValue !== inputValue && !withModifier($e);\n break;\n\n case \"up\":\n case \"down\":\n preventDefault = !withModifier($e);\n break;\n\n default:\n preventDefault = false;\n }\n preventDefault && $e.preventDefault();\n },\n _shouldTrigger: function shouldTrigger(keyName, $e) {\n var trigger;\n switch (keyName) {\n case \"tab\":\n trigger = !withModifier($e);\n break;\n\n default:\n trigger = true;\n }\n return trigger;\n },\n _checkInputValue: function checkInputValue() {\n var inputValue, areEquivalent, hasDifferentWhitespace;\n inputValue = this.getInputValue();\n areEquivalent = areQueriesEquivalent(inputValue, this.query);\n hasDifferentWhitespace = areEquivalent ? this.query.length !== inputValue.length : false;\n if (!areEquivalent) {\n this.trigger(\"queryChanged\", this.query = inputValue);\n } else if (hasDifferentWhitespace) {\n this.trigger(\"whitespaceChanged\", this.query);\n }\n },\n focus: function focus() {\n this.$input.focus();\n },\n blur: function blur() {\n this.$input.blur();\n },\n getQuery: function getQuery() {\n return this.query;\n },\n setQuery: function setQuery(query) {\n this.query = query;\n },\n getInputValue: function getInputValue() {\n return this.$input.val();\n },\n setInputValue: function setInputValue(value, silent) {\n this.$input.val(value);\n silent ? this.clearHint() : this._checkInputValue();\n },\n resetInputValue: function resetInputValue() {\n this.setInputValue(this.query, true);\n },\n getHint: function getHint() {\n return this.$hint.val();\n },\n setHint: function setHint(value) {\n this.$hint.val(value);\n },\n clearHint: function clearHint() {\n this.setHint(\"\");\n },\n clearHintIfInvalid: function clearHintIfInvalid() {\n var val, hint, valIsPrefixOfHint, isValid;\n val = this.getInputValue();\n hint = this.getHint();\n valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0;\n isValid = val !== \"\" && valIsPrefixOfHint && !this.hasOverflow();\n !isValid && this.clearHint();\n },\n getLanguageDirection: function getLanguageDirection() {\n return (this.$input.css(\"direction\") || \"ltr\").toLowerCase();\n },\n hasOverflow: function hasOverflow() {\n var constraint = this.$input.width() - 2;\n this.$overflowHelper.text(this.getInputValue());\n return this.$overflowHelper.width() >= constraint;\n },\n isCursorAtEnd: function() {\n var valueLength, selectionStart, range;\n valueLength = this.$input.val().length;\n selectionStart = this.$input[0].selectionStart;\n if (_.isNumber(selectionStart)) {\n return selectionStart === valueLength;\n } else if (document.selection) {\n range = document.selection.createRange();\n range.moveStart(\"character\", -valueLength);\n return valueLength === range.text.length;\n }\n return true;\n },\n destroy: function destroy() {\n this.$hint.off(\".tt\");\n this.$input.off(\".tt\");\n this.$hint = this.$input = this.$overflowHelper = null;\n }\n });\n return Input;\n function buildOverflowHelper($input) {\n return $('
').css({\n                position: \"absolute\",\n                visibility: \"hidden\",\n                whiteSpace: \"pre\",\n                fontFamily: $input.css(\"font-family\"),\n                fontSize: $input.css(\"font-size\"),\n                fontStyle: $input.css(\"font-style\"),\n                fontVariant: $input.css(\"font-variant\"),\n                fontWeight: $input.css(\"font-weight\"),\n                wordSpacing: $input.css(\"word-spacing\"),\n                letterSpacing: $input.css(\"letter-spacing\"),\n                textIndent: $input.css(\"text-indent\"),\n                textRendering: $input.css(\"text-rendering\"),\n                textTransform: $input.css(\"text-transform\")\n            }).insertAfter($input);\n        }\n        function areQueriesEquivalent(a, b) {\n            return Input.normalizeQuery(a) === Input.normalizeQuery(b);\n        }\n        function withModifier($e) {\n            return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey;\n        }\n    }();\n    var Dataset = function() {\n        var datasetKey = \"ttDataset\", valueKey = \"ttValue\", datumKey = \"ttDatum\";\n        function Dataset(o) {\n            o = o || {};\n            o.templates = o.templates || {};\n            if (!o.source) {\n                $.error(\"missing source\");\n            }\n            if (o.name && !isValidName(o.name)) {\n                $.error(\"invalid dataset name: \" + o.name);\n            }\n            this.query = null;\n            this.highlight = !!o.highlight;\n            this.name = o.name || _.getUniqueId();\n            this.source = o.source;\n            this.displayFn = getDisplayFn(o.display || o.displayKey);\n            this.templates = getTemplates(o.templates, this.displayFn);\n            this.$el = $(html.dataset.replace(\"%CLASS%\", this.name));\n        }\n        Dataset.extractDatasetName = function extractDatasetName(el) {\n            return $(el).data(datasetKey);\n        };\n        Dataset.extractValue = function extractDatum(el) {\n            return $(el).data(valueKey);\n        };\n        Dataset.extractDatum = function extractDatum(el) {\n            return $(el).data(datumKey);\n        };\n        _.mixin(Dataset.prototype, EventEmitter, {\n            _render: function render(query, suggestions) {\n                if (!this.$el) {\n                    return;\n                }\n                var that = this, hasSuggestions;\n                this.$el.empty();\n                hasSuggestions = suggestions && suggestions.length;\n                if (!hasSuggestions && this.templates.empty) {\n                    this.$el.html(getEmptyHtml()).prepend(that.templates.header ? getHeaderHtml() : null).append(that.templates.footer ? getFooterHtml() : null);\n                } else if (hasSuggestions) {\n                    this.$el.html(getSuggestionsHtml()).prepend(that.templates.header ? getHeaderHtml() : null).append(that.templates.footer ? getFooterHtml() : null);\n                }\n                this.trigger(\"rendered\");\n                function getEmptyHtml() {\n                    return that.templates.empty({\n                        query: query,\n                        isEmpty: true\n                    });\n                }\n                function getSuggestionsHtml() {\n                    var $suggestions, nodes;\n                    $suggestions = $(html.suggestions).css(css.suggestions);\n                    nodes = _.map(suggestions, getSuggestionNode);\n                    $suggestions.append.apply($suggestions, nodes);\n                    that.highlight && highlight({\n                        node: $suggestions[0],\n                        pattern: query\n                    });\n                    return $suggestions;\n                    function getSuggestionNode(suggestion) {\n                        var $el;\n                        $el = $(html.suggestion).append(that.templates.suggestion(suggestion)).data(datasetKey, that.name).data(valueKey, that.displayFn(suggestion)).data(datumKey, suggestion);\n                        $el.children().each(function() {\n                            $(this).css(css.suggestionChild);\n                        });\n                        return $el;\n                    }\n                }\n                function getHeaderHtml() {\n                    return that.templates.header({\n                        query: query,\n                        isEmpty: !hasSuggestions\n                    });\n                }\n                function getFooterHtml() {\n                    return that.templates.footer({\n                        query: query,\n                        isEmpty: !hasSuggestions\n                    });\n                }\n            },\n            getRoot: function getRoot() {\n                return this.$el;\n            },\n            update: function update(query) {\n                var that = this;\n                this.query = query;\n                this.canceled = false;\n                this.source(query, render);\n                function render(suggestions) {\n                    if (!that.canceled && query === that.query) {\n                        that._render(query, suggestions);\n                    }\n                }\n            },\n            cancel: function cancel() {\n                this.canceled = true;\n            },\n            clear: function clear() {\n                this.cancel();\n                this.$el.empty();\n                this.trigger(\"rendered\");\n            },\n            isEmpty: function isEmpty() {\n                return this.$el.is(\":empty\");\n            },\n            destroy: function destroy() {\n                this.$el = null;\n            }\n        });\n        return Dataset;\n        function getDisplayFn(display) {\n            display = display || \"value\";\n            return _.isFunction(display) ? display : displayFn;\n            function displayFn(obj) {\n                return obj[display];\n            }\n        }\n        function getTemplates(templates, displayFn) {\n            return {\n                empty: templates.empty && _.templatify(templates.empty),\n                header: templates.header && _.templatify(templates.header),\n                footer: templates.footer && _.templatify(templates.footer),\n                suggestion: templates.suggestion || suggestionTemplate\n            };\n            function suggestionTemplate(context) {\n                return \"

\" + displayFn(context) + \"

\";\n }\n }\n function isValidName(str) {\n return /^[_a-zA-Z0-9-]+$/.test(str);\n }\n }();\n var Dropdown = function() {\n function Dropdown(o) {\n var that = this, onSuggestionClick, onSuggestionMouseEnter, onSuggestionMouseLeave;\n o = o || {};\n if (!o.menu) {\n $.error(\"menu is required\");\n }\n this.isOpen = false;\n this.isEmpty = true;\n this.datasets = _.map(o.datasets, initializeDataset);\n onSuggestionClick = _.bind(this._onSuggestionClick, this);\n onSuggestionMouseEnter = _.bind(this._onSuggestionMouseEnter, this);\n onSuggestionMouseLeave = _.bind(this._onSuggestionMouseLeave, this);\n this.$menu = $(o.menu).on(\"click.tt\", \".tt-suggestion\", onSuggestionClick).on(\"mouseenter.tt\", \".tt-suggestion\", onSuggestionMouseEnter).on(\"mouseleave.tt\", \".tt-suggestion\", onSuggestionMouseLeave);\n _.each(this.datasets, function(dataset) {\n that.$menu.append(dataset.getRoot());\n dataset.onSync(\"rendered\", that._onRendered, that);\n });\n }\n _.mixin(Dropdown.prototype, EventEmitter, {\n _onSuggestionClick: function onSuggestionClick($e) {\n this.trigger(\"suggestionClicked\", $($e.currentTarget));\n },\n _onSuggestionMouseEnter: function onSuggestionMouseEnter($e) {\n this._removeCursor();\n this._setCursor($($e.currentTarget), true);\n },\n _onSuggestionMouseLeave: function onSuggestionMouseLeave() {\n this._removeCursor();\n },\n _onRendered: function onRendered() {\n this.isEmpty = _.every(this.datasets, isDatasetEmpty);\n this.isEmpty ? this._hide() : this.isOpen && this._show();\n this.trigger(\"datasetRendered\");\n function isDatasetEmpty(dataset) {\n return dataset.isEmpty();\n }\n },\n _hide: function() {\n this.$menu.hide();\n },\n _show: function() {\n this.$menu.css(\"display\", \"block\");\n },\n _getSuggestions: function getSuggestions() {\n return this.$menu.find(\".tt-suggestion\");\n },\n _getCursor: function getCursor() {\n return this.$menu.find(\".tt-cursor\").first();\n },\n _setCursor: function setCursor($el, silent) {\n $el.first().addClass(\"tt-cursor\");\n !silent && this.trigger(\"cursorMoved\");\n },\n _removeCursor: function removeCursor() {\n this._getCursor().removeClass(\"tt-cursor\");\n },\n _moveCursor: function moveCursor(increment) {\n var $suggestions, $oldCursor, newCursorIndex, $newCursor;\n if (!this.isOpen) {\n return;\n }\n $oldCursor = this._getCursor();\n $suggestions = this._getSuggestions();\n this._removeCursor();\n newCursorIndex = $suggestions.index($oldCursor) + increment;\n newCursorIndex = (newCursorIndex + 1) % ($suggestions.length + 1) - 1;\n if (newCursorIndex === -1) {\n this.trigger(\"cursorRemoved\");\n return;\n } else if (newCursorIndex < -1) {\n newCursorIndex = $suggestions.length - 1;\n }\n this._setCursor($newCursor = $suggestions.eq(newCursorIndex));\n this._ensureVisible($newCursor);\n },\n _ensureVisible: function ensureVisible($el) {\n var elTop, elBottom, menuScrollTop, menuHeight;\n elTop = $el.position().top;\n elBottom = elTop + $el.outerHeight(true);\n menuScrollTop = this.$menu.scrollTop();\n menuHeight = this.$menu.height() + parseInt(this.$menu.css(\"paddingTop\"), 10) + parseInt(this.$menu.css(\"paddingBottom\"), 10);\n if (elTop < 0) {\n this.$menu.scrollTop(menuScrollTop + elTop);\n } else if (menuHeight < elBottom) {\n this.$menu.scrollTop(menuScrollTop + (elBottom - menuHeight));\n }\n },\n close: function close() {\n if (this.isOpen) {\n this.isOpen = false;\n this._removeCursor();\n this._hide();\n this.trigger(\"closed\");\n }\n },\n open: function open() {\n if (!this.isOpen) {\n this.isOpen = true;\n !this.isEmpty && this._show();\n this.trigger(\"opened\");\n }\n },\n setLanguageDirection: function setLanguageDirection(dir) {\n this.$menu.css(dir === \"ltr\" ? css.ltr : css.rtl);\n },\n moveCursorUp: function moveCursorUp() {\n this._moveCursor(-1);\n },\n moveCursorDown: function moveCursorDown() {\n this._moveCursor(+1);\n },\n getDatumForSuggestion: function getDatumForSuggestion($el) {\n var datum = null;\n if ($el.length) {\n datum = {\n raw: Dataset.extractDatum($el),\n value: Dataset.extractValue($el),\n datasetName: Dataset.extractDatasetName($el)\n };\n }\n return datum;\n },\n getDatumForCursor: function getDatumForCursor() {\n return this.getDatumForSuggestion(this._getCursor().first());\n },\n getDatumForTopSuggestion: function getDatumForTopSuggestion() {\n return this.getDatumForSuggestion(this._getSuggestions().first());\n },\n update: function update(query) {\n _.each(this.datasets, updateDataset);\n function updateDataset(dataset) {\n dataset.update(query);\n }\n },\n empty: function empty() {\n _.each(this.datasets, clearDataset);\n this.isEmpty = true;\n function clearDataset(dataset) {\n dataset.clear();\n }\n },\n isVisible: function isVisible() {\n return this.isOpen && !this.isEmpty;\n },\n destroy: function destroy() {\n this.$menu.off(\".tt\");\n this.$menu = null;\n _.each(this.datasets, destroyDataset);\n function destroyDataset(dataset) {\n dataset.destroy();\n }\n }\n });\n return Dropdown;\n function initializeDataset(oDataset) {\n return new Dataset(oDataset);\n }\n }();\n var Typeahead = function() {\n var attrsKey = \"ttAttrs\";\n function Typeahead(o) {\n var $menu, $input, $hint;\n o = o || {};\n if (!o.input) {\n $.error(\"missing input\");\n }\n this.isActivated = false;\n this.autoselect = !!o.autoselect;\n this.minLength = _.isNumber(o.minLength) ? o.minLength : 1;\n this.$node = buildDomStructure(o.input, o.withHint);\n $menu = this.$node.find(\".tt-dropdown-menu\");\n $input = this.$node.find(\".tt-input\");\n $hint = this.$node.find(\".tt-hint\");\n $input.on(\"blur.tt\", function($e) {\n var active, isActive, hasActive;\n active = document.activeElement;\n isActive = $menu.is(active);\n hasActive = $menu.has(active).length > 0;\n if (_.isMsie() && (isActive || hasActive)) {\n $e.preventDefault();\n $e.stopImmediatePropagation();\n _.defer(function() {\n $input.focus();\n });\n }\n });\n $menu.on(\"mousedown.tt\", function($e) {\n $e.preventDefault();\n });\n this.eventBus = o.eventBus || new EventBus({\n el: $input\n });\n this.dropdown = new Dropdown({\n menu: $menu,\n datasets: o.datasets\n }).onSync(\"suggestionClicked\", this._onSuggestionClicked, this).onSync(\"cursorMoved\", this._onCursorMoved, this).onSync(\"cursorRemoved\", this._onCursorRemoved, this).onSync(\"opened\", this._onOpened, this).onSync(\"closed\", this._onClosed, this).onAsync(\"datasetRendered\", this._onDatasetRendered, this);\n this.input = new Input({\n input: $input,\n hint: $hint\n }).onSync(\"focused\", this._onFocused, this).onSync(\"blurred\", this._onBlurred, this).onSync(\"enterKeyed\", this._onEnterKeyed, this).onSync(\"tabKeyed\", this._onTabKeyed, this).onSync(\"escKeyed\", this._onEscKeyed, this).onSync(\"upKeyed\", this._onUpKeyed, this).onSync(\"downKeyed\", this._onDownKeyed, this).onSync(\"leftKeyed\", this._onLeftKeyed, this).onSync(\"rightKeyed\", this._onRightKeyed, this).onSync(\"queryChanged\", this._onQueryChanged, this).onSync(\"whitespaceChanged\", this._onWhitespaceChanged, this);\n this._setLanguageDirection();\n }\n _.mixin(Typeahead.prototype, {\n _onSuggestionClicked: function onSuggestionClicked(type, $el) {\n var datum;\n if (datum = this.dropdown.getDatumForSuggestion($el)) {\n this._select(datum);\n }\n },\n _onCursorMoved: function onCursorMoved() {\n var datum = this.dropdown.getDatumForCursor();\n this.input.setInputValue(datum.value, true);\n this.eventBus.trigger(\"cursorchanged\", datum.raw, datum.datasetName);\n },\n _onCursorRemoved: function onCursorRemoved() {\n this.input.resetInputValue();\n this._updateHint();\n },\n _onDatasetRendered: function onDatasetRendered() {\n this._updateHint();\n },\n _onOpened: function onOpened() {\n this._updateHint();\n this.eventBus.trigger(\"opened\");\n },\n _onClosed: function onClosed() {\n this.input.clearHint();\n this.eventBus.trigger(\"closed\");\n },\n _onFocused: function onFocused() {\n this.isActivated = true;\n this.dropdown.open();\n },\n _onBlurred: function onBlurred() {\n this.isActivated = false;\n this.dropdown.empty();\n this.dropdown.close();\n this.setVal(\"\", true); //LM\n },\n _onEnterKeyed: function onEnterKeyed(type, $e) {\n var cursorDatum, topSuggestionDatum;\n cursorDatum = this.dropdown.getDatumForCursor();\n topSuggestionDatum = this.dropdown.getDatumForTopSuggestion();\n if (cursorDatum) {\n this._select(cursorDatum);\n $e.preventDefault();\n } else if (this.autoselect && topSuggestionDatum) {\n this._select(topSuggestionDatum);\n $e.preventDefault();\n }\n },\n _onTabKeyed: function onTabKeyed(type, $e) {\n var datum;\n if (datum = this.dropdown.getDatumForCursor()) {\n this._select(datum);\n $e.preventDefault();\n } else {\n this._autocomplete(true);\n }\n },\n _onEscKeyed: function onEscKeyed() {\n this.dropdown.close();\n this.input.resetInputValue();\n },\n _onUpKeyed: function onUpKeyed() {\n var query = this.input.getQuery();\n this.dropdown.isEmpty && query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.moveCursorUp();\n this.dropdown.open();\n },\n _onDownKeyed: function onDownKeyed() {\n var query = this.input.getQuery();\n this.dropdown.isEmpty && query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.moveCursorDown();\n this.dropdown.open();\n },\n _onLeftKeyed: function onLeftKeyed() {\n this.dir === \"rtl\" && this._autocomplete();\n },\n _onRightKeyed: function onRightKeyed() {\n this.dir === \"ltr\" && this._autocomplete();\n },\n _onQueryChanged: function onQueryChanged(e, query) {\n this.input.clearHintIfInvalid();\n query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.empty();\n this.dropdown.open();\n this._setLanguageDirection();\n },\n _onWhitespaceChanged: function onWhitespaceChanged() {\n this._updateHint();\n this.dropdown.open();\n },\n _setLanguageDirection: function setLanguageDirection() {\n var dir;\n if (this.dir !== (dir = this.input.getLanguageDirection())) {\n this.dir = dir;\n this.$node.css(\"direction\", dir);\n this.dropdown.setLanguageDirection(dir);\n }\n },\n _updateHint: function updateHint() {\n var datum, val, query, escapedQuery, frontMatchRegEx, match;\n datum = this.dropdown.getDatumForTopSuggestion();\n if (datum && this.dropdown.isVisible() && !this.input.hasOverflow()) {\n val = this.input.getInputValue();\n query = Input.normalizeQuery(val);\n escapedQuery = _.escapeRegExChars(query);\n frontMatchRegEx = new RegExp(\"^(?:\" + escapedQuery + \")(.+$)\", \"i\");\n match = frontMatchRegEx.exec(datum.value);\n match ? this.input.setHint(val + match[1]) : this.input.clearHint();\n } else {\n this.input.clearHint();\n }\n },\n _autocomplete: function autocomplete(laxCursor) {\n var hint, query, isCursorAtEnd, datum;\n hint = this.input.getHint();\n query = this.input.getQuery();\n isCursorAtEnd = laxCursor || this.input.isCursorAtEnd();\n if (hint && query !== hint && isCursorAtEnd) {\n datum = this.dropdown.getDatumForTopSuggestion();\n datum && this.input.setInputValue(datum.value);\n this.eventBus.trigger(\"autocompleted\", datum.raw, datum.datasetName);\n }\n },\n _select: function select(datum) {\n this.input.setQuery(datum.value);\n this.input.setInputValue(datum.value, true);\n this._setLanguageDirection();\n this.eventBus.trigger(\"selected\", datum.raw, datum.datasetName);\n this.dropdown.close();\n _.defer(_.bind(this.dropdown.empty, this.dropdown));\n },\n open: function open() {\n this.dropdown.open();\n },\n close: function close() {\n this.dropdown.close();\n },\n setVal: function setVal(val) {\n if (this.isActivated) {\n this.input.setInputValue(val);\n } else {\n this.input.setQuery(val);\n this.input.setInputValue(val, true);\n }\n this._setLanguageDirection();\n },\n getVal: function getVal() {\n return this.input.getQuery();\n },\n destroy: function destroy() {\n this.input.destroy();\n this.dropdown.destroy();\n destroyDomStructure(this.$node);\n this.$node = null;\n }\n });\n return Typeahead;\n function buildDomStructure(input, withHint) {\n var $input, $wrapper, $dropdown, $hint;\n $input = $(input);\n $wrapper = $(html.wrapper).css(css.wrapper);\n $dropdown = $(html.dropdown).css(css.dropdown);\n $hint = $input.clone().css(css.hint).css(getBackgroundStyles($input));\n $hint.val(\"\").removeData().addClass(\"tt-hint\").removeAttr(\"id name placeholder\").prop(\"disabled\", true).attr({\n autocomplete: \"off\",\n spellcheck: \"false\"\n });\n $input.data(attrsKey, {\n dir: $input.attr(\"dir\"),\n autocomplete: $input.attr(\"autocomplete\"),\n spellcheck: $input.attr(\"spellcheck\"),\n style: $input.attr(\"style\")\n });\n $input.addClass(\"tt-input\").attr({\n autocomplete: \"off\",\n spellcheck: false\n }).css(withHint ? css.input : css.inputWithNoHint);\n try {\n !$input.attr(\"dir\") && $input.attr(\"dir\", \"auto\");\n } catch (e) {}\n return $input.wrap($wrapper).parent().prepend(withHint ? $hint : null).append($dropdown);\n }\n function getBackgroundStyles($el) {\n return {\n backgroundAttachment: $el.css(\"background-attachment\"),\n backgroundClip: $el.css(\"background-clip\"),\n backgroundColor: $el.css(\"background-color\"),\n backgroundImage: $el.css(\"background-image\"),\n backgroundOrigin: $el.css(\"background-origin\"),\n backgroundPosition: $el.css(\"background-position\"),\n backgroundRepeat: $el.css(\"background-repeat\"),\n backgroundSize: $el.css(\"background-size\")\n };\n }\n function destroyDomStructure($node) {\n var $input = $node.find(\".tt-input\");\n _.each($input.data(attrsKey), function(val, key) {\n _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val);\n });\n $input.detach().removeData(attrsKey).removeClass(\"tt-input\").insertAfter($node);\n $node.remove();\n }\n }();\n (function() {\n var old, typeaheadKey, methods;\n old = $.fn.typeahead;\n typeaheadKey = \"ttTypeahead\";\n methods = {\n initialize: function initialize(o, datasets) {\n datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1);\n o = o || {};\n return this.each(attach);\n function attach() {\n var $input = $(this), eventBus, typeahead;\n _.each(datasets, function(d) {\n d.highlight = !!o.highlight;\n });\n typeahead = new Typeahead({\n input: $input,\n eventBus: eventBus = new EventBus({\n el: $input\n }),\n withHint: _.isUndefined(o.hint) ? true : !!o.hint,\n minLength: o.minLength,\n autoselect: o.autoselect,\n datasets: datasets\n });\n $input.data(typeaheadKey, typeahead);\n }\n },\n open: function open() {\n return this.each(openTypeahead);\n function openTypeahead() {\n var $input = $(this), typeahead;\n if (typeahead = $input.data(typeaheadKey)) {\n typeahead.open();\n }\n }\n },\n close: function close() {\n return this.each(closeTypeahead);\n function closeTypeahead() {\n var $input = $(this), typeahead;\n if (typeahead = $input.data(typeaheadKey)) {\n typeahead.close();\n }\n }\n },\n val: function val(newVal) {\n return !arguments.length ? getVal(this.first()) : this.each(setVal);\n function setVal() {\n var $input = $(this), typeahead;\n if (typeahead = $input.data(typeaheadKey)) {\n typeahead.setVal(newVal);\n }\n }\n function getVal($input) {\n var typeahead, query;\n if (typeahead = $input.data(typeaheadKey)) {\n query = typeahead.getVal();\n }\n return query;\n }\n },\n destroy: function destroy() {\n return this.each(unattach);\n function unattach() {\n var $input = $(this), typeahead;\n if (typeahead = $input.data(typeaheadKey)) {\n typeahead.destroy();\n $input.removeData(typeaheadKey);\n }\n }\n }\n };\n $.fn.typeahead = function(method) {\n if (methods[method]) {\n return methods[method].apply(this, [].slice.call(arguments, 1));\n } else {\n return methods.initialize.apply(this, arguments);\n }\n };\n $.fn.typeahead.noConflict = function noConflict() {\n $.fn.typeahead = old;\n return this;\n };\n })();\n \n \n \n//})(window.jQuery);\n\n\n});\n", "define('searchView',[\n 'App',\n // Templates\n 'text!tpl/search.html',\n 'text!tpl/search_suggestion.html',\n // Tools\n 'typeahead'\n], function(App, searchTpl, suggestionTpl) {\n\n var searchView = Backbone.View.extend({\n el: '#search',\n /**\n * Init.\n */\n init: function() {\n var tpl = _.template(searchTpl);\n var className = 'form-control input-lg';\n var placeholder = 'Search reference';\n this.searchHtml = tpl({\n 'placeholder': placeholder,\n 'className': className\n });\n this.items = App.classes.concat(App.allItems);\n\n return this;\n },\n /**\n * Render input field with Typehead activated.\n */\n render: function() {\n // Append the view to the dom\n this.$el.append(this.searchHtml);\n\n // Render Typeahead\n var $searchInput = this.$el.find('input[type=text]');\n this.typeaheadRender($searchInput);\n this.typeaheadEvents($searchInput);\n\n return this;\n },\n /**\n * Apply Twitter Typeahead to the search input field.\n * @param {jquery} $input\n */\n typeaheadRender: function($input) {\n var self = this;\n $input.typeahead(null, {\n 'displayKey': 'name',\n 'minLength': 2,\n //'highlight': true,\n 'source': self.substringMatcher(this.items),\n 'templates': {\n 'empty': '

Unable to find any item that match the current query

',\n 'suggestion': _.template(suggestionTpl)\n }\n });\n },\n /**\n * Setup typeahead custom events (item selected).\n */\n typeaheadEvents: function($input) {\n var self = this;\n $input.on('typeahead:selected', function(e, item, datasetName) {\n var selectedItem = self.items[item.idx];\n select(selectedItem);\n });\n $input.on('keydown', function(e) {\n if (e.which === 13) { // enter\n var txt = $input.val();\n var f = _.find(self.items, function(it) { return it.name == txt; });\n if (f) {\n select(f);\n }\n } else if (e.which === 27) {\n $input.blur();\n }\n });\n\n function select(selectedItem) {\n var hash = App.router.getHash(selectedItem);//\n App.router.navigate(hash, {'trigger': true});\n $('#item').focus();\n }\n },\n /**\n * substringMatcher function for Typehead (search for strings in an array).\n * @param {array} array\n * @returns {Function}\n */\n substringMatcher: function(array) {\n return function findMatches(query, callback) {\n var matches = [], substrRegex, arrayLength = array.length;\n\n // regex used to determine if a string contains the substring `query`\n substrRegex = new RegExp(query, 'i');\n\n // iterate through the pool of strings and for any string that\n // contains the substring `query`, add it to the `matches` array\n for (var i=0; i < arrayLength; i++) {\n var item = array[i];\n if (substrRegex.test(item.name)) {\n // typeahead expects suggestions to be a js object\n matches.push({\n 'itemtype': item.itemtype,\n 'name': item.name,\n 'className': item.class,\n 'is_constructor': !!item.is_constructor,\n 'final': item.final,\n 'idx': i\n });\n }\n }\n\n callback(matches);\n };\n }\n\n });\n\n return searchView;\n\n});\n\n", "\ndefine('text!tpl/list.html',[],function () { return '<% _.each(groups, function(group){ %>\\n
\\n

\" tab-index=\"-1\"><%=group.name%>

\\n
\\n <% _.each(group.subgroups, function(subgroup, ind) { %>\\n
\\n <% if (subgroup.name !== \\'0\\') { %>\\n

<%=ind%>\" class=\"subgroup-name subgroup-<%=subgroup.name%>\"><%=subgroup.name%>

\\n <% } %>\\n \\n
\\n <% }); %>\\n
\\n
\\n<% }); %>\\n';});\n\n", "define('listView',[\n 'App',\n // Templates\n 'text!tpl/list.html'\n], function (App, listTpl) {\n var striptags = function(html) {\n var div = document.createElement('div');\n div.innerHTML = html;\n return div.textContent;\n };\n\n var listView = Backbone.View.extend({\n el: '#list',\n events: {},\n /**\n * Init.\n */\n init: function () {\n this.listTpl = _.template(listTpl);\n\n return this;\n },\n /**\n * Render the list.\n */\n render: function (items, listCollection) {\n if (items && listCollection) {\n var self = this;\n\n // Render items and group them by module\n // module === group\n this.groups = {};\n _.each(items, function (item, i) {\n\n if (!item.private && item.file.indexOf('addons') === -1) { //addons don't get displayed on main page\n\n var group = item.module || '_';\n var subgroup = item.submodule || '_';\n if (group === subgroup) {\n subgroup = '0';\n }\n var hash = App.router.getHash(item);\n\n // fixes broken links for #/p5/> and #/p5/>=\n item.hash = item.hash.replace('>', '>');\n\n // Create a group list\n if (!self.groups[group]) {\n self.groups[group] = {\n name: group.replace('_', ' '),\n subgroups: {}\n };\n }\n\n // Create a subgroup list\n if (!self.groups[group].subgroups[subgroup]) {\n self.groups[group].subgroups[subgroup] = {\n name: subgroup.replace('_', ' '),\n items: []\n };\n }\n\n // hide the un-interesting constants\n if (group === 'Constants' && !item.example)\n return;\n\n if (item.class === 'p5') {\n\n self.groups[group].subgroups[subgroup].items.push(item);\n\n } else {\n\n var found = _.find(self.groups[group].subgroups[subgroup].items,\n function(i){ return i.name == item.class; });\n\n if (!found) {\n\n // FIX TO INVISIBLE OBJECTS: DH (see also router.js)\n var ind = hash.lastIndexOf('/');\n hash = item.hash.substring(0, ind).replace('p5/','p5.');\n self.groups[group].subgroups[subgroup].items.push({\n name: item.class,\n hash: hash\n });\n }\n\n }\n }\n });\n\n // Put the
  • items html into the list
      \n var listHtml = self.listTpl({\n 'striptags': striptags,\n 'title': self.capitalizeFirst(listCollection),\n 'groups': self.groups,\n 'listCollection': listCollection\n });\n\n // Render the view\n this.$el.html(listHtml);\n }\n\n var renderEvent = new Event('reference-rendered');\n window.dispatchEvent(renderEvent);\n\n return this;\n },\n /**\n * Show a list of items.\n * @param {array} items Array of item objects.\n * @returns {object} This view.\n */\n show: function (listGroup) {\n if (App[listGroup]) {\n this.render(App[listGroup], listGroup);\n }\n App.pageView.hideContentViews();\n\n this.$el.show();\n\n return this;\n },\n /**\n * Helper method to capitalize the first letter of a string\n * @param {string} str\n * @returns {string} Returns the string.\n */\n capitalizeFirst: function (str) {\n return str.substr(0, 1).toUpperCase() + str.substr(1);\n }\n\n\n\n });\n\n return listView;\n\n});\n\n", "\ndefine('text!tpl/item.html',[],function () { return '

      <%=item.name%><% if (item.isMethod) { %>()<% } %>

      \\n\\n<% if (item.example) { %>\\n
      \\n

      Examples

      \\n\\n
      \">\\n <% _.each(item.example, function(example, i){ %>\\n <%= example %>\\n <% }); %>\\n
      \\n
      \\n<% } %>\\n\\n
      \\n \\n

      Description

      \\n\\n <% if (item.deprecated) { %>\\n

      \\n Deprecated: <%=item.name%><% if (item.isMethod) { %>()<% } %> is deprecated and will be removed in a future version of p5. <% if (item.deprecationMessage) { %><%=item.deprecationMessage%><% } %>\\n

      \\n <% } %>\\n \\n\\n <%= item.description %>\\n\\n <% if (item.extends) { %>\\n

      Extends \" title=\"<%=item.extends%> reference\"><%=item.extends%>

      \\n <% } %>\\n\\n <% if (item.module === \\'p5.sound\\') { %>\\n

      This function requires you include the p5.sound library. Add the following into the head of your index.html file:\\n

      <script src=\"path/to/p5.sound.js\"></script>
      \\n

      \\n <% } %>\\n\\n <% if (item.constRefs) { %>\\n

      Used by:\\n <%\\n var refs = item.constRefs;\\n for (var i = 0; i < refs.length; i ++) {\\n var ref = refs[i];\\n var name = ref;\\n if (name.substr(0, 3) === \\'p5.\\') {\\n name = name.substr(3);\\n }\\n if (i !== 0) {\\n if (i == refs.length - 1) {\\n %> and <%\\n } else {\\n %>, <%\\n }\\n }\\n %>\"><%= name %>()<%\\n }\\n %>\\n

      \\n <% } %>\\n
      \\n\\n<% if (isConstructor || !isClass) { %>\\n\\n
      \\n

      Syntax

      \\n

      \\n <% syntaxes.forEach(function(syntax) { %>\\n

      <%= syntax %>
      \\n <% }) %>\\n

      \\n
      \\n\\n\\n<% if (item.params) { %>\\n
      \\n

      Parameters

      \\n
        \\n <% for (var i=0; i\\n <% var p = item.params[i] %>\\n
      • \\n
        <%=p.name%>
        \\n <% if (p.type) { %>\\n
        \\n <% var type = p.type.replace(/(p5\\\\.[A-Z][A-Za-z]*)/, \\'$1\\'); %>\\n <%=type%>: <%=p.description%>\\n <% if (p.optional) { %> (Optional)<% } %>\\n
        \\n <% } %>\\n
      • \\n <% } %>\\n
      \\n
      \\n<% } %>\\n\\n<% if (item.return && item.return.type) { %>\\n
      \\n

      Returns

      \\n

      <%=item.return.type%>: <%= item.return.description %>

      \\n
      \\n<% } %>\\n\\n<% } %>\\n';});\n\n", "\ndefine('text!tpl/class.html',[],function () { return '\\n<% if (typeof constructor !== \\'undefined\\') { %>\\n
      \\n <%=constructor%>\\n
      \\n<% } %>\\n\\n<% let fields = _.filter(things, function(item) { return item.itemtype === \\'property\\' && item.access !== \\'private\\' }); %>\\n<% if (fields.length > 0) { %>\\n

      Fields

      \\n \\n<% } %>\\n\\n<% let methods = _.filter(things, function(item) { return item.itemtype === \\'method\\' && item.access !== \\'private\\' }); %>\\n<% if (methods.length > 0) { %>\\n

      Methods

      \\n \\n<% } %>\\n';});\n\n", "\ndefine('text!tpl/itemEnd.html',[],function () { return '\\n

      \\n\\n
      \\n<% if (item.file && item.line) { %>\\nNotice any errors or typos? Please let us know. Please feel free to edit /<%= item.file %>#L<%= item.line %>\" target=\"_blank\" ><%= item.file %> and issue a pull request!\\n<% } %>\\n
      \\n\\n\"creative\\n

      \\n';});\n\n", - "// Copyright (C) 2006 Google Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n\n/**\n * @fileoverview\n * some functions for browser-side pretty printing of code contained in html.\n *\n *

      \n * For a fairly comprehensive set of languages see the\n * README\n * file that came with this source. At a minimum, the lexer should work on a\n * number of languages including C and friends, Java, Python, Bash, SQL, HTML,\n * XML, CSS, Javascript, and Makefiles. It works passably on Ruby, PHP and Awk\n * and a subset of Perl, but, because of commenting conventions, doesn't work on\n * Smalltalk, Lisp-like, or CAML-like languages without an explicit lang class.\n *

      \n * Usage:

        \n *
      1. include this source file in an html page via\n * {@code }\n *
      2. define style rules. See the example page for examples.\n *
      3. mark the {@code
        } and {@code } tags in your source with\n *    {@code class=prettyprint.}\n *    You can also use the (html deprecated) {@code } tag, but the pretty\n *    printer needs to do more substantial DOM manipulations to support that, so\n *    some css styles may not be preserved.\n * </ol>\n * That's it.  I wanted to keep the API as simple as possible, so there's no\n * need to specify which language the code is in, but if you wish, you can add\n * another class to the {@code <pre>} or {@code <code>} element to specify the\n * language, as in {@code <pre class=\"prettyprint lang-java\">}.  Any class that\n * starts with \"lang-\" followed by a file extension, specifies the file type.\n * See the \"lang-*.js\" files in this directory for code that implements\n * per-language file handlers.\n * <p>\n * Change log:<br>\n * cbeust, 2006/08/22\n * <blockquote>\n *   Java annotations (start with \"@\") are now captured as literals (\"lit\")\n * </blockquote>\n * @requires console\n */\n\n// JSLint declarations\n/*global console, document, navigator, setTimeout, window, define */\n\n/** @define {boolean} */\nvar IN_GLOBAL_SCOPE = true;\n\n/**\n * Split {@code prettyPrint} into multiple timeouts so as not to interfere with\n * UI events.\n * If set to {@code false}, {@code prettyPrint()} is synchronous.\n */\nwindow['PR_SHOULD_USE_CONTINUATION'] = true;\n\n/**\n * Pretty print a chunk of code.\n * @param {string} sourceCodeHtml The HTML to pretty print.\n * @param {string} opt_langExtension The language name to use.\n *     Typically, a filename extension like 'cpp' or 'java'.\n * @param {number|boolean} opt_numberLines True to number lines,\n *     or the 1-indexed number of the first line in sourceCodeHtml.\n * @return {string} code as html, but prettier\n */\nvar prettyPrintOne;\n/**\n * Find all the {@code <pre>} and {@code <code>} tags in the DOM with\n * {@code class=prettyprint} and prettify them.\n *\n * @param {Function} opt_whenDone called when prettifying is done.\n * @param {HTMLElement|HTMLDocument} opt_root an element or document\n *   containing all the elements to pretty print.\n *   Defaults to {@code document.body}.\n */\nvar prettyPrint;\n\n\n(function () {\n  var win = window;\n  // Keyword lists for various languages.\n  // We use things that coerce to strings to make them compact when minified\n  // and to defeat aggressive optimizers that fold large string constants.\n  var FLOW_CONTROL_KEYWORDS = [\"break,continue,do,else,for,if,return,while\"];\n  var C_KEYWORDS = [FLOW_CONTROL_KEYWORDS,\"auto,case,char,const,default,\" + \n      \"double,enum,extern,float,goto,inline,int,long,register,short,signed,\" +\n      \"sizeof,static,struct,switch,typedef,union,unsigned,void,volatile\"];\n  var COMMON_KEYWORDS = [C_KEYWORDS,\"catch,class,delete,false,import,\" +\n      \"new,operator,private,protected,public,this,throw,true,try,typeof\"];\n  var CPP_KEYWORDS = [COMMON_KEYWORDS,\"alignof,align_union,asm,axiom,bool,\" +\n      \"concept,concept_map,const_cast,constexpr,decltype,delegate,\" +\n      \"dynamic_cast,explicit,export,friend,generic,late_check,\" +\n      \"mutable,namespace,nullptr,property,reinterpret_cast,static_assert,\" +\n      \"static_cast,template,typeid,typename,using,virtual,where\"];\n  var JAVA_KEYWORDS = [COMMON_KEYWORDS,\n      \"abstract,assert,boolean,byte,extends,final,finally,implements,import,\" +\n      \"instanceof,interface,null,native,package,strictfp,super,synchronized,\" +\n      \"throws,transient\"];\n  var CSHARP_KEYWORDS = [JAVA_KEYWORDS,\n      \"as,base,by,checked,decimal,delegate,descending,dynamic,event,\" +\n      \"fixed,foreach,from,group,implicit,in,internal,into,is,let,\" +\n      \"lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,\" +\n      \"sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,\" +\n      \"var,virtual,where\"];\n  var COFFEE_KEYWORDS = \"all,and,by,catch,class,else,extends,false,finally,\" +\n      \"for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,\" +\n      \"throw,true,try,unless,until,when,while,yes\";\n  var JSCRIPT_KEYWORDS = [COMMON_KEYWORDS,\n      \"debugger,eval,export,function,get,null,set,undefined,var,with,\" +\n      \"Infinity,NaN\"];\n  var PERL_KEYWORDS = \"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,\" +\n      \"goto,if,import,last,local,my,next,no,our,print,package,redo,require,\" +\n      \"sub,undef,unless,until,use,wantarray,while,BEGIN,END\";\n  var PYTHON_KEYWORDS = [FLOW_CONTROL_KEYWORDS, \"and,as,assert,class,def,del,\" +\n      \"elif,except,exec,finally,from,global,import,in,is,lambda,\" +\n      \"nonlocal,not,or,pass,print,raise,try,with,yield,\" +\n      \"False,True,None\"];\n  var RUBY_KEYWORDS = [FLOW_CONTROL_KEYWORDS, \"alias,and,begin,case,class,\" +\n      \"def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,\" +\n      \"rescue,retry,self,super,then,true,undef,unless,until,when,yield,\" +\n      \"BEGIN,END\"];\n   var RUST_KEYWORDS = [FLOW_CONTROL_KEYWORDS, \"as,assert,const,copy,drop,\" +\n      \"enum,extern,fail,false,fn,impl,let,log,loop,match,mod,move,mut,priv,\" +\n      \"pub,pure,ref,self,static,struct,true,trait,type,unsafe,use\"];\n  var SH_KEYWORDS = [FLOW_CONTROL_KEYWORDS, \"case,done,elif,esac,eval,fi,\" +\n      \"function,in,local,set,then,until\"];\n  var ALL_KEYWORDS = [\n      CPP_KEYWORDS, CSHARP_KEYWORDS, JSCRIPT_KEYWORDS, PERL_KEYWORDS,\n      PYTHON_KEYWORDS, RUBY_KEYWORDS, SH_KEYWORDS];\n  var C_TYPES = /^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\\d*)\\b/;\n\n  // token style names.  correspond to css classes\n  /**\n   * token style for a string literal\n   * @const\n   */\n  var PR_STRING = 'str';\n  /**\n   * token style for a keyword\n   * @const\n   */\n  var PR_KEYWORD = 'kwd';\n  /**\n   * token style for a comment\n   * @const\n   */\n  var PR_COMMENT = 'com';\n  /**\n   * token style for a type\n   * @const\n   */\n  var PR_TYPE = 'typ';\n  /**\n   * token style for a literal value.  e.g. 1, null, true.\n   * @const\n   */\n  var PR_LITERAL = 'lit';\n  /**\n   * token style for a punctuation string.\n   * @const\n   */\n  var PR_PUNCTUATION = 'pun';\n  /**\n   * token style for plain text.\n   * @const\n   */\n  var PR_PLAIN = 'pln';\n\n  /**\n   * token style for an sgml tag.\n   * @const\n   */\n  var PR_TAG = 'tag';\n  /**\n   * token style for a markup declaration such as a DOCTYPE.\n   * @const\n   */\n  var PR_DECLARATION = 'dec';\n  /**\n   * token style for embedded source.\n   * @const\n   */\n  var PR_SOURCE = 'src';\n  /**\n   * token style for an sgml attribute name.\n   * @const\n   */\n  var PR_ATTRIB_NAME = 'atn';\n  /**\n   * token style for an sgml attribute value.\n   * @const\n   */\n  var PR_ATTRIB_VALUE = 'atv';\n\n  /**\n   * A class that indicates a section of markup that is not code, e.g. to allow\n   * embedding of line numbers within code listings.\n   * @const\n   */\n  var PR_NOCODE = 'nocode';\n\n  \n  \n  /**\n   * A set of tokens that can precede a regular expression literal in\n   * javascript\n   * http://web.archive.org/web/20070717142515/http://www.mozilla.org/js/language/js20/rationale/syntax.html\n   * has the full list, but I've removed ones that might be problematic when\n   * seen in languages that don't support regular expression literals.\n   *\n   * <p>Specifically, I've removed any keywords that can't precede a regexp\n   * literal in a syntactically legal javascript program, and I've removed the\n   * \"in\" keyword since it's not a keyword in many languages, and might be used\n   * as a count of inches.\n   *\n   * <p>The link above does not accurately describe EcmaScript rules since\n   * it fails to distinguish between (a=++/b/i) and (a++/b/i) but it works\n   * very well in practice.\n   *\n   * @private\n   * @const\n   */\n  var REGEXP_PRECEDER_PATTERN = '(?:^^\\\\.?|[+-]|[!=]=?=?|\\\\#|%=?|&&?=?|\\\\(|\\\\*=?|[+\\\\-]=|->|\\\\/=?|::?|<<?=?|>>?>?=?|,|;|\\\\?|@|\\\\[|~|{|\\\\^\\\\^?=?|\\\\|\\\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\\\s*';\n  \n  // CAVEAT: this does not properly handle the case where a regular\n  // expression immediately follows another since a regular expression may\n  // have flags for case-sensitivity and the like.  Having regexp tokens\n  // adjacent is not valid in any language I'm aware of, so I'm punting.\n  // TODO: maybe style special characters inside a regexp as punctuation.\n\n  /**\n   * Given a group of {@link RegExp}s, returns a {@code RegExp} that globally\n   * matches the union of the sets of strings matched by the input RegExp.\n   * Since it matches globally, if the input strings have a start-of-input\n   * anchor (/^.../), it is ignored for the purposes of unioning.\n   * @param {Array.<RegExp>} regexs non multiline, non-global regexs.\n   * @return {RegExp} a global regex.\n   */\n  function combinePrefixPatterns(regexs) {\n    var capturedGroupIndex = 0;\n  \n    var needToFoldCase = false;\n    var ignoreCase = false;\n    for (var i = 0, n = regexs.length; i < n; ++i) {\n      var regex = regexs[i];\n      if (regex.ignoreCase) {\n        ignoreCase = true;\n      } else if (/[a-z]/i.test(regex.source.replace(\n                     /\\\\u[0-9a-f]{4}|\\\\x[0-9a-f]{2}|\\\\[^ux]/gi, ''))) {\n        needToFoldCase = true;\n        ignoreCase = false;\n        break;\n      }\n    }\n  \n    var escapeCharToCodeUnit = {\n      'b': 8,\n      't': 9,\n      'n': 0xa,\n      'v': 0xb,\n      'f': 0xc,\n      'r': 0xd\n    };\n  \n    function decodeEscape(charsetPart) {\n      var cc0 = charsetPart.charCodeAt(0);\n      if (cc0 !== 92 /* \\\\ */) {\n        return cc0;\n      }\n      var c1 = charsetPart.charAt(1);\n      cc0 = escapeCharToCodeUnit[c1];\n      if (cc0) {\n        return cc0;\n      } else if ('0' <= c1 && c1 <= '7') {\n        return parseInt(charsetPart.substring(1), 8);\n      } else if (c1 === 'u' || c1 === 'x') {\n        return parseInt(charsetPart.substring(2), 16);\n      } else {\n        return charsetPart.charCodeAt(1);\n      }\n    }\n  \n    function encodeEscape(charCode) {\n      if (charCode < 0x20) {\n        return (charCode < 0x10 ? '\\\\x0' : '\\\\x') + charCode.toString(16);\n      }\n      var ch = String.fromCharCode(charCode);\n      return (ch === '\\\\' || ch === '-' || ch === ']' || ch === '^')\n          ? \"\\\\\" + ch : ch;\n    }\n  \n    function caseFoldCharset(charSet) {\n      var charsetParts = charSet.substring(1, charSet.length - 1).match(\n          new RegExp(\n              '\\\\\\\\u[0-9A-Fa-f]{4}'\n              + '|\\\\\\\\x[0-9A-Fa-f]{2}'\n              + '|\\\\\\\\[0-3][0-7]{0,2}'\n              + '|\\\\\\\\[0-7]{1,2}'\n              + '|\\\\\\\\[\\\\s\\\\S]'\n              + '|-'\n              + '|[^-\\\\\\\\]',\n              'g'));\n      var ranges = [];\n      var inverse = charsetParts[0] === '^';\n  \n      var out = ['['];\n      if (inverse) { out.push('^'); }\n  \n      for (var i = inverse ? 1 : 0, n = charsetParts.length; i < n; ++i) {\n        var p = charsetParts[i];\n        if (/\\\\[bdsw]/i.test(p)) {  // Don't muck with named groups.\n          out.push(p);\n        } else {\n          var start = decodeEscape(p);\n          var end;\n          if (i + 2 < n && '-' === charsetParts[i + 1]) {\n            end = decodeEscape(charsetParts[i + 2]);\n            i += 2;\n          } else {\n            end = start;\n          }\n          ranges.push([start, end]);\n          // If the range might intersect letters, then expand it.\n          // This case handling is too simplistic.\n          // It does not deal with non-latin case folding.\n          // It works for latin source code identifiers though.\n          if (!(end < 65 || start > 122)) {\n            if (!(end < 65 || start > 90)) {\n              ranges.push([Math.max(65, start) | 32, Math.min(end, 90) | 32]);\n            }\n            if (!(end < 97 || start > 122)) {\n              ranges.push([Math.max(97, start) & ~32, Math.min(end, 122) & ~32]);\n            }\n          }\n        }\n      }\n  \n      // [[1, 10], [3, 4], [8, 12], [14, 14], [16, 16], [17, 17]]\n      // -> [[1, 12], [14, 14], [16, 17]]\n      ranges.sort(function (a, b) { return (a[0] - b[0]) || (b[1]  - a[1]); });\n      var consolidatedRanges = [];\n      var lastRange = [];\n      for (var i = 0; i < ranges.length; ++i) {\n        var range = ranges[i];\n        if (range[0] <= lastRange[1] + 1) {\n          lastRange[1] = Math.max(lastRange[1], range[1]);\n        } else {\n          consolidatedRanges.push(lastRange = range);\n        }\n      }\n  \n      for (var i = 0; i < consolidatedRanges.length; ++i) {\n        var range = consolidatedRanges[i];\n        out.push(encodeEscape(range[0]));\n        if (range[1] > range[0]) {\n          if (range[1] + 1 > range[0]) { out.push('-'); }\n          out.push(encodeEscape(range[1]));\n        }\n      }\n      out.push(']');\n      return out.join('');\n    }\n  \n    function allowAnywhereFoldCaseAndRenumberGroups(regex) {\n      // Split into character sets, escape sequences, punctuation strings\n      // like ('(', '(?:', ')', '^'), and runs of characters that do not\n      // include any of the above.\n      var parts = regex.source.match(\n          new RegExp(\n              '(?:'\n              + '\\\\[(?:[^\\\\x5C\\\\x5D]|\\\\\\\\[\\\\s\\\\S])*\\\\]'  // a character set\n              + '|\\\\\\\\u[A-Fa-f0-9]{4}'  // a unicode escape\n              + '|\\\\\\\\x[A-Fa-f0-9]{2}'  // a hex escape\n              + '|\\\\\\\\[0-9]+'  // a back-reference or octal escape\n              + '|\\\\\\\\[^ux0-9]'  // other escape sequence\n              + '|\\\\(\\\\?[:!=]'  // start of a non-capturing group\n              + '|[\\\\(\\\\)\\\\^]'  // start/end of a group, or line start\n              + '|[^\\\\x5B\\\\x5C\\\\(\\\\)\\\\^]+'  // run of other characters\n              + ')',\n              'g'));\n      var n = parts.length;\n  \n      // Maps captured group numbers to the number they will occupy in\n      // the output or to -1 if that has not been determined, or to\n      // undefined if they need not be capturing in the output.\n      var capturedGroups = [];\n  \n      // Walk over and identify back references to build the capturedGroups\n      // mapping.\n      for (var i = 0, groupIndex = 0; i < n; ++i) {\n        var p = parts[i];\n        if (p === '(') {\n          // groups are 1-indexed, so max group index is count of '('\n          ++groupIndex;\n        } else if ('\\\\' === p.charAt(0)) {\n          var decimalValue = +p.substring(1);\n          if (decimalValue) {\n            if (decimalValue <= groupIndex) {\n              capturedGroups[decimalValue] = -1;\n            } else {\n              // Replace with an unambiguous escape sequence so that\n              // an octal escape sequence does not turn into a backreference\n              // to a capturing group from an earlier regex.\n              parts[i] = encodeEscape(decimalValue);\n            }\n          }\n        }\n      }\n  \n      // Renumber groups and reduce capturing groups to non-capturing groups\n      // where possible.\n      for (var i = 1; i < capturedGroups.length; ++i) {\n        if (-1 === capturedGroups[i]) {\n          capturedGroups[i] = ++capturedGroupIndex;\n        }\n      }\n      for (var i = 0, groupIndex = 0; i < n; ++i) {\n        var p = parts[i];\n        if (p === '(') {\n          ++groupIndex;\n          if (!capturedGroups[groupIndex]) {\n            parts[i] = '(?:';\n          }\n        } else if ('\\\\' === p.charAt(0)) {\n          var decimalValue = +p.substring(1);\n          if (decimalValue && decimalValue <= groupIndex) {\n            parts[i] = '\\\\' + capturedGroups[decimalValue];\n          }\n        }\n      }\n  \n      // Remove any prefix anchors so that the output will match anywhere.\n      // ^^ really does mean an anchored match though.\n      for (var i = 0; i < n; ++i) {\n        if ('^' === parts[i] && '^' !== parts[i + 1]) { parts[i] = ''; }\n      }\n  \n      // Expand letters to groups to handle mixing of case-sensitive and\n      // case-insensitive patterns if necessary.\n      if (regex.ignoreCase && needToFoldCase) {\n        for (var i = 0; i < n; ++i) {\n          var p = parts[i];\n          var ch0 = p.charAt(0);\n          if (p.length >= 2 && ch0 === '[') {\n            parts[i] = caseFoldCharset(p);\n          } else if (ch0 !== '\\\\') {\n            // TODO: handle letters in numeric escapes.\n            parts[i] = p.replace(\n                /[a-zA-Z]/g,\n                function (ch) {\n                  var cc = ch.charCodeAt(0);\n                  return '[' + String.fromCharCode(cc & ~32, cc | 32) + ']';\n                });\n          }\n        }\n      }\n  \n      return parts.join('');\n    }\n  \n    var rewritten = [];\n    for (var i = 0, n = regexs.length; i < n; ++i) {\n      var regex = regexs[i];\n      if (regex.global || regex.multiline) { throw new Error('' + regex); }\n      rewritten.push(\n          '(?:' + allowAnywhereFoldCaseAndRenumberGroups(regex) + ')');\n    }\n  \n    return new RegExp(rewritten.join('|'), ignoreCase ? 'gi' : 'g');\n  }\n\n  /**\n   * Split markup into a string of source code and an array mapping ranges in\n   * that string to the text nodes in which they appear.\n   *\n   * <p>\n   * The HTML DOM structure:</p>\n   * <pre>\n   * (Element   \"p\"\n   *   (Element \"b\"\n   *     (Text  \"print \"))       ; #1\n   *   (Text    \"'Hello '\")      ; #2\n   *   (Element \"br\")            ; #3\n   *   (Text    \"  + 'World';\")) ; #4\n   * </pre>\n   * <p>\n   * corresponds to the HTML\n   * {@code <p><b>print </b>'Hello '<br>  + 'World';</p>}.</p>\n   *\n   * <p>\n   * It will produce the output:</p>\n   * <pre>\n   * {\n   *   sourceCode: \"print 'Hello '\\n  + 'World';\",\n   *   //                     1          2\n   *   //           012345678901234 5678901234567\n   *   spans: [0, #1, 6, #2, 14, #3, 15, #4]\n   * }\n   * </pre>\n   * <p>\n   * where #1 is a reference to the {@code \"print \"} text node above, and so\n   * on for the other text nodes.\n   * </p>\n   *\n   * <p>\n   * The {@code} spans array is an array of pairs.  Even elements are the start\n   * indices of substrings, and odd elements are the text nodes (or BR elements)\n   * that contain the text for those substrings.\n   * Substrings continue until the next index or the end of the source.\n   * </p>\n   *\n   * @param {Node} node an HTML DOM subtree containing source-code.\n   * @param {boolean} isPreformatted true if white-space in text nodes should\n   *    be considered significant.\n   * @return {Object} source code and the text nodes in which they occur.\n   */\n  function extractSourceSpans(node, isPreformatted) {\n    var nocode = /(?:^|\\s)nocode(?:\\s|$)/;\n  \n    var chunks = [];\n    var length = 0;\n    var spans = [];\n    var k = 0;\n  \n    function walk(node) {\n      var type = node.nodeType;\n      if (type == 1) {  // Element\n        if (nocode.test(node.className)) { return; }\n        for (var child = node.firstChild; child; child = child.nextSibling) {\n          walk(child);\n        }\n        var nodeName = node.nodeName.toLowerCase();\n        if ('br' === nodeName || 'li' === nodeName) {\n          chunks[k] = '\\n';\n          spans[k << 1] = length++;\n          spans[(k++ << 1) | 1] = node;\n        }\n      } else if (type == 3 || type == 4) {  // Text\n        var text = node.nodeValue;\n        if (text.length) {\n          if (!isPreformatted) {\n            text = text.replace(/[ \\t\\r\\n]+/g, ' ');\n          } else {\n            text = text.replace(/\\r\\n?/g, '\\n');  // Normalize newlines.\n          }\n          // TODO: handle tabs here?\n          chunks[k] = text;\n          spans[k << 1] = length;\n          length += text.length;\n          spans[(k++ << 1) | 1] = node;\n        }\n      }\n    }\n  \n    walk(node);\n  \n    return {\n      sourceCode: chunks.join('').replace(/\\n$/, ''),\n      spans: spans\n    };\n  }\n\n  /**\n   * Apply the given language handler to sourceCode and add the resulting\n   * decorations to out.\n   * @param {number} basePos the index of sourceCode within the chunk of source\n   *    whose decorations are already present on out.\n   */\n  function appendDecorations(basePos, sourceCode, langHandler, out) {\n    if (!sourceCode) { return; }\n    var job = {\n      sourceCode: sourceCode,\n      basePos: basePos\n    };\n    langHandler(job);\n    out.push.apply(out, job.decorations);\n  }\n\n  var notWs = /\\S/;\n\n  /**\n   * Given an element, if it contains only one child element and any text nodes\n   * it contains contain only space characters, return the sole child element.\n   * Otherwise returns undefined.\n   * <p>\n   * This is meant to return the CODE element in {@code <pre><code ...>} when\n   * there is a single child element that contains all the non-space textual\n   * content, but not to return anything where there are multiple child elements\n   * as in {@code <pre><code>...</code><code>...</code></pre>} or when there\n   * is textual content.\n   */\n  function childContentWrapper(element) {\n    var wrapper = undefined;\n    for (var c = element.firstChild; c; c = c.nextSibling) {\n      var type = c.nodeType;\n      wrapper = (type === 1)  // Element Node\n          ? (wrapper ? element : c)\n          : (type === 3)  // Text Node\n          ? (notWs.test(c.nodeValue) ? element : wrapper)\n          : wrapper;\n    }\n    return wrapper === element ? undefined : wrapper;\n  }\n\n  /** Given triples of [style, pattern, context] returns a lexing function,\n    * The lexing function interprets the patterns to find token boundaries and\n    * returns a decoration list of the form\n    * [index_0, style_0, index_1, style_1, ..., index_n, style_n]\n    * where index_n is an index into the sourceCode, and style_n is a style\n    * constant like PR_PLAIN.  index_n-1 <= index_n, and style_n-1 applies to\n    * all characters in sourceCode[index_n-1:index_n].\n    *\n    * The stylePatterns is a list whose elements have the form\n    * [style : string, pattern : RegExp, DEPRECATED, shortcut : string].\n    *\n    * Style is a style constant like PR_PLAIN, or can be a string of the\n    * form 'lang-FOO', where FOO is a language extension describing the\n    * language of the portion of the token in $1 after pattern executes.\n    * E.g., if style is 'lang-lisp', and group 1 contains the text\n    * '(hello (world))', then that portion of the token will be passed to the\n    * registered lisp handler for formatting.\n    * The text before and after group 1 will be restyled using this decorator\n    * so decorators should take care that this doesn't result in infinite\n    * recursion.  For example, the HTML lexer rule for SCRIPT elements looks\n    * something like ['lang-js', /<[s]cript>(.+?)<\\/script>/].  This may match\n    * '<script>foo()<\\/script>', which would cause the current decorator to\n    * be called with '<script>' which would not match the same rule since\n    * group 1 must not be empty, so it would be instead styled as PR_TAG by\n    * the generic tag rule.  The handler registered for the 'js' extension would\n    * then be called with 'foo()', and finally, the current decorator would\n    * be called with '<\\/script>' which would not match the original rule and\n    * so the generic tag rule would identify it as a tag.\n    *\n    * Pattern must only match prefixes, and if it matches a prefix, then that\n    * match is considered a token with the same style.\n    *\n    * Context is applied to the last non-whitespace, non-comment token\n    * recognized.\n    *\n    * Shortcut is an optional string of characters, any of which, if the first\n    * character, gurantee that this pattern and only this pattern matches.\n    *\n    * @param {Array} shortcutStylePatterns patterns that always start with\n    *   a known character.  Must have a shortcut string.\n    * @param {Array} fallthroughStylePatterns patterns that will be tried in\n    *   order if the shortcut ones fail.  May have shortcuts.\n    *\n    * @return {function (Object)} a\n    *   function that takes source code and returns a list of decorations.\n    */\n  function createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns) {\n    var shortcuts = {};\n    var tokenizer;\n    (function () {\n      var allPatterns = shortcutStylePatterns.concat(fallthroughStylePatterns);\n      var allRegexs = [];\n      var regexKeys = {};\n      for (var i = 0, n = allPatterns.length; i < n; ++i) {\n        var patternParts = allPatterns[i];\n        var shortcutChars = patternParts[3];\n        if (shortcutChars) {\n          for (var c = shortcutChars.length; --c >= 0;) {\n            shortcuts[shortcutChars.charAt(c)] = patternParts;\n          }\n        }\n        var regex = patternParts[1];\n        var k = '' + regex;\n        if (!regexKeys.hasOwnProperty(k)) {\n          allRegexs.push(regex);\n          regexKeys[k] = null;\n        }\n      }\n      allRegexs.push(/[\\0-\\uffff]/);\n      tokenizer = combinePrefixPatterns(allRegexs);\n    })();\n\n    var nPatterns = fallthroughStylePatterns.length;\n\n    /**\n     * Lexes job.sourceCode and produces an output array job.decorations of\n     * style classes preceded by the position at which they start in\n     * job.sourceCode in order.\n     *\n     * @param {Object} job an object like <pre>{\n     *    sourceCode: {string} sourceText plain text,\n     *    basePos: {int} position of job.sourceCode in the larger chunk of\n     *        sourceCode.\n     * }</pre>\n     */\n    var decorate = function (job) {\n      var sourceCode = job.sourceCode, basePos = job.basePos;\n      /** Even entries are positions in source in ascending order.  Odd enties\n        * are style markers (e.g., PR_COMMENT) that run from that position until\n        * the end.\n        * @type {Array.<number|string>}\n        */\n      var decorations = [basePos, PR_PLAIN];\n      var pos = 0;  // index into sourceCode\n      var tokens = sourceCode.match(tokenizer) || [];\n      var styleCache = {};\n\n      for (var ti = 0, nTokens = tokens.length; ti < nTokens; ++ti) {\n        var token = tokens[ti];\n        var style = styleCache[token];\n        var match = void 0;\n\n        var isEmbedded;\n        if (typeof style === 'string') {\n          isEmbedded = false;\n        } else {\n          var patternParts = shortcuts[token.charAt(0)];\n          if (patternParts) {\n            match = token.match(patternParts[1]);\n            style = patternParts[0];\n          } else {\n            for (var i = 0; i < nPatterns; ++i) {\n              patternParts = fallthroughStylePatterns[i];\n              match = token.match(patternParts[1]);\n              if (match) {\n                style = patternParts[0];\n                break;\n              }\n            }\n\n            if (!match) {  // make sure that we make progress\n              style = PR_PLAIN;\n            }\n          }\n\n          isEmbedded = style.length >= 5 && 'lang-' === style.substring(0, 5);\n          if (isEmbedded && !(match && typeof match[1] === 'string')) {\n            isEmbedded = false;\n            style = PR_SOURCE;\n          }\n\n          if (!isEmbedded) { styleCache[token] = style; }\n        }\n\n        var tokenStart = pos;\n        pos += token.length;\n\n        if (!isEmbedded) {\n          decorations.push(basePos + tokenStart, style);\n        } else {  // Treat group 1 as an embedded block of source code.\n          var embeddedSource = match[1];\n          var embeddedSourceStart = token.indexOf(embeddedSource);\n          var embeddedSourceEnd = embeddedSourceStart + embeddedSource.length;\n          if (match[2]) {\n            // If embeddedSource can be blank, then it would match at the\n            // beginning which would cause us to infinitely recurse on the\n            // entire token, so we catch the right context in match[2].\n            embeddedSourceEnd = token.length - match[2].length;\n            embeddedSourceStart = embeddedSourceEnd - embeddedSource.length;\n          }\n          var lang = style.substring(5);\n          // Decorate the left of the embedded source\n          appendDecorations(\n              basePos + tokenStart,\n              token.substring(0, embeddedSourceStart),\n              decorate, decorations);\n          // Decorate the embedded source\n          appendDecorations(\n              basePos + tokenStart + embeddedSourceStart,\n              embeddedSource,\n              langHandlerForExtension(lang, embeddedSource),\n              decorations);\n          // Decorate the right of the embedded section\n          appendDecorations(\n              basePos + tokenStart + embeddedSourceEnd,\n              token.substring(embeddedSourceEnd),\n              decorate, decorations);\n        }\n      }\n      job.decorations = decorations;\n    };\n    return decorate;\n  }\n\n  /** returns a function that produces a list of decorations from source text.\n    *\n    * This code treats \", ', and ` as string delimiters, and \\ as a string\n    * escape.  It does not recognize perl's qq() style strings.\n    * It has no special handling for double delimiter escapes as in basic, or\n    * the tripled delimiters used in python, but should work on those regardless\n    * although in those cases a single string literal may be broken up into\n    * multiple adjacent string literals.\n    *\n    * It recognizes C, C++, and shell style comments.\n    *\n    * @param {Object} options a set of optional parameters.\n    * @return {function (Object)} a function that examines the source code\n    *     in the input job and builds the decoration list.\n    */\n  function sourceDecorator(options) {\n    var shortcutStylePatterns = [], fallthroughStylePatterns = [];\n    if (options['tripleQuotedStrings']) {\n      // '''multi-line-string''', 'single-line-string', and double-quoted\n      shortcutStylePatterns.push(\n          [PR_STRING,  /^(?:\\'\\'\\'(?:[^\\'\\\\]|\\\\[\\s\\S]|\\'{1,2}(?=[^\\']))*(?:\\'\\'\\'|$)|\\\"\\\"\\\"(?:[^\\\"\\\\]|\\\\[\\s\\S]|\\\"{1,2}(?=[^\\\"]))*(?:\\\"\\\"\\\"|$)|\\'(?:[^\\\\\\']|\\\\[\\s\\S])*(?:\\'|$)|\\\"(?:[^\\\\\\\"]|\\\\[\\s\\S])*(?:\\\"|$))/,\n           null, '\\'\"']);\n    } else if (options['multiLineStrings']) {\n      // 'multi-line-string', \"multi-line-string\"\n      shortcutStylePatterns.push(\n          [PR_STRING,  /^(?:\\'(?:[^\\\\\\']|\\\\[\\s\\S])*(?:\\'|$)|\\\"(?:[^\\\\\\\"]|\\\\[\\s\\S])*(?:\\\"|$)|\\`(?:[^\\\\\\`]|\\\\[\\s\\S])*(?:\\`|$))/,\n           null, '\\'\"`']);\n    } else {\n      // 'single-line-string', \"single-line-string\"\n      shortcutStylePatterns.push(\n          [PR_STRING,\n           /^(?:\\'(?:[^\\\\\\'\\r\\n]|\\\\.)*(?:\\'|$)|\\\"(?:[^\\\\\\\"\\r\\n]|\\\\.)*(?:\\\"|$))/,\n           null, '\"\\'']);\n    }\n    if (options['verbatimStrings']) {\n      // verbatim-string-literal production from the C# grammar.  See issue 93.\n      fallthroughStylePatterns.push(\n          [PR_STRING, /^@\\\"(?:[^\\\"]|\\\"\\\")*(?:\\\"|$)/, null]);\n    }\n    var hc = options['hashComments'];\n    if (hc) {\n      if (options['cStyleComments']) {\n        if (hc > 1) {  // multiline hash comments\n          shortcutStylePatterns.push(\n              [PR_COMMENT, /^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/, null, '#']);\n        } else {\n          // Stop C preprocessor declarations at an unclosed open comment\n          shortcutStylePatterns.push(\n              [PR_COMMENT, /^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\\b|[^\\r\\n]*)/,\n               null, '#']);\n        }\n        // #include <stdio.h>\n        fallthroughStylePatterns.push(\n            [PR_STRING,\n             /^<(?:(?:(?:\\.\\.\\/)*|\\/?)(?:[\\w-]+(?:\\/[\\w-]+)+)?[\\w-]+\\.h(?:h|pp|\\+\\+)?|[a-z]\\w*)>/,\n             null]);\n      } else {\n        shortcutStylePatterns.push([PR_COMMENT, /^#[^\\r\\n]*/, null, '#']);\n      }\n    }\n    if (options['cStyleComments']) {\n      fallthroughStylePatterns.push([PR_COMMENT, /^\\/\\/[^\\r\\n]*/, null]);\n      fallthroughStylePatterns.push(\n          [PR_COMMENT, /^\\/\\*[\\s\\S]*?(?:\\*\\/|$)/, null]);\n    }\n    var regexLiterals = options['regexLiterals'];\n    if (regexLiterals) {\n      /**\n       * @const\n       */\n      var regexExcls = regexLiterals > 1\n        ? ''  // Multiline regex literals\n        : '\\n\\r';\n      /**\n       * @const\n       */\n      var regexAny = regexExcls ? '.' : '[\\\\S\\\\s]';\n      /**\n       * @const\n       */\n      var REGEX_LITERAL = (\n          // A regular expression literal starts with a slash that is\n          // not followed by * or / so that it is not confused with\n          // comments.\n          '/(?=[^/*' + regexExcls + '])'\n          // and then contains any number of raw characters,\n          + '(?:[^/\\\\x5B\\\\x5C' + regexExcls + ']'\n          // escape sequences (\\x5C),\n          +    '|\\\\x5C' + regexAny\n          // or non-nesting character sets (\\x5B\\x5D);\n          +    '|\\\\x5B(?:[^\\\\x5C\\\\x5D' + regexExcls + ']'\n          +             '|\\\\x5C' + regexAny + ')*(?:\\\\x5D|$))+'\n          // finally closed by a /.\n          + '/');\n      fallthroughStylePatterns.push(\n          ['lang-regex',\n           RegExp('^' + REGEXP_PRECEDER_PATTERN + '(' + REGEX_LITERAL + ')')\n           ]);\n    }\n\n    var types = options['types'];\n    if (types) {\n      fallthroughStylePatterns.push([PR_TYPE, types]);\n    }\n\n    var keywords = (\"\" + options['keywords']).replace(/^ | $/g, '');\n    if (keywords.length) {\n      fallthroughStylePatterns.push(\n          [PR_KEYWORD,\n           new RegExp('^(?:' + keywords.replace(/[\\s,]+/g, '|') + ')\\\\b'),\n           null]);\n    }\n\n    shortcutStylePatterns.push([PR_PLAIN,       /^\\s+/, null, ' \\r\\n\\t\\xA0']);\n\n    var punctuation =\n      // The Bash man page says\n\n      // A word is a sequence of characters considered as a single\n      // unit by GRUB. Words are separated by metacharacters,\n      // which are the following plus space, tab, and newline: { }\n      // | & $ ; < >\n      // ...\n      \n      // A word beginning with # causes that word and all remaining\n      // characters on that line to be ignored.\n\n      // which means that only a '#' after /(?:^|[{}|&$;<>\\s])/ starts a\n      // comment but empirically\n      // $ echo {#}\n      // {#}\n      // $ echo \\$#\n      // $#\n      // $ echo }#\n      // }#\n\n      // so /(?:^|[|&;<>\\s])/ is more appropriate.\n\n      // http://gcc.gnu.org/onlinedocs/gcc-2.95.3/cpp_1.html#SEC3\n      // suggests that this definition is compatible with a\n      // default mode that tries to use a single token definition\n      // to recognize both bash/python style comments and C\n      // preprocessor directives.\n\n      // This definition of punctuation does not include # in the list of\n      // follow-on exclusions, so # will not be broken before if preceeded\n      // by a punctuation character.  We could try to exclude # after\n      // [|&;<>] but that doesn't seem to cause many major problems.\n      // If that does turn out to be a problem, we should change the below\n      // when hc is truthy to include # in the run of punctuation characters\n      // only when not followint [|&;<>].\n      '^.[^\\\\s\\\\w.$@\\'\"`/\\\\\\\\]*';\n    if (options['regexLiterals']) {\n      punctuation += '(?!\\s*\\/)';\n    }\n\n    fallthroughStylePatterns.push(\n        // TODO(mikesamuel): recognize non-latin letters and numerals in idents\n        [PR_LITERAL,     /^@[a-z_$][a-z_$@0-9]*/i, null],\n        [PR_TYPE,        /^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\\w+_t\\b)/, null],\n        [PR_PLAIN,       /^[a-z_$][a-z_$@0-9]*/i, null],\n        [PR_LITERAL,\n         new RegExp(\n             '^(?:'\n             // A hex number\n             + '0x[a-f0-9]+'\n             // or an octal or decimal number,\n             + '|(?:\\\\d(?:_\\\\d+)*\\\\d*(?:\\\\.\\\\d*)?|\\\\.\\\\d\\\\+)'\n             // possibly in scientific notation\n             + '(?:e[+\\\\-]?\\\\d+)?'\n             + ')'\n             // with an optional modifier like UL for unsigned long\n             + '[a-z]*', 'i'),\n         null, '0123456789'],\n        // Don't treat escaped quotes in bash as starting strings.\n        // See issue 144.\n        [PR_PLAIN,       /^\\\\[\\s\\S]?/, null],\n        [PR_PUNCTUATION, new RegExp(punctuation), null]);\n\n    return createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns);\n  }\n\n  var decorateSource = sourceDecorator({\n        'keywords': ALL_KEYWORDS,\n        'hashComments': true,\n        'cStyleComments': true,\n        'multiLineStrings': true,\n        'regexLiterals': true\n      });\n\n  /**\n   * Given a DOM subtree, wraps it in a list, and puts each line into its own\n   * list item.\n   *\n   * @param {Node} node modified in place.  Its content is pulled into an\n   *     HTMLOListElement, and each line is moved into a separate list item.\n   *     This requires cloning elements, so the input might not have unique\n   *     IDs after numbering.\n   * @param {boolean} isPreformatted true iff white-space in text nodes should\n   *     be treated as significant.\n   */\n  function numberLines(node, opt_startLineNum, isPreformatted) {\n    var nocode = /(?:^|\\s)nocode(?:\\s|$)/;\n    var lineBreak = /\\r\\n?|\\n/;\n  \n    var document = node.ownerDocument;\n  \n    var li = document.createElement('li');\n    while (node.firstChild) {\n      li.appendChild(node.firstChild);\n    }\n    // An array of lines.  We split below, so this is initialized to one\n    // un-split line.\n    var listItems = [li];\n  \n    function walk(node) {\n      var type = node.nodeType;\n      if (type == 1 && !nocode.test(node.className)) {  // Element\n        if ('br' === node.nodeName) {\n          breakAfter(node);\n          // Discard the <BR> since it is now flush against a </LI>.\n          if (node.parentNode) {\n            node.parentNode.removeChild(node);\n          }\n        } else {\n          for (var child = node.firstChild; child; child = child.nextSibling) {\n            walk(child);\n          }\n        }\n      } else if ((type == 3 || type == 4) && isPreformatted) {  // Text\n        var text = node.nodeValue;\n        var match = text.match(lineBreak);\n        if (match) {\n          var firstLine = text.substring(0, match.index);\n          node.nodeValue = firstLine;\n          var tail = text.substring(match.index + match[0].length);\n          if (tail) {\n            var parent = node.parentNode;\n            parent.insertBefore(\n              document.createTextNode(tail), node.nextSibling);\n          }\n          breakAfter(node);\n          if (!firstLine) {\n            // Don't leave blank text nodes in the DOM.\n            node.parentNode.removeChild(node);\n          }\n        }\n      }\n    }\n  \n    // Split a line after the given node.\n    function breakAfter(lineEndNode) {\n      // If there's nothing to the right, then we can skip ending the line\n      // here, and move root-wards since splitting just before an end-tag\n      // would require us to create a bunch of empty copies.\n      while (!lineEndNode.nextSibling) {\n        lineEndNode = lineEndNode.parentNode;\n        if (!lineEndNode) { return; }\n      }\n  \n      function breakLeftOf(limit, copy) {\n        // Clone shallowly if this node needs to be on both sides of the break.\n        var rightSide = copy ? limit.cloneNode(false) : limit;\n        var parent = limit.parentNode;\n        if (parent) {\n          // We clone the parent chain.\n          // This helps us resurrect important styling elements that cross lines.\n          // E.g. in <i>Foo<br>Bar</i>\n          // should be rewritten to <li><i>Foo</i></li><li><i>Bar</i></li>.\n          var parentClone = breakLeftOf(parent, 1);\n          // Move the clone and everything to the right of the original\n          // onto the cloned parent.\n          var next = limit.nextSibling;\n          parentClone.appendChild(rightSide);\n          for (var sibling = next; sibling; sibling = next) {\n            next = sibling.nextSibling;\n            parentClone.appendChild(sibling);\n          }\n        }\n        return rightSide;\n      }\n  \n      var copiedListItem = breakLeftOf(lineEndNode.nextSibling, 0);\n  \n      // Walk the parent chain until we reach an unattached LI.\n      for (var parent;\n           // Check nodeType since IE invents document fragments.\n           (parent = copiedListItem.parentNode) && parent.nodeType === 1;) {\n        copiedListItem = parent;\n      }\n      // Put it on the list of lines for later processing.\n      listItems.push(copiedListItem);\n    }\n  \n    // Split lines while there are lines left to split.\n    for (var i = 0;  // Number of lines that have been split so far.\n         i < listItems.length;  // length updated by breakAfter calls.\n         ++i) {\n      walk(listItems[i]);\n    }\n  \n    // Make sure numeric indices show correctly.\n    if (opt_startLineNum === (opt_startLineNum|0)) {\n      listItems[0].setAttribute('value', opt_startLineNum);\n    }\n  \n    var ol = document.createElement('ol');\n    ol.className = 'linenums';\n    var offset = Math.max(0, ((opt_startLineNum - 1 /* zero index */)) | 0) || 0;\n    for (var i = 0, n = listItems.length; i < n; ++i) {\n      li = listItems[i];\n      // Stick a class on the LIs so that stylesheets can\n      // color odd/even rows, or any other row pattern that\n      // is co-prime with 10.\n      li.className = 'L' + ((i + offset) % 10);\n      if (!li.firstChild) {\n        li.appendChild(document.createTextNode('\\xA0'));\n      }\n      ol.appendChild(li);\n    }\n  \n    node.appendChild(ol);\n  }\n  /**\n   * Breaks {@code job.sourceCode} around style boundaries in\n   * {@code job.decorations} and modifies {@code job.sourceNode} in place.\n   * @param {Object} job like <pre>{\n   *    sourceCode: {string} source as plain text,\n   *    sourceNode: {HTMLElement} the element containing the source,\n   *    spans: {Array.<number|Node>} alternating span start indices into source\n   *       and the text node or element (e.g. {@code <BR>}) corresponding to that\n   *       span.\n   *    decorations: {Array.<number|string} an array of style classes preceded\n   *       by the position at which they start in job.sourceCode in order\n   * }</pre>\n   * @private\n   */\n  function recombineTagsAndDecorations(job) {\n    var isIE8OrEarlier = /\\bMSIE\\s(\\d+)/.exec(navigator.userAgent);\n    isIE8OrEarlier = isIE8OrEarlier && +isIE8OrEarlier[1] <= 8;\n    var newlineRe = /\\n/g;\n  \n    var source = job.sourceCode;\n    var sourceLength = source.length;\n    // Index into source after the last code-unit recombined.\n    var sourceIndex = 0;\n  \n    var spans = job.spans;\n    var nSpans = spans.length;\n    // Index into spans after the last span which ends at or before sourceIndex.\n    var spanIndex = 0;\n  \n    var decorations = job.decorations;\n    var nDecorations = decorations.length;\n    // Index into decorations after the last decoration which ends at or before\n    // sourceIndex.\n    var decorationIndex = 0;\n  \n    // Remove all zero-length decorations.\n    decorations[nDecorations] = sourceLength;\n    var decPos, i;\n    for (i = decPos = 0; i < nDecorations;) {\n      if (decorations[i] !== decorations[i + 2]) {\n        decorations[decPos++] = decorations[i++];\n        decorations[decPos++] = decorations[i++];\n      } else {\n        i += 2;\n      }\n    }\n    nDecorations = decPos;\n  \n    // Simplify decorations.\n    for (i = decPos = 0; i < nDecorations;) {\n      var startPos = decorations[i];\n      // Conflate all adjacent decorations that use the same style.\n      var startDec = decorations[i + 1];\n      var end = i + 2;\n      while (end + 2 <= nDecorations && decorations[end + 1] === startDec) {\n        end += 2;\n      }\n      decorations[decPos++] = startPos;\n      decorations[decPos++] = startDec;\n      i = end;\n    }\n  \n    nDecorations = decorations.length = decPos;\n  \n    var sourceNode = job.sourceNode;\n    var oldDisplay;\n    if (sourceNode) {\n      oldDisplay = sourceNode.style.display;\n      sourceNode.style.display = 'none';\n    }\n    try {\n      var decoration = null;\n      while (spanIndex < nSpans) {\n        var spanStart = spans[spanIndex];\n        var spanEnd = spans[spanIndex + 2] || sourceLength;\n  \n        var decEnd = decorations[decorationIndex + 2] || sourceLength;\n  \n        var end = Math.min(spanEnd, decEnd);\n  \n        var textNode = spans[spanIndex + 1];\n        var styledText;\n        if (textNode.nodeType !== 1  // Don't muck with <BR>s or <LI>s\n            // Don't introduce spans around empty text nodes.\n            && (styledText = source.substring(sourceIndex, end))) {\n          // This may seem bizarre, and it is.  Emitting LF on IE causes the\n          // code to display with spaces instead of line breaks.\n          // Emitting Windows standard issue linebreaks (CRLF) causes a blank\n          // space to appear at the beginning of every line but the first.\n          // Emitting an old Mac OS 9 line separator makes everything spiffy.\n          if (isIE8OrEarlier) {\n            styledText = styledText.replace(newlineRe, '\\r');\n          }\n          textNode.nodeValue = styledText;\n          var document = textNode.ownerDocument;\n          var span = document.createElement('span');\n          span.className = decorations[decorationIndex + 1];\n          var parentNode = textNode.parentNode;\n          parentNode.replaceChild(span, textNode);\n          span.appendChild(textNode);\n          if (sourceIndex < spanEnd) {  // Split off a text node.\n            spans[spanIndex + 1] = textNode\n                // TODO: Possibly optimize by using '' if there's no flicker.\n                = document.createTextNode(source.substring(end, spanEnd));\n            parentNode.insertBefore(textNode, span.nextSibling);\n          }\n        }\n  \n        sourceIndex = end;\n  \n        if (sourceIndex >= spanEnd) {\n          spanIndex += 2;\n        }\n        if (sourceIndex >= decEnd) {\n          decorationIndex += 2;\n        }\n      }\n    } finally {\n      if (sourceNode) {\n        sourceNode.style.display = oldDisplay;\n      }\n    }\n  }\n\n  /** Maps language-specific file extensions to handlers. */\n  var langHandlerRegistry = {};\n  /** Register a language handler for the given file extensions.\n    * @param {function (Object)} handler a function from source code to a list\n    *      of decorations.  Takes a single argument job which describes the\n    *      state of the computation.   The single parameter has the form\n    *      {@code {\n    *        sourceCode: {string} as plain text.\n    *        decorations: {Array.<number|string>} an array of style classes\n    *                     preceded by the position at which they start in\n    *                     job.sourceCode in order.\n    *                     The language handler should assigned this field.\n    *        basePos: {int} the position of source in the larger source chunk.\n    *                 All positions in the output decorations array are relative\n    *                 to the larger source chunk.\n    *      } }\n    * @param {Array.<string>} fileExtensions\n    */\n  function registerLangHandler(handler, fileExtensions) {\n    for (var i = fileExtensions.length; --i >= 0;) {\n      var ext = fileExtensions[i];\n      if (!langHandlerRegistry.hasOwnProperty(ext)) {\n        langHandlerRegistry[ext] = handler;\n      } else if (win['console']) {\n        console['warn']('cannot override language handler %s', ext);\n      }\n    }\n  }\n  function langHandlerForExtension(extension, source) {\n    if (!(extension && langHandlerRegistry.hasOwnProperty(extension))) {\n      // Treat it as markup if the first non whitespace character is a < and\n      // the last non-whitespace character is a >.\n      extension = /^\\s*</.test(source)\n          ? 'default-markup'\n          : 'default-code';\n    }\n    return langHandlerRegistry[extension];\n  }\n  registerLangHandler(decorateSource, ['default-code']);\n  registerLangHandler(\n      createSimpleLexer(\n          [],\n          [\n           [PR_PLAIN,       /^[^<?]+/],\n           [PR_DECLARATION, /^<!\\w[^>]*(?:>|$)/],\n           [PR_COMMENT,     /^<\\!--[\\s\\S]*?(?:-\\->|$)/],\n           // Unescaped content in an unknown language\n           ['lang-',        /^<\\?([\\s\\S]+?)(?:\\?>|$)/],\n           ['lang-',        /^<%([\\s\\S]+?)(?:%>|$)/],\n           [PR_PUNCTUATION, /^(?:<[%?]|[%?]>)/],\n           ['lang-',        /^<xmp\\b[^>]*>([\\s\\S]+?)<\\/xmp\\b[^>]*>/i],\n           // Unescaped content in javascript.  (Or possibly vbscript).\n           ['lang-js',      /^<script\\b[^>]*>([\\s\\S]*?)(<\\/script\\b[^>]*>)/i],\n           // Contains unescaped stylesheet content\n           ['lang-css',     /^<style\\b[^>]*>([\\s\\S]*?)(<\\/style\\b[^>]*>)/i],\n           ['lang-in.tag',  /^(<\\/?[a-z][^<>]*>)/i]\n          ]),\n      ['default-markup', 'htm', 'html', 'mxml', 'xhtml', 'xml', 'xsl']);\n  registerLangHandler(\n      createSimpleLexer(\n          [\n           [PR_PLAIN,        /^[\\s]+/, null, ' \\t\\r\\n'],\n           [PR_ATTRIB_VALUE, /^(?:\\\"[^\\\"]*\\\"?|\\'[^\\']*\\'?)/, null, '\\\"\\'']\n           ],\n          [\n           [PR_TAG,          /^^<\\/?[a-z](?:[\\w.:-]*\\w)?|\\/?>$/i],\n           [PR_ATTRIB_NAME,  /^(?!style[\\s=]|on)[a-z](?:[\\w:-]*\\w)?/i],\n           ['lang-uq.val',   /^=\\s*([^>\\'\\\"\\s]*(?:[^>\\'\\\"\\s\\/]|\\/(?=\\s)))/],\n           [PR_PUNCTUATION,  /^[=<>\\/]+/],\n           ['lang-js',       /^on\\w+\\s*=\\s*\\\"([^\\\"]+)\\\"/i],\n           ['lang-js',       /^on\\w+\\s*=\\s*\\'([^\\']+)\\'/i],\n           ['lang-js',       /^on\\w+\\s*=\\s*([^\\\"\\'>\\s]+)/i],\n           ['lang-css',      /^style\\s*=\\s*\\\"([^\\\"]+)\\\"/i],\n           ['lang-css',      /^style\\s*=\\s*\\'([^\\']+)\\'/i],\n           ['lang-css',      /^style\\s*=\\s*([^\\\"\\'>\\s]+)/i]\n           ]),\n      ['in.tag']);\n  registerLangHandler(\n      createSimpleLexer([], [[PR_ATTRIB_VALUE, /^[\\s\\S]+/]]), ['uq.val']);\n  registerLangHandler(sourceDecorator({\n          'keywords': CPP_KEYWORDS,\n          'hashComments': true,\n          'cStyleComments': true,\n          'types': C_TYPES\n        }), ['c', 'cc', 'cpp', 'cxx', 'cyc', 'm']);\n  registerLangHandler(sourceDecorator({\n          'keywords': 'null,true,false'\n        }), ['json']);\n  registerLangHandler(sourceDecorator({\n          'keywords': CSHARP_KEYWORDS,\n          'hashComments': true,\n          'cStyleComments': true,\n          'verbatimStrings': true,\n          'types': C_TYPES\n        }), ['cs']);\n  registerLangHandler(sourceDecorator({\n          'keywords': JAVA_KEYWORDS,\n          'cStyleComments': true\n        }), ['java']);\n  registerLangHandler(sourceDecorator({\n          'keywords': SH_KEYWORDS,\n          'hashComments': true,\n          'multiLineStrings': true\n        }), ['bash', 'bsh', 'csh', 'sh']);\n  registerLangHandler(sourceDecorator({\n          'keywords': PYTHON_KEYWORDS,\n          'hashComments': true,\n          'multiLineStrings': true,\n          'tripleQuotedStrings': true\n        }), ['cv', 'py', 'python']);\n  registerLangHandler(sourceDecorator({\n          'keywords': PERL_KEYWORDS,\n          'hashComments': true,\n          'multiLineStrings': true,\n          'regexLiterals': 2  // multiline regex literals\n        }), ['perl', 'pl', 'pm']);\n  registerLangHandler(sourceDecorator({\n          'keywords': RUBY_KEYWORDS,\n          'hashComments': true,\n          'multiLineStrings': true,\n          'regexLiterals': true\n        }), ['rb', 'ruby']);\n  registerLangHandler(sourceDecorator({\n          'keywords': JSCRIPT_KEYWORDS,\n          'cStyleComments': true,\n          'regexLiterals': true\n        }), ['javascript', 'js']);\n  registerLangHandler(sourceDecorator({\n          'keywords': COFFEE_KEYWORDS,\n          'hashComments': 3,  // ### style block comments\n          'cStyleComments': true,\n          'multilineStrings': true,\n          'tripleQuotedStrings': true,\n          'regexLiterals': true\n        }), ['coffee']);\n  registerLangHandler(sourceDecorator({\n          'keywords': RUST_KEYWORDS,\n          'cStyleComments': true,\n          'multilineStrings': true\n        }), ['rc', 'rs', 'rust']);\n  registerLangHandler(\n      createSimpleLexer([], [[PR_STRING, /^[\\s\\S]+/]]), ['regex']);\n\n  function applyDecorator(job) {\n    var opt_langExtension = job.langExtension;\n\n    try {\n      // Extract tags, and convert the source code to plain text.\n      var sourceAndSpans = extractSourceSpans(job.sourceNode, job.pre);\n      /** Plain text. @type {string} */\n      var source = sourceAndSpans.sourceCode;\n      job.sourceCode = source;\n      job.spans = sourceAndSpans.spans;\n      job.basePos = 0;\n\n      // Apply the appropriate language handler\n      langHandlerForExtension(opt_langExtension, source)(job);\n\n      // Integrate the decorations and tags back into the source code,\n      // modifying the sourceNode in place.\n      recombineTagsAndDecorations(job);\n    } catch (e) {\n      if (win['console']) {\n        console['log'](e && e['stack'] || e);\n      }\n    }\n  }\n\n  /**\n   * Pretty print a chunk of code.\n   * @param sourceCodeHtml {string} The HTML to pretty print.\n   * @param opt_langExtension {string} The language name to use.\n   *     Typically, a filename extension like 'cpp' or 'java'.\n   * @param opt_numberLines {number|boolean} True to number lines,\n   *     or the 1-indexed number of the first line in sourceCodeHtml.\n   */\n  function $prettyPrintOne(sourceCodeHtml, opt_langExtension, opt_numberLines) {\n    var container = document.createElement('div');\n    // This could cause images to load and onload listeners to fire.\n    // E.g. <img onerror=\"alert(1337)\" src=\"nosuchimage.png\">.\n    // We assume that the inner HTML is from a trusted source.\n    // The pre-tag is required for IE8 which strips newlines from innerHTML\n    // when it is injected into a <pre> tag.\n    // http://stackoverflow.com/questions/451486/pre-tag-loses-line-breaks-when-setting-innerhtml-in-ie\n    // http://stackoverflow.com/questions/195363/inserting-a-newline-into-a-pre-tag-ie-javascript\n    container.innerHTML = '<pre>' + sourceCodeHtml + '</pre>';\n    container = container.firstChild;\n    if (opt_numberLines) {\n      numberLines(container, opt_numberLines, true);\n    }\n\n    var job = {\n      langExtension: opt_langExtension,\n      numberLines: opt_numberLines,\n      sourceNode: container,\n      pre: 1\n    };\n    applyDecorator(job);\n    return container.innerHTML;\n  }\n\n   /**\n    * Find all the {@code <pre>} and {@code <code>} tags in the DOM with\n    * {@code class=prettyprint} and prettify them.\n    *\n    * @param {Function} opt_whenDone called when prettifying is done.\n    * @param {HTMLElement|HTMLDocument} opt_root an element or document\n    *   containing all the elements to pretty print.\n    *   Defaults to {@code document.body}.\n    */\n  function $prettyPrint(opt_whenDone, opt_root) {\n    var root = opt_root || document.body;\n    var doc = root.ownerDocument || document;\n    function byTagName(tn) { return root.getElementsByTagName(tn); }\n    // fetch a list of nodes to rewrite\n    var codeSegments = [byTagName('pre'), byTagName('code'), byTagName('xmp')];\n    var elements = [];\n    for (var i = 0; i < codeSegments.length; ++i) {\n      for (var j = 0, n = codeSegments[i].length; j < n; ++j) {\n        elements.push(codeSegments[i][j]);\n      }\n    }\n    codeSegments = null;\n\n    var clock = Date;\n    if (!clock['now']) {\n      clock = { 'now': function () { return +(new Date); } };\n    }\n\n    // The loop is broken into a series of continuations to make sure that we\n    // don't make the browser unresponsive when rewriting a large page.\n    var k = 0;\n    var prettyPrintingJob;\n\n    var langExtensionRe = /\\blang(?:uage)?-([\\w.]+)(?!\\S)/;\n    var prettyPrintRe = /\\bprettyprint\\b/;\n    var prettyPrintedRe = /\\bprettyprinted\\b/;\n    var preformattedTagNameRe = /pre|xmp/i;\n    var codeRe = /^code$/i;\n    var preCodeXmpRe = /^(?:pre|code|xmp)$/i;\n    var EMPTY = {};\n\n    function doWork() {\n      var endTime = (win['PR_SHOULD_USE_CONTINUATION'] ?\n                     clock['now']() + 250 /* ms */ :\n                     Infinity);\n      for (; k < elements.length && clock['now']() < endTime; k++) {\n        var cs = elements[k];\n\n        // Look for a preceding comment like\n        // <?prettify lang=\"...\" linenums=\"...\"?>\n        var attrs = EMPTY;\n        {\n          for (var preceder = cs; (preceder = preceder.previousSibling);) {\n            var nt = preceder.nodeType;\n            // <?foo?> is parsed by HTML 5 to a comment node (8)\n            // like <!--?foo?-->, but in XML is a processing instruction\n            var value = (nt === 7 || nt === 8) && preceder.nodeValue;\n            if (value\n                ? !/^\\??prettify\\b/.test(value)\n                : (nt !== 3 || /\\S/.test(preceder.nodeValue))) {\n              // Skip over white-space text nodes but not others.\n              break;\n            }\n            if (value) {\n              attrs = {};\n              value.replace(\n                  /\\b(\\w+)=([\\w:.%+-]+)/g,\n                function (_, name, value) { attrs[name] = value; });\n              break;\n            }\n          }\n        }\n\n        var className = cs.className;\n        if ((attrs !== EMPTY || prettyPrintRe.test(className))\n            // Don't redo this if we've already done it.\n            // This allows recalling pretty print to just prettyprint elements\n            // that have been added to the page since last call.\n            && !prettyPrintedRe.test(className)) {\n\n          // make sure this is not nested in an already prettified element\n          var nested = false;\n          for (var p = cs.parentNode; p; p = p.parentNode) {\n            var tn = p.tagName;\n            if (preCodeXmpRe.test(tn)\n                && p.className && prettyPrintRe.test(p.className)) {\n              nested = true;\n              break;\n            }\n          }\n          if (!nested) {\n            // Mark done.  If we fail to prettyprint for whatever reason,\n            // we shouldn't try again.\n            cs.className += ' prettyprinted';\n\n            // If the classes includes a language extensions, use it.\n            // Language extensions can be specified like\n            //     <pre class=\"prettyprint lang-cpp\">\n            // the language extension \"cpp\" is used to find a language handler\n            // as passed to PR.registerLangHandler.\n            // HTML5 recommends that a language be specified using \"language-\"\n            // as the prefix instead.  Google Code Prettify supports both.\n            // http://dev.w3.org/html5/spec-author-view/the-code-element.html\n            var langExtension = attrs['lang'];\n            if (!langExtension) {\n              langExtension = className.match(langExtensionRe);\n              // Support <pre class=\"prettyprint\"><code class=\"language-c\">\n              var wrapper;\n              if (!langExtension && (wrapper = childContentWrapper(cs))\n                  && codeRe.test(wrapper.tagName)) {\n                langExtension = wrapper.className.match(langExtensionRe);\n              }\n\n              if (langExtension) { langExtension = langExtension[1]; }\n            }\n\n            var preformatted;\n            if (preformattedTagNameRe.test(cs.tagName)) {\n              preformatted = 1;\n            } else {\n              var currentStyle = cs['currentStyle'];\n              var defaultView = doc.defaultView;\n              var whitespace = (\n                  currentStyle\n                  ? currentStyle['whiteSpace']\n                  : (defaultView\n                     && defaultView.getComputedStyle)\n                  ? defaultView.getComputedStyle(cs, null)\n                  .getPropertyValue('white-space')\n                  : 0);\n              preformatted = whitespace\n                  && 'pre' === whitespace.substring(0, 3);\n            }\n\n            // Look for a class like linenums or linenums:<n> where <n> is the\n            // 1-indexed number of the first line.\n            var lineNums = attrs['linenums'];\n            if (!(lineNums = lineNums === 'true' || +lineNums)) {\n              lineNums = className.match(/\\blinenums\\b(?::(\\d+))?/);\n              lineNums =\n                lineNums\n                ? lineNums[1] && lineNums[1].length\n                  ? +lineNums[1] : true\n                : false;\n            }\n            if (lineNums) { numberLines(cs, lineNums, preformatted); }\n\n            // do the pretty printing\n            prettyPrintingJob = {\n              langExtension: langExtension,\n              sourceNode: cs,\n              numberLines: lineNums,\n              pre: preformatted\n            };\n            applyDecorator(prettyPrintingJob);\n          }\n        }\n      }\n      if (k < elements.length) {\n        // finish up in a continuation\n        setTimeout(doWork, 250);\n      } else if ('function' === typeof opt_whenDone) {\n        opt_whenDone();\n      }\n    }\n\n    doWork();\n  }\n\n  /**\n   * Contains functions for creating and registering new language handlers.\n   * @type {Object}\n   */\n  var PR = win['PR'] = {\n        'createSimpleLexer': createSimpleLexer,\n        'registerLangHandler': registerLangHandler,\n        'sourceDecorator': sourceDecorator,\n        'PR_ATTRIB_NAME': PR_ATTRIB_NAME,\n        'PR_ATTRIB_VALUE': PR_ATTRIB_VALUE,\n        'PR_COMMENT': PR_COMMENT,\n        'PR_DECLARATION': PR_DECLARATION,\n        'PR_KEYWORD': PR_KEYWORD,\n        'PR_LITERAL': PR_LITERAL,\n        'PR_NOCODE': PR_NOCODE,\n        'PR_PLAIN': PR_PLAIN,\n        'PR_PUNCTUATION': PR_PUNCTUATION,\n        'PR_SOURCE': PR_SOURCE,\n        'PR_STRING': PR_STRING,\n        'PR_TAG': PR_TAG,\n        'PR_TYPE': PR_TYPE,\n        'prettyPrintOne':\n           IN_GLOBAL_SCOPE\n             ? (win['prettyPrintOne'] = $prettyPrintOne)\n             : (prettyPrintOne = $prettyPrintOne),\n        'prettyPrint': prettyPrint =\n           IN_GLOBAL_SCOPE\n             ? (win['prettyPrint'] = $prettyPrint)\n             : (prettyPrint = $prettyPrint)\n      };\n\n  // Make PR available via the Asynchronous Module Definition (AMD) API.\n  // Per https://github.com/amdjs/amdjs-api/wiki/AMD:\n  // The Asynchronous Module Definition (AMD) API specifies a\n  // mechanism for defining modules such that the module and its\n  // dependencies can be asynchronously loaded.\n  // ...\n  // To allow a clear indicator that a global define function (as\n  // needed for script src browser loading) conforms to the AMD API,\n  // any global define function SHOULD have a property called \"amd\"\n  // whose value is an object. This helps avoid conflict with any\n  // other existing JavaScript code that could have defined a define()\n  // function that does not conform to the AMD API.\n  if (typeof define === \"function\" && define['amd']) {\n    define(\"google-code-prettify\", [], function () {\n      return PR; \n    });\n  }\n})();\n\ndefine(\"prettify\", function(){});\n\n",
        +    "// Copyright (C) 2006 Google Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n\n/**\n * @fileoverview\n * some functions for browser-side pretty printing of code contained in html.\n *\n * <p>\n * For a fairly comprehensive set of languages see the\n * <a href=\"http://google-code-prettify.googlecode.com/svn/trunk/README.html#langs\">README</a>\n * file that came with this source.  At a minimum, the lexer should work on a\n * number of languages including C and friends, Java, Python, Bash, SQL, HTML,\n * XML, CSS, Javascript, and Makefiles.  It works passably on Ruby, PHP and Awk\n * and a subset of Perl, but, because of commenting conventions, doesn't work on\n * Smalltalk, Lisp-like, or CAML-like languages without an explicit lang class.\n * <p>\n * Usage: <ol>\n * <li> include this source file in an html page via\n *   {@code <script src=\"/path/to/prettify.js\"></script>}\n * <li> define style rules.  See the example page for examples.\n * <li> mark the {@code <pre>} and {@code <code>} tags in your source with\n *    {@code class=prettyprint.}\n *    You can also use the (html deprecated) {@code <xmp>} tag, but the pretty\n *    printer needs to do more substantial DOM manipulations to support that, so\n *    some css styles may not be preserved.\n * </ol>\n * That's it.  I wanted to keep the API as simple as possible, so there's no\n * need to specify which language the code is in, but if you wish, you can add\n * another class to the {@code <pre>} or {@code <code>} element to specify the\n * language, as in {@code <pre class=\"prettyprint lang-java\">}.  Any class that\n * starts with \"lang-\" followed by a file extension, specifies the file type.\n * See the \"lang-*.js\" files in this directory for code that implements\n * per-language file handlers.\n * <p>\n * Change log:<br>\n * cbeust, 2006/08/22\n * <blockquote>\n *   Java annotations (start with \"@\") are now captured as literals (\"lit\")\n * </blockquote>\n * @requires console\n */\n\n// JSLint declarations\n/*global console, document, navigator, setTimeout, window, define */\n\n/** @define {boolean} */\nvar IN_GLOBAL_SCOPE = true;\n\n/**\n * Split {@code prettyPrint} into multiple timeouts so as not to interfere with\n * UI events.\n * If set to {@code false}, {@code prettyPrint()} is synchronous.\n */\nwindow['PR_SHOULD_USE_CONTINUATION'] = true;\n\n/**\n * Pretty print a chunk of code.\n * @param {string} sourceCodeHtml The HTML to pretty print.\n * @param {string} opt_langExtension The language name to use.\n *     Typically, a filename extension like 'cpp' or 'java'.\n * @param {number|boolean} opt_numberLines True to number lines,\n *     or the 1-indexed number of the first line in sourceCodeHtml.\n * @return {string} code as html, but prettier\n */\nvar prettyPrintOne;\n/**\n * Find all the {@code <pre>} and {@code <code>} tags in the DOM with\n * {@code class=prettyprint} and prettify them.\n *\n * @param {Function} opt_whenDone called when prettifying is done.\n * @param {HTMLElement|HTMLDocument} opt_root an element or document\n *   containing all the elements to pretty print.\n *   Defaults to {@code document.body}.\n */\nvar prettyPrint;\n\n\n(function () {\n  var win = window;\n  // Keyword lists for various languages.\n  // We use things that coerce to strings to make them compact when minified\n  // and to defeat aggressive optimizers that fold large string constants.\n  var FLOW_CONTROL_KEYWORDS = [\"break,continue,do,else,for,if,return,while\"];\n  var C_KEYWORDS = [FLOW_CONTROL_KEYWORDS,\"auto,case,char,const,default,\" + \n      \"double,enum,extern,float,goto,inline,int,long,register,short,signed,\" +\n      \"sizeof,static,struct,switch,typedef,union,unsigned,void,volatile\"];\n  var COMMON_KEYWORDS = [C_KEYWORDS,\"catch,class,delete,false,import,\" +\n      \"new,operator,private,protected,public,this,throw,true,try,typeof\"];\n  var CPP_KEYWORDS = [COMMON_KEYWORDS,\"alignof,align_union,asm,axiom,bool,\" +\n      \"concept,concept_map,const_cast,constexpr,decltype,delegate,\" +\n      \"dynamic_cast,explicit,export,friend,generic,late_check,\" +\n      \"mutable,namespace,nullptr,property,reinterpret_cast,static_assert,\" +\n      \"static_cast,template,typeid,typename,using,virtual,where\"];\n  var JAVA_KEYWORDS = [COMMON_KEYWORDS,\n      \"abstract,assert,boolean,byte,extends,final,finally,implements,import,\" +\n      \"instanceof,interface,null,native,package,strictfp,super,synchronized,\" +\n      \"throws,transient\"];\n  var CSHARP_KEYWORDS = [JAVA_KEYWORDS,\n      \"as,base,by,checked,decimal,delegate,descending,dynamic,event,\" +\n      \"fixed,foreach,from,group,implicit,in,internal,into,is,let,\" +\n      \"lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,\" +\n      \"sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,\" +\n      \"var,virtual,where\"];\n  var COFFEE_KEYWORDS = \"all,and,by,catch,class,else,extends,false,finally,\" +\n      \"for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,\" +\n      \"throw,true,try,unless,until,when,while,yes\";\n  var JSCRIPT_KEYWORDS = [COMMON_KEYWORDS,\n      \"debugger,eval,export,function,get,null,set,undefined,var,with,\" +\n      \"Infinity,NaN\"];\n  var PERL_KEYWORDS = \"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,\" +\n      \"goto,if,import,last,local,my,next,no,our,print,package,redo,require,\" +\n      \"sub,undef,unless,until,use,wantarray,while,BEGIN,END\";\n  var PYTHON_KEYWORDS = [FLOW_CONTROL_KEYWORDS, \"and,as,assert,class,def,del,\" +\n      \"elif,except,exec,finally,from,global,import,in,is,lambda,\" +\n      \"nonlocal,not,or,pass,print,raise,try,with,yield,\" +\n      \"False,True,None\"];\n  var RUBY_KEYWORDS = [FLOW_CONTROL_KEYWORDS, \"alias,and,begin,case,class,\" +\n      \"def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,\" +\n      \"rescue,retry,self,super,then,true,undef,unless,until,when,yield,\" +\n      \"BEGIN,END\"];\n   var RUST_KEYWORDS = [FLOW_CONTROL_KEYWORDS, \"as,assert,const,copy,drop,\" +\n      \"enum,extern,fail,false,fn,impl,let,log,loop,match,mod,move,mut,priv,\" +\n      \"pub,pure,ref,self,static,struct,true,trait,type,unsafe,use\"];\n  var SH_KEYWORDS = [FLOW_CONTROL_KEYWORDS, \"case,done,elif,esac,eval,fi,\" +\n      \"function,in,local,set,then,until\"];\n  var ALL_KEYWORDS = [\n      CPP_KEYWORDS, CSHARP_KEYWORDS, JSCRIPT_KEYWORDS, PERL_KEYWORDS,\n      PYTHON_KEYWORDS, RUBY_KEYWORDS, SH_KEYWORDS];\n  var C_TYPES = /^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\\d*)\\b/;\n\n  // token style names.  correspond to css classes\n  /**\n   * token style for a string literal\n   * @const\n   */\n  var PR_STRING = 'str';\n  /**\n   * token style for a keyword\n   * @const\n   */\n  var PR_KEYWORD = 'kwd';\n  /**\n   * token style for a comment\n   * @const\n   */\n  var PR_COMMENT = 'com';\n  /**\n   * token style for a type\n   * @const\n   */\n  var PR_TYPE = 'typ';\n  /**\n   * token style for a literal value.  e.g. 1, null, true.\n   * @const\n   */\n  var PR_LITERAL = 'lit';\n  /**\n   * token style for a punctuation string.\n   * @const\n   */\n  var PR_PUNCTUATION = 'pun';\n  /**\n   * token style for plain text.\n   * @const\n   */\n  var PR_PLAIN = 'pln';\n\n  /**\n   * token style for an sgml tag.\n   * @const\n   */\n  var PR_TAG = 'tag';\n  /**\n   * token style for a markup declaration such as a DOCTYPE.\n   * @const\n   */\n  var PR_DECLARATION = 'dec';\n  /**\n   * token style for embedded source.\n   * @const\n   */\n  var PR_SOURCE = 'src';\n  /**\n   * token style for an sgml attribute name.\n   * @const\n   */\n  var PR_ATTRIB_NAME = 'atn';\n  /**\n   * token style for an sgml attribute value.\n   * @const\n   */\n  var PR_ATTRIB_VALUE = 'atv';\n\n  /**\n   * A class that indicates a section of markup that is not code, e.g. to allow\n   * embedding of line numbers within code listings.\n   * @const\n   */\n  var PR_NOCODE = 'nocode';\n\n  \n  \n  /**\n   * A set of tokens that can precede a regular expression literal in\n   * javascript\n   * http://web.archive.org/web/20070717142515/http://www.mozilla.org/js/language/js20/rationale/syntax.html\n   * has the full list, but I've removed ones that might be problematic when\n   * seen in languages that don't support regular expression literals.\n   *\n   * <p>Specifically, I've removed any keywords that can't precede a regexp\n   * literal in a syntactically legal javascript program, and I've removed the\n   * \"in\" keyword since it's not a keyword in many languages, and might be used\n   * as a count of inches.\n   *\n   * <p>The link above does not accurately describe EcmaScript rules since\n   * it fails to distinguish between (a=++/b/i) and (a++/b/i) but it works\n   * very well in practice.\n   *\n   * @private\n   * @const\n   */\n  var REGEXP_PRECEDER_PATTERN = '(?:^^\\\\.?|[+-]|[!=]=?=?|\\\\#|%=?|&&?=?|\\\\(|\\\\*=?|[+\\\\-]=|->|\\\\/=?|::?|<<?=?|>>?>?=?|,|;|\\\\?|@|\\\\[|~|{|\\\\^\\\\^?=?|\\\\|\\\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\\\s*';\n  \n  // CAVEAT: this does not properly handle the case where a regular\n  // expression immediately follows another since a regular expression may\n  // have flags for case-sensitivity and the like.  Having regexp tokens\n  // adjacent is not valid in any language I'm aware of, so I'm punting.\n  // TODO: maybe style special characters inside a regexp as punctuation.\n\n  /**\n   * Given a group of {@link RegExp}s, returns a {@code RegExp} that globally\n   * matches the union of the sets of strings matched by the input RegExp.\n   * Since it matches globally, if the input strings have a start-of-input\n   * anchor (/^.../), it is ignored for the purposes of unioning.\n   * @param {Array.<RegExp>} regexs non multiline, non-global regexs.\n   * @return {RegExp} a global regex.\n   */\n  function combinePrefixPatterns(regexs) {\n    var capturedGroupIndex = 0;\n  \n    var needToFoldCase = false;\n    var ignoreCase = false;\n    for (var i = 0, n = regexs.length; i < n; ++i) {\n      var regex = regexs[i];\n      if (regex.ignoreCase) {\n        ignoreCase = true;\n      } else if (/[a-z]/i.test(regex.source.replace(\n                     /\\\\u[0-9a-f]{4}|\\\\x[0-9a-f]{2}|\\\\[^ux]/gi, ''))) {\n        needToFoldCase = true;\n        ignoreCase = false;\n        break;\n      }\n    }\n  \n    var escapeCharToCodeUnit = {\n      'b': 8,\n      't': 9,\n      'n': 0xa,\n      'v': 0xb,\n      'f': 0xc,\n      'r': 0xd\n    };\n  \n    function decodeEscape(charsetPart) {\n      var cc0 = charsetPart.charCodeAt(0);\n      if (cc0 !== 92 /* \\\\ */) {\n        return cc0;\n      }\n      var c1 = charsetPart.charAt(1);\n      cc0 = escapeCharToCodeUnit[c1];\n      if (cc0) {\n        return cc0;\n      } else if ('0' <= c1 && c1 <= '7') {\n        return parseInt(charsetPart.substring(1), 8);\n      } else if (c1 === 'u' || c1 === 'x') {\n        return parseInt(charsetPart.substring(2), 16);\n      } else {\n        return charsetPart.charCodeAt(1);\n      }\n    }\n  \n    function encodeEscape(charCode) {\n      if (charCode < 0x20) {\n        return (charCode < 0x10 ? '\\\\x0' : '\\\\x') + charCode.toString(16);\n      }\n      var ch = String.fromCharCode(charCode);\n      return (ch === '\\\\' || ch === '-' || ch === ']' || ch === '^')\n          ? \"\\\\\" + ch : ch;\n    }\n  \n    function caseFoldCharset(charSet) {\n      var charsetParts = charSet.substring(1, charSet.length - 1).match(\n          new RegExp(\n              '\\\\\\\\u[0-9A-Fa-f]{4}'\n              + '|\\\\\\\\x[0-9A-Fa-f]{2}'\n              + '|\\\\\\\\[0-3][0-7]{0,2}'\n              + '|\\\\\\\\[0-7]{1,2}'\n              + '|\\\\\\\\[\\\\s\\\\S]'\n              + '|-'\n              + '|[^-\\\\\\\\]',\n              'g'));\n      var ranges = [];\n      var inverse = charsetParts[0] === '^';\n  \n      var out = ['['];\n      if (inverse) { out.push('^'); }\n  \n      for (var i = inverse ? 1 : 0, n = charsetParts.length; i < n; ++i) {\n        var p = charsetParts[i];\n        if (/\\\\[bdsw]/i.test(p)) {  // Don't muck with named groups.\n          out.push(p);\n        } else {\n          var start = decodeEscape(p);\n          var end;\n          if (i + 2 < n && '-' === charsetParts[i + 1]) {\n            end = decodeEscape(charsetParts[i + 2]);\n            i += 2;\n          } else {\n            end = start;\n          }\n          ranges.push([start, end]);\n          // If the range might intersect letters, then expand it.\n          // This case handling is too simplistic.\n          // It does not deal with non-latin case folding.\n          // It works for latin source code identifiers though.\n          if (!(end < 65 || start > 122)) {\n            if (!(end < 65 || start > 90)) {\n              ranges.push([Math.max(65, start) | 32, Math.min(end, 90) | 32]);\n            }\n            if (!(end < 97 || start > 122)) {\n              ranges.push([Math.max(97, start) & ~32, Math.min(end, 122) & ~32]);\n            }\n          }\n        }\n      }\n  \n      // [[1, 10], [3, 4], [8, 12], [14, 14], [16, 16], [17, 17]]\n      // -> [[1, 12], [14, 14], [16, 17]]\n      ranges.sort(function (a, b) { return (a[0] - b[0]) || (b[1]  - a[1]); });\n      var consolidatedRanges = [];\n      var lastRange = [];\n      for (var i = 0; i < ranges.length; ++i) {\n        var range = ranges[i];\n        if (range[0] <= lastRange[1] + 1) {\n          lastRange[1] = Math.max(lastRange[1], range[1]);\n        } else {\n          consolidatedRanges.push(lastRange = range);\n        }\n      }\n  \n      for (var i = 0; i < consolidatedRanges.length; ++i) {\n        var range = consolidatedRanges[i];\n        out.push(encodeEscape(range[0]));\n        if (range[1] > range[0]) {\n          if (range[1] + 1 > range[0]) { out.push('-'); }\n          out.push(encodeEscape(range[1]));\n        }\n      }\n      out.push(']');\n      return out.join('');\n    }\n  \n    function allowAnywhereFoldCaseAndRenumberGroups(regex) {\n      // Split into character sets, escape sequences, punctuation strings\n      // like ('(', '(?:', ')', '^'), and runs of characters that do not\n      // include any of the above.\n      var parts = regex.source.match(\n          new RegExp(\n              '(?:'\n              + '\\\\[(?:[^\\\\x5C\\\\x5D]|\\\\\\\\[\\\\s\\\\S])*\\\\]'  // a character set\n              + '|\\\\\\\\u[A-Fa-f0-9]{4}'  // a unicode escape\n              + '|\\\\\\\\x[A-Fa-f0-9]{2}'  // a hex escape\n              + '|\\\\\\\\[0-9]+'  // a back-reference or octal escape\n              + '|\\\\\\\\[^ux0-9]'  // other escape sequence\n              + '|\\\\(\\\\?[:!=]'  // start of a non-capturing group\n              + '|[\\\\(\\\\)\\\\^]'  // start/end of a group, or line start\n              + '|[^\\\\x5B\\\\x5C\\\\(\\\\)\\\\^]+'  // run of other characters\n              + ')',\n              'g'));\n      var n = parts.length;\n  \n      // Maps captured group numbers to the number they will occupy in\n      // the output or to -1 if that has not been determined, or to\n      // undefined if they need not be capturing in the output.\n      var capturedGroups = [];\n  \n      // Walk over and identify back references to build the capturedGroups\n      // mapping.\n      for (var i = 0, groupIndex = 0; i < n; ++i) {\n        var p = parts[i];\n        if (p === '(') {\n          // groups are 1-indexed, so max group index is count of '('\n          ++groupIndex;\n        } else if ('\\\\' === p.charAt(0)) {\n          var decimalValue = +p.substring(1);\n          if (decimalValue) {\n            if (decimalValue <= groupIndex) {\n              capturedGroups[decimalValue] = -1;\n            } else {\n              // Replace with an unambiguous escape sequence so that\n              // an octal escape sequence does not turn into a backreference\n              // to a capturing group from an earlier regex.\n              parts[i] = encodeEscape(decimalValue);\n            }\n          }\n        }\n      }\n  \n      // Renumber groups and reduce capturing groups to non-capturing groups\n      // where possible.\n      for (var i = 1; i < capturedGroups.length; ++i) {\n        if (-1 === capturedGroups[i]) {\n          capturedGroups[i] = ++capturedGroupIndex;\n        }\n      }\n      for (var i = 0, groupIndex = 0; i < n; ++i) {\n        var p = parts[i];\n        if (p === '(') {\n          ++groupIndex;\n          if (!capturedGroups[groupIndex]) {\n            parts[i] = '(?:';\n          }\n        } else if ('\\\\' === p.charAt(0)) {\n          var decimalValue = +p.substring(1);\n          if (decimalValue && decimalValue <= groupIndex) {\n            parts[i] = '\\\\' + capturedGroups[decimalValue];\n          }\n        }\n      }\n  \n      // Remove any prefix anchors so that the output will match anywhere.\n      // ^^ really does mean an anchored match though.\n      for (var i = 0; i < n; ++i) {\n        if ('^' === parts[i] && '^' !== parts[i + 1]) { parts[i] = ''; }\n      }\n  \n      // Expand letters to groups to handle mixing of case-sensitive and\n      // case-insensitive patterns if necessary.\n      if (regex.ignoreCase && needToFoldCase) {\n        for (var i = 0; i < n; ++i) {\n          var p = parts[i];\n          var ch0 = p.charAt(0);\n          if (p.length >= 2 && ch0 === '[') {\n            parts[i] = caseFoldCharset(p);\n          } else if (ch0 !== '\\\\') {\n            // TODO: handle letters in numeric escapes.\n            parts[i] = p.replace(\n                /[a-zA-Z]/g,\n                function (ch) {\n                  var cc = ch.charCodeAt(0);\n                  return '[' + String.fromCharCode(cc & ~32, cc | 32) + ']';\n                });\n          }\n        }\n      }\n  \n      return parts.join('');\n    }\n  \n    var rewritten = [];\n    for (var i = 0, n = regexs.length; i < n; ++i) {\n      var regex = regexs[i];\n      if (regex.global || regex.multiline) { throw new Error('' + regex); }\n      rewritten.push(\n          '(?:' + allowAnywhereFoldCaseAndRenumberGroups(regex) + ')');\n    }\n  \n    return new RegExp(rewritten.join('|'), ignoreCase ? 'gi' : 'g');\n  }\n\n  /**\n   * Split markup into a string of source code and an array mapping ranges in\n   * that string to the text nodes in which they appear.\n   *\n   * <p>\n   * The HTML DOM structure:</p>\n   * <pre>\n   * (Element   \"p\"\n   *   (Element \"b\"\n   *     (Text  \"print \"))       ; #1\n   *   (Text    \"'Hello '\")      ; #2\n   *   (Element \"br\")            ; #3\n   *   (Text    \"  + 'World';\")) ; #4\n   * </pre>\n   * <p>\n   * corresponds to the HTML\n   * {@code <p><b>print </b>'Hello '<br>  + 'World';</p>}.</p>\n   *\n   * <p>\n   * It will produce the output:</p>\n   * <pre>\n   * {\n   *   sourceCode: \"print 'Hello '\\n  + 'World';\",\n   *   //                     1          2\n   *   //           012345678901234 5678901234567\n   *   spans: [0, #1, 6, #2, 14, #3, 15, #4]\n   * }\n   * </pre>\n   * <p>\n   * where #1 is a reference to the {@code \"print \"} text node above, and so\n   * on for the other text nodes.\n   * </p>\n   *\n   * <p>\n   * The {@code} spans array is an array of pairs.  Even elements are the start\n   * indices of substrings, and odd elements are the text nodes (or BR elements)\n   * that contain the text for those substrings.\n   * Substrings continue until the next index or the end of the source.\n   * </p>\n   *\n   * @param {Node} node an HTML DOM subtree containing source-code.\n   * @param {boolean} isPreformatted true if white-space in text nodes should\n   *    be considered significant.\n   * @return {Object} source code and the text nodes in which they occur.\n   */\n  function extractSourceSpans(node, isPreformatted) {\n    var nocode = /(?:^|\\s)nocode(?:\\s|$)/;\n  \n    var chunks = [];\n    var length = 0;\n    var spans = [];\n    var k = 0;\n  \n    function walk(node) {\n      var type = node.nodeType;\n      if (type == 1) {  // Element\n        if (nocode.test(node.className)) { return; }\n        for (var child = node.firstChild; child; child = child.nextSibling) {\n          walk(child);\n        }\n        var nodeName = node.nodeName.toLowerCase();\n        if ('br' === nodeName || 'li' === nodeName) {\n          chunks[k] = '\\n';\n          spans[k << 1] = length++;\n          spans[(k++ << 1) | 1] = node;\n        }\n      } else if (type == 3 || type == 4) {  // Text\n        var text = node.nodeValue;\n        if (text.length) {\n          if (!isPreformatted) {\n            text = text.replace(/[ \\t\\r\\n]+/g, ' ');\n          } else {\n            text = text.replace(/\\r\\n?/g, '\\n');  // Normalize newlines.\n          }\n          // TODO: handle tabs here?\n          chunks[k] = text;\n          spans[k << 1] = length;\n          length += text.length;\n          spans[(k++ << 1) | 1] = node;\n        }\n      }\n    }\n  \n    walk(node);\n  \n    return {\n      sourceCode: chunks.join('').replace(/\\n$/, ''),\n      spans: spans\n    };\n  }\n\n  /**\n   * Apply the given language handler to sourceCode and add the resulting\n   * decorations to out.\n   * @param {number} basePos the index of sourceCode within the chunk of source\n   *    whose decorations are already present on out.\n   */\n  function appendDecorations(basePos, sourceCode, langHandler, out) {\n    if (!sourceCode) { return; }\n    var job = {\n      sourceCode: sourceCode,\n      basePos: basePos\n    };\n    langHandler(job);\n    out.push.apply(out, job.decorations);\n  }\n\n  var notWs = /\\S/;\n\n  /**\n   * Given an element, if it contains only one child element and any text nodes\n   * it contains contain only space characters, return the sole child element.\n   * Otherwise returns undefined.\n   * <p>\n   * This is meant to return the CODE element in {@code <pre><code ...>} when\n   * there is a single child element that contains all the non-space textual\n   * content, but not to return anything where there are multiple child elements\n   * as in {@code <pre><code>...</code><code>...</code></pre>} or when there\n   * is textual content.\n   */\n  function childContentWrapper(element) {\n    var wrapper = undefined;\n    for (var c = element.firstChild; c; c = c.nextSibling) {\n      var type = c.nodeType;\n      wrapper = (type === 1)  // Element Node\n          ? (wrapper ? element : c)\n          : (type === 3)  // Text Node\n          ? (notWs.test(c.nodeValue) ? element : wrapper)\n          : wrapper;\n    }\n    return wrapper === element ? undefined : wrapper;\n  }\n\n  /** Given triples of [style, pattern, context] returns a lexing function,\n    * The lexing function interprets the patterns to find token boundaries and\n    * returns a decoration list of the form\n    * [index_0, style_0, index_1, style_1, ..., index_n, style_n]\n    * where index_n is an index into the sourceCode, and style_n is a style\n    * constant like PR_PLAIN.  index_n-1 <= index_n, and style_n-1 applies to\n    * all characters in sourceCode[index_n-1:index_n].\n    *\n    * The stylePatterns is a list whose elements have the form\n    * [style : string, pattern : RegExp, DEPRECATED, shortcut : string].\n    *\n    * Style is a style constant like PR_PLAIN, or can be a string of the\n    * form 'lang-FOO', where FOO is a language extension describing the\n    * language of the portion of the token in $1 after pattern executes.\n    * E.g., if style is 'lang-lisp', and group 1 contains the text\n    * '(hello (world))', then that portion of the token will be passed to the\n    * registered lisp handler for formatting.\n    * The text before and after group 1 will be restyled using this decorator\n    * so decorators should take care that this doesn't result in infinite\n    * recursion.  For example, the HTML lexer rule for SCRIPT elements looks\n    * something like ['lang-js', /<[s]cript>(.+?)<\\/script>/].  This may match\n    * '<script>foo()<\\/script>', which would cause the current decorator to\n    * be called with '<script>' which would not match the same rule since\n    * group 1 must not be empty, so it would be instead styled as PR_TAG by\n    * the generic tag rule.  The handler registered for the 'js' extension would\n    * then be called with 'foo()', and finally, the current decorator would\n    * be called with '<\\/script>' which would not match the original rule and\n    * so the generic tag rule would identify it as a tag.\n    *\n    * Pattern must only match prefixes, and if it matches a prefix, then that\n    * match is considered a token with the same style.\n    *\n    * Context is applied to the last non-whitespace, non-comment token\n    * recognized.\n    *\n    * Shortcut is an optional string of characters, any of which, if the first\n    * character, guarantee that this pattern and only this pattern matches.\n    *\n    * @param {Array} shortcutStylePatterns patterns that always start with\n    *   a known character.  Must have a shortcut string.\n    * @param {Array} fallthroughStylePatterns patterns that will be tried in\n    *   order if the shortcut ones fail.  May have shortcuts.\n    *\n    * @return {function (Object)} a\n    *   function that takes source code and returns a list of decorations.\n    */\n  function createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns) {\n    var shortcuts = {};\n    var tokenizer;\n    (function () {\n      var allPatterns = shortcutStylePatterns.concat(fallthroughStylePatterns);\n      var allRegexs = [];\n      var regexKeys = {};\n      for (var i = 0, n = allPatterns.length; i < n; ++i) {\n        var patternParts = allPatterns[i];\n        var shortcutChars = patternParts[3];\n        if (shortcutChars) {\n          for (var c = shortcutChars.length; --c >= 0;) {\n            shortcuts[shortcutChars.charAt(c)] = patternParts;\n          }\n        }\n        var regex = patternParts[1];\n        var k = '' + regex;\n        if (!regexKeys.hasOwnProperty(k)) {\n          allRegexs.push(regex);\n          regexKeys[k] = null;\n        }\n      }\n      allRegexs.push(/[\\0-\\uffff]/);\n      tokenizer = combinePrefixPatterns(allRegexs);\n    })();\n\n    var nPatterns = fallthroughStylePatterns.length;\n\n    /**\n     * Lexes job.sourceCode and produces an output array job.decorations of\n     * style classes preceded by the position at which they start in\n     * job.sourceCode in order.\n     *\n     * @param {Object} job an object like <pre>{\n     *    sourceCode: {string} sourceText plain text,\n     *    basePos: {int} position of job.sourceCode in the larger chunk of\n     *        sourceCode.\n     * }</pre>\n     */\n    var decorate = function (job) {\n      var sourceCode = job.sourceCode, basePos = job.basePos;\n      /** Even entries are positions in source in ascending order.  Odd enties\n        * are style markers (e.g., PR_COMMENT) that run from that position until\n        * the end.\n        * @type {Array.<number|string>}\n        */\n      var decorations = [basePos, PR_PLAIN];\n      var pos = 0;  // index into sourceCode\n      var tokens = sourceCode.match(tokenizer) || [];\n      var styleCache = {};\n\n      for (var ti = 0, nTokens = tokens.length; ti < nTokens; ++ti) {\n        var token = tokens[ti];\n        var style = styleCache[token];\n        var match = void 0;\n\n        var isEmbedded;\n        if (typeof style === 'string') {\n          isEmbedded = false;\n        } else {\n          var patternParts = shortcuts[token.charAt(0)];\n          if (patternParts) {\n            match = token.match(patternParts[1]);\n            style = patternParts[0];\n          } else {\n            for (var i = 0; i < nPatterns; ++i) {\n              patternParts = fallthroughStylePatterns[i];\n              match = token.match(patternParts[1]);\n              if (match) {\n                style = patternParts[0];\n                break;\n              }\n            }\n\n            if (!match) {  // make sure that we make progress\n              style = PR_PLAIN;\n            }\n          }\n\n          isEmbedded = style.length >= 5 && 'lang-' === style.substring(0, 5);\n          if (isEmbedded && !(match && typeof match[1] === 'string')) {\n            isEmbedded = false;\n            style = PR_SOURCE;\n          }\n\n          if (!isEmbedded) { styleCache[token] = style; }\n        }\n\n        var tokenStart = pos;\n        pos += token.length;\n\n        if (!isEmbedded) {\n          decorations.push(basePos + tokenStart, style);\n        } else {  // Treat group 1 as an embedded block of source code.\n          var embeddedSource = match[1];\n          var embeddedSourceStart = token.indexOf(embeddedSource);\n          var embeddedSourceEnd = embeddedSourceStart + embeddedSource.length;\n          if (match[2]) {\n            // If embeddedSource can be blank, then it would match at the\n            // beginning which would cause us to infinitely recurse on the\n            // entire token, so we catch the right context in match[2].\n            embeddedSourceEnd = token.length - match[2].length;\n            embeddedSourceStart = embeddedSourceEnd - embeddedSource.length;\n          }\n          var lang = style.substring(5);\n          // Decorate the left of the embedded source\n          appendDecorations(\n              basePos + tokenStart,\n              token.substring(0, embeddedSourceStart),\n              decorate, decorations);\n          // Decorate the embedded source\n          appendDecorations(\n              basePos + tokenStart + embeddedSourceStart,\n              embeddedSource,\n              langHandlerForExtension(lang, embeddedSource),\n              decorations);\n          // Decorate the right of the embedded section\n          appendDecorations(\n              basePos + tokenStart + embeddedSourceEnd,\n              token.substring(embeddedSourceEnd),\n              decorate, decorations);\n        }\n      }\n      job.decorations = decorations;\n    };\n    return decorate;\n  }\n\n  /** returns a function that produces a list of decorations from source text.\n    *\n    * This code treats \", ', and ` as string delimiters, and \\ as a string\n    * escape.  It does not recognize perl's qq() style strings.\n    * It has no special handling for double delimiter escapes as in basic, or\n    * the tripled delimiters used in python, but should work on those regardless\n    * although in those cases a single string literal may be broken up into\n    * multiple adjacent string literals.\n    *\n    * It recognizes C, C++, and shell style comments.\n    *\n    * @param {Object} options a set of optional parameters.\n    * @return {function (Object)} a function that examines the source code\n    *     in the input job and builds the decoration list.\n    */\n  function sourceDecorator(options) {\n    var shortcutStylePatterns = [], fallthroughStylePatterns = [];\n    if (options['tripleQuotedStrings']) {\n      // '''multi-line-string''', 'single-line-string', and double-quoted\n      shortcutStylePatterns.push(\n          [PR_STRING,  /^(?:\\'\\'\\'(?:[^\\'\\\\]|\\\\[\\s\\S]|\\'{1,2}(?=[^\\']))*(?:\\'\\'\\'|$)|\\\"\\\"\\\"(?:[^\\\"\\\\]|\\\\[\\s\\S]|\\\"{1,2}(?=[^\\\"]))*(?:\\\"\\\"\\\"|$)|\\'(?:[^\\\\\\']|\\\\[\\s\\S])*(?:\\'|$)|\\\"(?:[^\\\\\\\"]|\\\\[\\s\\S])*(?:\\\"|$))/,\n           null, '\\'\"']);\n    } else if (options['multiLineStrings']) {\n      // 'multi-line-string', \"multi-line-string\"\n      shortcutStylePatterns.push(\n          [PR_STRING,  /^(?:\\'(?:[^\\\\\\']|\\\\[\\s\\S])*(?:\\'|$)|\\\"(?:[^\\\\\\\"]|\\\\[\\s\\S])*(?:\\\"|$)|\\`(?:[^\\\\\\`]|\\\\[\\s\\S])*(?:\\`|$))/,\n           null, '\\'\"`']);\n    } else {\n      // 'single-line-string', \"single-line-string\"\n      shortcutStylePatterns.push(\n          [PR_STRING,\n           /^(?:\\'(?:[^\\\\\\'\\r\\n]|\\\\.)*(?:\\'|$)|\\\"(?:[^\\\\\\\"\\r\\n]|\\\\.)*(?:\\\"|$))/,\n           null, '\"\\'']);\n    }\n    if (options['verbatimStrings']) {\n      // verbatim-string-literal production from the C# grammar.  See issue 93.\n      fallthroughStylePatterns.push(\n          [PR_STRING, /^@\\\"(?:[^\\\"]|\\\"\\\")*(?:\\\"|$)/, null]);\n    }\n    var hc = options['hashComments'];\n    if (hc) {\n      if (options['cStyleComments']) {\n        if (hc > 1) {  // multiline hash comments\n          shortcutStylePatterns.push(\n              [PR_COMMENT, /^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/, null, '#']);\n        } else {\n          // Stop C preprocessor declarations at an unclosed open comment\n          shortcutStylePatterns.push(\n              [PR_COMMENT, /^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\\b|[^\\r\\n]*)/,\n               null, '#']);\n        }\n        // #include <stdio.h>\n        fallthroughStylePatterns.push(\n            [PR_STRING,\n             /^<(?:(?:(?:\\.\\.\\/)*|\\/?)(?:[\\w-]+(?:\\/[\\w-]+)+)?[\\w-]+\\.h(?:h|pp|\\+\\+)?|[a-z]\\w*)>/,\n             null]);\n      } else {\n        shortcutStylePatterns.push([PR_COMMENT, /^#[^\\r\\n]*/, null, '#']);\n      }\n    }\n    if (options['cStyleComments']) {\n      fallthroughStylePatterns.push([PR_COMMENT, /^\\/\\/[^\\r\\n]*/, null]);\n      fallthroughStylePatterns.push(\n          [PR_COMMENT, /^\\/\\*[\\s\\S]*?(?:\\*\\/|$)/, null]);\n    }\n    var regexLiterals = options['regexLiterals'];\n    if (regexLiterals) {\n      /**\n       * @const\n       */\n      var regexExcls = regexLiterals > 1\n        ? ''  // Multiline regex literals\n        : '\\n\\r';\n      /**\n       * @const\n       */\n      var regexAny = regexExcls ? '.' : '[\\\\S\\\\s]';\n      /**\n       * @const\n       */\n      var REGEX_LITERAL = (\n          // A regular expression literal starts with a slash that is\n          // not followed by * or / so that it is not confused with\n          // comments.\n          '/(?=[^/*' + regexExcls + '])'\n          // and then contains any number of raw characters,\n          + '(?:[^/\\\\x5B\\\\x5C' + regexExcls + ']'\n          // escape sequences (\\x5C),\n          +    '|\\\\x5C' + regexAny\n          // or non-nesting character sets (\\x5B\\x5D);\n          +    '|\\\\x5B(?:[^\\\\x5C\\\\x5D' + regexExcls + ']'\n          +             '|\\\\x5C' + regexAny + ')*(?:\\\\x5D|$))+'\n          // finally closed by a /.\n          + '/');\n      fallthroughStylePatterns.push(\n          ['lang-regex',\n           RegExp('^' + REGEXP_PRECEDER_PATTERN + '(' + REGEX_LITERAL + ')')\n           ]);\n    }\n\n    var types = options['types'];\n    if (types) {\n      fallthroughStylePatterns.push([PR_TYPE, types]);\n    }\n\n    var keywords = (\"\" + options['keywords']).replace(/^ | $/g, '');\n    if (keywords.length) {\n      fallthroughStylePatterns.push(\n          [PR_KEYWORD,\n           new RegExp('^(?:' + keywords.replace(/[\\s,]+/g, '|') + ')\\\\b'),\n           null]);\n    }\n\n    shortcutStylePatterns.push([PR_PLAIN,       /^\\s+/, null, ' \\r\\n\\t\\xA0']);\n\n    var punctuation =\n      // The Bash man page says\n\n      // A word is a sequence of characters considered as a single\n      // unit by GRUB. Words are separated by metacharacters,\n      // which are the following plus space, tab, and newline: { }\n      // | & $ ; < >\n      // ...\n      \n      // A word beginning with # causes that word and all remaining\n      // characters on that line to be ignored.\n\n      // which means that only a '#' after /(?:^|[{}|&$;<>\\s])/ starts a\n      // comment but empirically\n      // $ echo {#}\n      // {#}\n      // $ echo \\$#\n      // $#\n      // $ echo }#\n      // }#\n\n      // so /(?:^|[|&;<>\\s])/ is more appropriate.\n\n      // http://gcc.gnu.org/onlinedocs/gcc-2.95.3/cpp_1.html#SEC3\n      // suggests that this definition is compatible with a\n      // default mode that tries to use a single token definition\n      // to recognize both bash/python style comments and C\n      // preprocessor directives.\n\n      // This definition of punctuation does not include # in the list of\n      // follow-on exclusions, so # will not be broken before if preceded\n      // by a punctuation character.  We could try to exclude # after\n      // [|&;<>] but that doesn't seem to cause many major problems.\n      // If that does turn out to be a problem, we should change the below\n      // when hc is truthy to include # in the run of punctuation characters\n      // only when not following [|&;<>].\n      '^.[^\\\\s\\\\w.$@\\'\"`/\\\\\\\\]*';\n    if (options['regexLiterals']) {\n      punctuation += '(?!\\s*\\/)';\n    }\n\n    fallthroughStylePatterns.push(\n        // TODO(mikesamuel): recognize non-latin letters and numerals in idents\n        [PR_LITERAL,     /^@[a-z_$][a-z_$@0-9]*/i, null],\n        [PR_TYPE,        /^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\\w+_t\\b)/, null],\n        [PR_PLAIN,       /^[a-z_$][a-z_$@0-9]*/i, null],\n        [PR_LITERAL,\n         new RegExp(\n             '^(?:'\n             // A hex number\n             + '0x[a-f0-9]+'\n             // or an octal or decimal number,\n             + '|(?:\\\\d(?:_\\\\d+)*\\\\d*(?:\\\\.\\\\d*)?|\\\\.\\\\d\\\\+)'\n             // possibly in scientific notation\n             + '(?:e[+\\\\-]?\\\\d+)?'\n             + ')'\n             // with an optional modifier like UL for unsigned long\n             + '[a-z]*', 'i'),\n         null, '0123456789'],\n        // Don't treat escaped quotes in bash as starting strings.\n        // See issue 144.\n        [PR_PLAIN,       /^\\\\[\\s\\S]?/, null],\n        [PR_PUNCTUATION, new RegExp(punctuation), null]);\n\n    return createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns);\n  }\n\n  var decorateSource = sourceDecorator({\n        'keywords': ALL_KEYWORDS,\n        'hashComments': true,\n        'cStyleComments': true,\n        'multiLineStrings': true,\n        'regexLiterals': true\n      });\n\n  /**\n   * Given a DOM subtree, wraps it in a list, and puts each line into its own\n   * list item.\n   *\n   * @param {Node} node modified in place.  Its content is pulled into an\n   *     HTMLOListElement, and each line is moved into a separate list item.\n   *     This requires cloning elements, so the input might not have unique\n   *     IDs after numbering.\n   * @param {boolean} isPreformatted true iff white-space in text nodes should\n   *     be treated as significant.\n   */\n  function numberLines(node, opt_startLineNum, isPreformatted) {\n    var nocode = /(?:^|\\s)nocode(?:\\s|$)/;\n    var lineBreak = /\\r\\n?|\\n/;\n  \n    var document = node.ownerDocument;\n  \n    var li = document.createElement('li');\n    while (node.firstChild) {\n      li.appendChild(node.firstChild);\n    }\n    // An array of lines.  We split below, so this is initialized to one\n    // un-split line.\n    var listItems = [li];\n  \n    function walk(node) {\n      var type = node.nodeType;\n      if (type == 1 && !nocode.test(node.className)) {  // Element\n        if ('br' === node.nodeName) {\n          breakAfter(node);\n          // Discard the <BR> since it is now flush against a </LI>.\n          if (node.parentNode) {\n            node.parentNode.removeChild(node);\n          }\n        } else {\n          for (var child = node.firstChild; child; child = child.nextSibling) {\n            walk(child);\n          }\n        }\n      } else if ((type == 3 || type == 4) && isPreformatted) {  // Text\n        var text = node.nodeValue;\n        var match = text.match(lineBreak);\n        if (match) {\n          var firstLine = text.substring(0, match.index);\n          node.nodeValue = firstLine;\n          var tail = text.substring(match.index + match[0].length);\n          if (tail) {\n            var parent = node.parentNode;\n            parent.insertBefore(\n              document.createTextNode(tail), node.nextSibling);\n          }\n          breakAfter(node);\n          if (!firstLine) {\n            // Don't leave blank text nodes in the DOM.\n            node.parentNode.removeChild(node);\n          }\n        }\n      }\n    }\n  \n    // Split a line after the given node.\n    function breakAfter(lineEndNode) {\n      // If there's nothing to the right, then we can skip ending the line\n      // here, and move root-wards since splitting just before an end-tag\n      // would require us to create a bunch of empty copies.\n      while (!lineEndNode.nextSibling) {\n        lineEndNode = lineEndNode.parentNode;\n        if (!lineEndNode) { return; }\n      }\n  \n      function breakLeftOf(limit, copy) {\n        // Clone shallowly if this node needs to be on both sides of the break.\n        var rightSide = copy ? limit.cloneNode(false) : limit;\n        var parent = limit.parentNode;\n        if (parent) {\n          // We clone the parent chain.\n          // This helps us resurrect important styling elements that cross lines.\n          // E.g. in <i>Foo<br>Bar</i>\n          // should be rewritten to <li><i>Foo</i></li><li><i>Bar</i></li>.\n          var parentClone = breakLeftOf(parent, 1);\n          // Move the clone and everything to the right of the original\n          // onto the cloned parent.\n          var next = limit.nextSibling;\n          parentClone.appendChild(rightSide);\n          for (var sibling = next; sibling; sibling = next) {\n            next = sibling.nextSibling;\n            parentClone.appendChild(sibling);\n          }\n        }\n        return rightSide;\n      }\n  \n      var copiedListItem = breakLeftOf(lineEndNode.nextSibling, 0);\n  \n      // Walk the parent chain until we reach an unattached LI.\n      for (var parent;\n           // Check nodeType since IE invents document fragments.\n           (parent = copiedListItem.parentNode) && parent.nodeType === 1;) {\n        copiedListItem = parent;\n      }\n      // Put it on the list of lines for later processing.\n      listItems.push(copiedListItem);\n    }\n  \n    // Split lines while there are lines left to split.\n    for (var i = 0;  // Number of lines that have been split so far.\n         i < listItems.length;  // length updated by breakAfter calls.\n         ++i) {\n      walk(listItems[i]);\n    }\n  \n    // Make sure numeric indices show correctly.\n    if (opt_startLineNum === (opt_startLineNum|0)) {\n      listItems[0].setAttribute('value', opt_startLineNum);\n    }\n  \n    var ol = document.createElement('ol');\n    ol.className = 'linenums';\n    var offset = Math.max(0, ((opt_startLineNum - 1 /* zero index */)) | 0) || 0;\n    for (var i = 0, n = listItems.length; i < n; ++i) {\n      li = listItems[i];\n      // Stick a class on the LIs so that stylesheets can\n      // color odd/even rows, or any other row pattern that\n      // is co-prime with 10.\n      li.className = 'L' + ((i + offset) % 10);\n      if (!li.firstChild) {\n        li.appendChild(document.createTextNode('\\xA0'));\n      }\n      ol.appendChild(li);\n    }\n  \n    node.appendChild(ol);\n  }\n  /**\n   * Breaks {@code job.sourceCode} around style boundaries in\n   * {@code job.decorations} and modifies {@code job.sourceNode} in place.\n   * @param {Object} job like <pre>{\n   *    sourceCode: {string} source as plain text,\n   *    sourceNode: {HTMLElement} the element containing the source,\n   *    spans: {Array.<number|Node>} alternating span start indices into source\n   *       and the text node or element (e.g. {@code <BR>}) corresponding to that\n   *       span.\n   *    decorations: {Array.<number|string} an array of style classes preceded\n   *       by the position at which they start in job.sourceCode in order\n   * }</pre>\n   * @private\n   */\n  function recombineTagsAndDecorations(job) {\n    var isIE8OrEarlier = /\\bMSIE\\s(\\d+)/.exec(navigator.userAgent);\n    isIE8OrEarlier = isIE8OrEarlier && +isIE8OrEarlier[1] <= 8;\n    var newlineRe = /\\n/g;\n  \n    var source = job.sourceCode;\n    var sourceLength = source.length;\n    // Index into source after the last code-unit recombined.\n    var sourceIndex = 0;\n  \n    var spans = job.spans;\n    var nSpans = spans.length;\n    // Index into spans after the last span which ends at or before sourceIndex.\n    var spanIndex = 0;\n  \n    var decorations = job.decorations;\n    var nDecorations = decorations.length;\n    // Index into decorations after the last decoration which ends at or before\n    // sourceIndex.\n    var decorationIndex = 0;\n  \n    // Remove all zero-length decorations.\n    decorations[nDecorations] = sourceLength;\n    var decPos, i;\n    for (i = decPos = 0; i < nDecorations;) {\n      if (decorations[i] !== decorations[i + 2]) {\n        decorations[decPos++] = decorations[i++];\n        decorations[decPos++] = decorations[i++];\n      } else {\n        i += 2;\n      }\n    }\n    nDecorations = decPos;\n  \n    // Simplify decorations.\n    for (i = decPos = 0; i < nDecorations;) {\n      var startPos = decorations[i];\n      // Conflate all adjacent decorations that use the same style.\n      var startDec = decorations[i + 1];\n      var end = i + 2;\n      while (end + 2 <= nDecorations && decorations[end + 1] === startDec) {\n        end += 2;\n      }\n      decorations[decPos++] = startPos;\n      decorations[decPos++] = startDec;\n      i = end;\n    }\n  \n    nDecorations = decorations.length = decPos;\n  \n    var sourceNode = job.sourceNode;\n    var oldDisplay;\n    if (sourceNode) {\n      oldDisplay = sourceNode.style.display;\n      sourceNode.style.display = 'none';\n    }\n    try {\n      var decoration = null;\n      while (spanIndex < nSpans) {\n        var spanStart = spans[spanIndex];\n        var spanEnd = spans[spanIndex + 2] || sourceLength;\n  \n        var decEnd = decorations[decorationIndex + 2] || sourceLength;\n  \n        var end = Math.min(spanEnd, decEnd);\n  \n        var textNode = spans[spanIndex + 1];\n        var styledText;\n        if (textNode.nodeType !== 1  // Don't muck with <BR>s or <LI>s\n            // Don't introduce spans around empty text nodes.\n            && (styledText = source.substring(sourceIndex, end))) {\n          // This may seem bizarre, and it is.  Emitting LF on IE causes the\n          // code to display with spaces instead of line breaks.\n          // Emitting Windows standard issue linebreaks (CRLF) causes a blank\n          // space to appear at the beginning of every line but the first.\n          // Emitting an old Mac OS 9 line separator makes everything spiffy.\n          if (isIE8OrEarlier) {\n            styledText = styledText.replace(newlineRe, '\\r');\n          }\n          textNode.nodeValue = styledText;\n          var document = textNode.ownerDocument;\n          var span = document.createElement('span');\n          span.className = decorations[decorationIndex + 1];\n          var parentNode = textNode.parentNode;\n          parentNode.replaceChild(span, textNode);\n          span.appendChild(textNode);\n          if (sourceIndex < spanEnd) {  // Split off a text node.\n            spans[spanIndex + 1] = textNode\n                // TODO: Possibly optimize by using '' if there's no flicker.\n                = document.createTextNode(source.substring(end, spanEnd));\n            parentNode.insertBefore(textNode, span.nextSibling);\n          }\n        }\n  \n        sourceIndex = end;\n  \n        if (sourceIndex >= spanEnd) {\n          spanIndex += 2;\n        }\n        if (sourceIndex >= decEnd) {\n          decorationIndex += 2;\n        }\n      }\n    } finally {\n      if (sourceNode) {\n        sourceNode.style.display = oldDisplay;\n      }\n    }\n  }\n\n  /** Maps language-specific file extensions to handlers. */\n  var langHandlerRegistry = {};\n  /** Register a language handler for the given file extensions.\n    * @param {function (Object)} handler a function from source code to a list\n    *      of decorations.  Takes a single argument job which describes the\n    *      state of the computation.   The single parameter has the form\n    *      {@code {\n    *        sourceCode: {string} as plain text.\n    *        decorations: {Array.<number|string>} an array of style classes\n    *                     preceded by the position at which they start in\n    *                     job.sourceCode in order.\n    *                     The language handler should assigned this field.\n    *        basePos: {int} the position of source in the larger source chunk.\n    *                 All positions in the output decorations array are relative\n    *                 to the larger source chunk.\n    *      } }\n    * @param {Array.<string>} fileExtensions\n    */\n  function registerLangHandler(handler, fileExtensions) {\n    for (var i = fileExtensions.length; --i >= 0;) {\n      var ext = fileExtensions[i];\n      if (!langHandlerRegistry.hasOwnProperty(ext)) {\n        langHandlerRegistry[ext] = handler;\n      } else if (win['console']) {\n        console['warn']('cannot override language handler %s', ext);\n      }\n    }\n  }\n  function langHandlerForExtension(extension, source) {\n    if (!(extension && langHandlerRegistry.hasOwnProperty(extension))) {\n      // Treat it as markup if the first non whitespace character is a < and\n      // the last non-whitespace character is a >.\n      extension = /^\\s*</.test(source)\n          ? 'default-markup'\n          : 'default-code';\n    }\n    return langHandlerRegistry[extension];\n  }\n  registerLangHandler(decorateSource, ['default-code']);\n  registerLangHandler(\n      createSimpleLexer(\n          [],\n          [\n           [PR_PLAIN,       /^[^<?]+/],\n           [PR_DECLARATION, /^<!\\w[^>]*(?:>|$)/],\n           [PR_COMMENT,     /^<\\!--[\\s\\S]*?(?:-\\->|$)/],\n           // Unescaped content in an unknown language\n           ['lang-',        /^<\\?([\\s\\S]+?)(?:\\?>|$)/],\n           ['lang-',        /^<%([\\s\\S]+?)(?:%>|$)/],\n           [PR_PUNCTUATION, /^(?:<[%?]|[%?]>)/],\n           ['lang-',        /^<xmp\\b[^>]*>([\\s\\S]+?)<\\/xmp\\b[^>]*>/i],\n           // Unescaped content in javascript.  (Or possibly vbscript).\n           ['lang-js',      /^<script\\b[^>]*>([\\s\\S]*?)(<\\/script\\b[^>]*>)/i],\n           // Contains unescaped stylesheet content\n           ['lang-css',     /^<style\\b[^>]*>([\\s\\S]*?)(<\\/style\\b[^>]*>)/i],\n           ['lang-in.tag',  /^(<\\/?[a-z][^<>]*>)/i]\n          ]),\n      ['default-markup', 'htm', 'html', 'mxml', 'xhtml', 'xml', 'xsl']);\n  registerLangHandler(\n      createSimpleLexer(\n          [\n           [PR_PLAIN,        /^[\\s]+/, null, ' \\t\\r\\n'],\n           [PR_ATTRIB_VALUE, /^(?:\\\"[^\\\"]*\\\"?|\\'[^\\']*\\'?)/, null, '\\\"\\'']\n           ],\n          [\n           [PR_TAG,          /^^<\\/?[a-z](?:[\\w.:-]*\\w)?|\\/?>$/i],\n           [PR_ATTRIB_NAME,  /^(?!style[\\s=]|on)[a-z](?:[\\w:-]*\\w)?/i],\n           ['lang-uq.val',   /^=\\s*([^>\\'\\\"\\s]*(?:[^>\\'\\\"\\s\\/]|\\/(?=\\s)))/],\n           [PR_PUNCTUATION,  /^[=<>\\/]+/],\n           ['lang-js',       /^on\\w+\\s*=\\s*\\\"([^\\\"]+)\\\"/i],\n           ['lang-js',       /^on\\w+\\s*=\\s*\\'([^\\']+)\\'/i],\n           ['lang-js',       /^on\\w+\\s*=\\s*([^\\\"\\'>\\s]+)/i],\n           ['lang-css',      /^style\\s*=\\s*\\\"([^\\\"]+)\\\"/i],\n           ['lang-css',      /^style\\s*=\\s*\\'([^\\']+)\\'/i],\n           ['lang-css',      /^style\\s*=\\s*([^\\\"\\'>\\s]+)/i]\n           ]),\n      ['in.tag']);\n  registerLangHandler(\n      createSimpleLexer([], [[PR_ATTRIB_VALUE, /^[\\s\\S]+/]]), ['uq.val']);\n  registerLangHandler(sourceDecorator({\n          'keywords': CPP_KEYWORDS,\n          'hashComments': true,\n          'cStyleComments': true,\n          'types': C_TYPES\n        }), ['c', 'cc', 'cpp', 'cxx', 'cyc', 'm']);\n  registerLangHandler(sourceDecorator({\n          'keywords': 'null,true,false'\n        }), ['json']);\n  registerLangHandler(sourceDecorator({\n          'keywords': CSHARP_KEYWORDS,\n          'hashComments': true,\n          'cStyleComments': true,\n          'verbatimStrings': true,\n          'types': C_TYPES\n        }), ['cs']);\n  registerLangHandler(sourceDecorator({\n          'keywords': JAVA_KEYWORDS,\n          'cStyleComments': true\n        }), ['java']);\n  registerLangHandler(sourceDecorator({\n          'keywords': SH_KEYWORDS,\n          'hashComments': true,\n          'multiLineStrings': true\n        }), ['bash', 'bsh', 'csh', 'sh']);\n  registerLangHandler(sourceDecorator({\n          'keywords': PYTHON_KEYWORDS,\n          'hashComments': true,\n          'multiLineStrings': true,\n          'tripleQuotedStrings': true\n        }), ['cv', 'py', 'python']);\n  registerLangHandler(sourceDecorator({\n          'keywords': PERL_KEYWORDS,\n          'hashComments': true,\n          'multiLineStrings': true,\n          'regexLiterals': 2  // multiline regex literals\n        }), ['perl', 'pl', 'pm']);\n  registerLangHandler(sourceDecorator({\n          'keywords': RUBY_KEYWORDS,\n          'hashComments': true,\n          'multiLineStrings': true,\n          'regexLiterals': true\n        }), ['rb', 'ruby']);\n  registerLangHandler(sourceDecorator({\n          'keywords': JSCRIPT_KEYWORDS,\n          'cStyleComments': true,\n          'regexLiterals': true\n        }), ['javascript', 'js']);\n  registerLangHandler(sourceDecorator({\n          'keywords': COFFEE_KEYWORDS,\n          'hashComments': 3,  // ### style block comments\n          'cStyleComments': true,\n          'multilineStrings': true,\n          'tripleQuotedStrings': true,\n          'regexLiterals': true\n        }), ['coffee']);\n  registerLangHandler(sourceDecorator({\n          'keywords': RUST_KEYWORDS,\n          'cStyleComments': true,\n          'multilineStrings': true\n        }), ['rc', 'rs', 'rust']);\n  registerLangHandler(\n      createSimpleLexer([], [[PR_STRING, /^[\\s\\S]+/]]), ['regex']);\n\n  function applyDecorator(job) {\n    var opt_langExtension = job.langExtension;\n\n    try {\n      // Extract tags, and convert the source code to plain text.\n      var sourceAndSpans = extractSourceSpans(job.sourceNode, job.pre);\n      /** Plain text. @type {string} */\n      var source = sourceAndSpans.sourceCode;\n      job.sourceCode = source;\n      job.spans = sourceAndSpans.spans;\n      job.basePos = 0;\n\n      // Apply the appropriate language handler\n      langHandlerForExtension(opt_langExtension, source)(job);\n\n      // Integrate the decorations and tags back into the source code,\n      // modifying the sourceNode in place.\n      recombineTagsAndDecorations(job);\n    } catch (e) {\n      if (win['console']) {\n        console['log'](e && e['stack'] || e);\n      }\n    }\n  }\n\n  /**\n   * Pretty print a chunk of code.\n   * @param sourceCodeHtml {string} The HTML to pretty print.\n   * @param opt_langExtension {string} The language name to use.\n   *     Typically, a filename extension like 'cpp' or 'java'.\n   * @param opt_numberLines {number|boolean} True to number lines,\n   *     or the 1-indexed number of the first line in sourceCodeHtml.\n   */\n  function $prettyPrintOne(sourceCodeHtml, opt_langExtension, opt_numberLines) {\n    var container = document.createElement('div');\n    // This could cause images to load and onload listeners to fire.\n    // E.g. <img onerror=\"alert(1337)\" src=\"nosuchimage.png\">.\n    // We assume that the inner HTML is from a trusted source.\n    // The pre-tag is required for IE8 which strips newlines from innerHTML\n    // when it is injected into a <pre> tag.\n    // http://stackoverflow.com/questions/451486/pre-tag-loses-line-breaks-when-setting-innerhtml-in-ie\n    // http://stackoverflow.com/questions/195363/inserting-a-newline-into-a-pre-tag-ie-javascript\n    container.innerHTML = '<pre>' + sourceCodeHtml + '</pre>';\n    container = container.firstChild;\n    if (opt_numberLines) {\n      numberLines(container, opt_numberLines, true);\n    }\n\n    var job = {\n      langExtension: opt_langExtension,\n      numberLines: opt_numberLines,\n      sourceNode: container,\n      pre: 1\n    };\n    applyDecorator(job);\n    return container.innerHTML;\n  }\n\n   /**\n    * Find all the {@code <pre>} and {@code <code>} tags in the DOM with\n    * {@code class=prettyprint} and prettify them.\n    *\n    * @param {Function} opt_whenDone called when prettifying is done.\n    * @param {HTMLElement|HTMLDocument} opt_root an element or document\n    *   containing all the elements to pretty print.\n    *   Defaults to {@code document.body}.\n    */\n  function $prettyPrint(opt_whenDone, opt_root) {\n    var root = opt_root || document.body;\n    var doc = root.ownerDocument || document;\n    function byTagName(tn) { return root.getElementsByTagName(tn); }\n    // fetch a list of nodes to rewrite\n    var codeSegments = [byTagName('pre'), byTagName('code'), byTagName('xmp')];\n    var elements = [];\n    for (var i = 0; i < codeSegments.length; ++i) {\n      for (var j = 0, n = codeSegments[i].length; j < n; ++j) {\n        elements.push(codeSegments[i][j]);\n      }\n    }\n    codeSegments = null;\n\n    var clock = Date;\n    if (!clock['now']) {\n      clock = { 'now': function () { return +(new Date); } };\n    }\n\n    // The loop is broken into a series of continuations to make sure that we\n    // don't make the browser unresponsive when rewriting a large page.\n    var k = 0;\n    var prettyPrintingJob;\n\n    var langExtensionRe = /\\blang(?:uage)?-([\\w.]+)(?!\\S)/;\n    var prettyPrintRe = /\\bprettyprint\\b/;\n    var prettyPrintedRe = /\\bprettyprinted\\b/;\n    var preformattedTagNameRe = /pre|xmp/i;\n    var codeRe = /^code$/i;\n    var preCodeXmpRe = /^(?:pre|code|xmp)$/i;\n    var EMPTY = {};\n\n    function doWork() {\n      var endTime = (win['PR_SHOULD_USE_CONTINUATION'] ?\n                     clock['now']() + 250 /* ms */ :\n                     Infinity);\n      for (; k < elements.length && clock['now']() < endTime; k++) {\n        var cs = elements[k];\n\n        // Look for a preceding comment like\n        // <?prettify lang=\"...\" linenums=\"...\"?>\n        var attrs = EMPTY;\n        {\n          for (var preceder = cs; (preceder = preceder.previousSibling);) {\n            var nt = preceder.nodeType;\n            // <?foo?> is parsed by HTML 5 to a comment node (8)\n            // like <!--?foo?-->, but in XML is a processing instruction\n            var value = (nt === 7 || nt === 8) && preceder.nodeValue;\n            if (value\n                ? !/^\\??prettify\\b/.test(value)\n                : (nt !== 3 || /\\S/.test(preceder.nodeValue))) {\n              // Skip over white-space text nodes but not others.\n              break;\n            }\n            if (value) {\n              attrs = {};\n              value.replace(\n                  /\\b(\\w+)=([\\w:.%+-]+)/g,\n                function (_, name, value) { attrs[name] = value; });\n              break;\n            }\n          }\n        }\n\n        var className = cs.className;\n        if ((attrs !== EMPTY || prettyPrintRe.test(className))\n            // Don't redo this if we've already done it.\n            // This allows recalling pretty print to just prettyprint elements\n            // that have been added to the page since last call.\n            && !prettyPrintedRe.test(className)) {\n\n          // make sure this is not nested in an already prettified element\n          var nested = false;\n          for (var p = cs.parentNode; p; p = p.parentNode) {\n            var tn = p.tagName;\n            if (preCodeXmpRe.test(tn)\n                && p.className && prettyPrintRe.test(p.className)) {\n              nested = true;\n              break;\n            }\n          }\n          if (!nested) {\n            // Mark done.  If we fail to prettyprint for whatever reason,\n            // we shouldn't try again.\n            cs.className += ' prettyprinted';\n\n            // If the classes includes a language extensions, use it.\n            // Language extensions can be specified like\n            //     <pre class=\"prettyprint lang-cpp\">\n            // the language extension \"cpp\" is used to find a language handler\n            // as passed to PR.registerLangHandler.\n            // HTML5 recommends that a language be specified using \"language-\"\n            // as the prefix instead.  Google Code Prettify supports both.\n            // http://dev.w3.org/html5/spec-author-view/the-code-element.html\n            var langExtension = attrs['lang'];\n            if (!langExtension) {\n              langExtension = className.match(langExtensionRe);\n              // Support <pre class=\"prettyprint\"><code class=\"language-c\">\n              var wrapper;\n              if (!langExtension && (wrapper = childContentWrapper(cs))\n                  && codeRe.test(wrapper.tagName)) {\n                langExtension = wrapper.className.match(langExtensionRe);\n              }\n\n              if (langExtension) { langExtension = langExtension[1]; }\n            }\n\n            var preformatted;\n            if (preformattedTagNameRe.test(cs.tagName)) {\n              preformatted = 1;\n            } else {\n              var currentStyle = cs['currentStyle'];\n              var defaultView = doc.defaultView;\n              var whitespace = (\n                  currentStyle\n                  ? currentStyle['whiteSpace']\n                  : (defaultView\n                     && defaultView.getComputedStyle)\n                  ? defaultView.getComputedStyle(cs, null)\n                  .getPropertyValue('white-space')\n                  : 0);\n              preformatted = whitespace\n                  && 'pre' === whitespace.substring(0, 3);\n            }\n\n            // Look for a class like linenums or linenums:<n> where <n> is the\n            // 1-indexed number of the first line.\n            var lineNums = attrs['linenums'];\n            if (!(lineNums = lineNums === 'true' || +lineNums)) {\n              lineNums = className.match(/\\blinenums\\b(?::(\\d+))?/);\n              lineNums =\n                lineNums\n                ? lineNums[1] && lineNums[1].length\n                  ? +lineNums[1] : true\n                : false;\n            }\n            if (lineNums) { numberLines(cs, lineNums, preformatted); }\n\n            // do the pretty printing\n            prettyPrintingJob = {\n              langExtension: langExtension,\n              sourceNode: cs,\n              numberLines: lineNums,\n              pre: preformatted\n            };\n            applyDecorator(prettyPrintingJob);\n          }\n        }\n      }\n      if (k < elements.length) {\n        // finish up in a continuation\n        setTimeout(doWork, 250);\n      } else if ('function' === typeof opt_whenDone) {\n        opt_whenDone();\n      }\n    }\n\n    doWork();\n  }\n\n  /**\n   * Contains functions for creating and registering new language handlers.\n   * @type {Object}\n   */\n  var PR = win['PR'] = {\n        'createSimpleLexer': createSimpleLexer,\n        'registerLangHandler': registerLangHandler,\n        'sourceDecorator': sourceDecorator,\n        'PR_ATTRIB_NAME': PR_ATTRIB_NAME,\n        'PR_ATTRIB_VALUE': PR_ATTRIB_VALUE,\n        'PR_COMMENT': PR_COMMENT,\n        'PR_DECLARATION': PR_DECLARATION,\n        'PR_KEYWORD': PR_KEYWORD,\n        'PR_LITERAL': PR_LITERAL,\n        'PR_NOCODE': PR_NOCODE,\n        'PR_PLAIN': PR_PLAIN,\n        'PR_PUNCTUATION': PR_PUNCTUATION,\n        'PR_SOURCE': PR_SOURCE,\n        'PR_STRING': PR_STRING,\n        'PR_TAG': PR_TAG,\n        'PR_TYPE': PR_TYPE,\n        'prettyPrintOne':\n           IN_GLOBAL_SCOPE\n             ? (win['prettyPrintOne'] = $prettyPrintOne)\n             : (prettyPrintOne = $prettyPrintOne),\n        'prettyPrint': prettyPrint =\n           IN_GLOBAL_SCOPE\n             ? (win['prettyPrint'] = $prettyPrint)\n             : (prettyPrint = $prettyPrint)\n      };\n\n  // Make PR available via the Asynchronous Module Definition (AMD) API.\n  // Per https://github.com/amdjs/amdjs-api/wiki/AMD:\n  // The Asynchronous Module Definition (AMD) API specifies a\n  // mechanism for defining modules such that the module and its\n  // dependencies can be asynchronously loaded.\n  // ...\n  // To allow a clear indicator that a global define function (as\n  // needed for script src browser loading) conforms to the AMD API,\n  // any global define function SHOULD have a property called \"amd\"\n  // whose value is an object. This helps avoid conflict with any\n  // other existing JavaScript code that could have defined a define()\n  // function that does not conform to the AMD API.\n  if (typeof define === \"function\" && define['amd']) {\n    define(\"google-code-prettify\", [], function () {\n      return PR; \n    });\n  }\n})();\n\ndefine(\"prettify\", function(){});\n\n",
             "define('itemView',[\n  'App',\n  // Templates\n  'text!tpl/item.html',\n  'text!tpl/class.html',\n  'text!tpl/itemEnd.html',\n  // Tools\n  'prettify'\n], function(App, itemTpl, classTpl, endTpl) {\n  'use strict';\n\n  var appVersion = App.project.version || 'master';\n\n  var itemView = Backbone.View.extend({\n    el: '#item',\n    init: function() {\n      this.$html = $('html');\n      this.$body = $('body');\n      this.$scrollBody = $('html, body'); // hack for Chrome/Firefox scroll\n\n      this.tpl = _.template(itemTpl);\n      this.classTpl = _.template(classTpl);\n      this.endTpl = _.template(endTpl);\n\n      return this;\n    },\n    getSyntax: function(isMethod, cleanItem) {\n      var isConstructor = cleanItem.is_constructor;\n      var syntax = '';\n      if (isConstructor) {\n        syntax += 'new ';\n      } else if (cleanItem.static && cleanItem.class) {\n        syntax += cleanItem.class + '.';\n      }\n      syntax += cleanItem.name;\n\n      if (isMethod || isConstructor) {\n        syntax += '(';\n        if (cleanItem.params) {\n          for (var i = 0; i < cleanItem.params.length; i++) {\n            var p = cleanItem.params[i];\n            if (p.optional) {\n              syntax += '[';\n            }\n            syntax += p.name;\n            if (p.optdefault) {\n              syntax += '=' + p.optdefault;\n            }\n            if (p.optional) {\n              syntax += ']';\n            }\n            if (i !== cleanItem.params.length - 1) {\n              syntax += ', ';\n            }\n          }\n        }\n        syntax += ')';\n      }\n\n      return syntax;\n    },\n    // Return a list of valid syntaxes across all overloaded versions of\n    // this item.\n    //\n    // For reference, we ultimately want to replicate something like this:\n    //\n    // https://processing.org/reference/color_.html\n    getSyntaxes: function(isMethod, cleanItem) {\n      var overloads = cleanItem.overloads || [cleanItem];\n      return overloads.map(this.getSyntax.bind(this, isMethod));\n    },\n    render: function(item) {\n      if (item) {\n        var itemHtml = '';\n        var cleanItem = this.clean(item);\n        var isClass = item.hasOwnProperty('itemtype') ? 0 : 1;\n        var collectionName = isClass\n            ? 'Constructor'\n            : this.capitalizeFirst(cleanItem.itemtype),\n          isConstructor = cleanItem.is_constructor;\n        cleanItem.isMethod = collectionName === 'Method';\n\n        var syntaxes = this.getSyntaxes(cleanItem.isMethod, cleanItem);\n\n        // Set the item header (title)\n\n        // Set item contents\n        if (isClass) {\n          var constructor = this.tpl({\n            item: cleanItem,\n            isClass: true,\n            isConstructor: isConstructor,\n            syntaxes: syntaxes\n          });\n          cleanItem.constructor = constructor;\n\n          var contents = _.find(App.classes, function(c) {\n            return c.name === cleanItem.name;\n          });\n          cleanItem.things = contents.items;\n\n          itemHtml = this.classTpl(cleanItem);\n        } else {\n          cleanItem.constRefs =\n            item.module === 'Constants' && App.data.consts[item.name];\n\n          itemHtml = this.tpl({\n            item: cleanItem,\n            isClass: false,\n            isConstructor: false,\n            syntaxes: syntaxes\n          });\n        }\n\n        itemHtml += this.endTpl({ item: cleanItem, appVersion: appVersion });\n\n        // Insert the view in the dom\n        this.$el.html(itemHtml);\n\n        renderCode(cleanItem.name);\n\n        // Set the document title based on the item name.\n        // If it is a method, add parentheses to the name\n        if (item.itemtype === 'method') {\n          App.pageView.appendToDocumentTitle(item.name + '()');\n        } else {\n          App.pageView.appendToDocumentTitle(item.name);\n        }\n\n        // Hook up alt-text for examples\n        setTimeout(function() {\n          var alts = $('.example-content')[0];\n          if (alts) {\n            alts = $(alts)\n              .data('alt')\n              .split('\\n');\n\n            var canvases = $('.cnv_div');\n            for (var j = 0; j < alts.length; j++) {\n              if (j < canvases.length) {\n                $(canvases[j]).append(\n                  '<span class=\"sr-only\">' + alts[j] + '</span>'\n                );\n              }\n            }\n          }\n        }, 1000);\n        Prism.highlightAll();\n      }\n\n      var renderEvent = new Event('reference-rendered');\n      window.dispatchEvent(renderEvent);\n\n      return this;\n    },\n    /**\n     * Clean item properties: url encode properties containing paths.\n     * @param {object} item The item object.\n     * @returns {object} Returns the same item object with urlencoded paths.\n     */\n    clean: function(item) {\n      var cleanItem = item;\n\n      if (cleanItem.hasOwnProperty('file')) {\n        cleanItem.urlencodedfile = encodeURIComponent(item.file);\n      }\n      return cleanItem;\n    },\n    /**\n     * Show a single item.\n     * @param {object} item Item object.\n     * @returns {object} This view.\n     */\n    show: function(item) {\n      if (item) {\n        this.render(item);\n      }\n\n      App.pageView.hideContentViews();\n\n      this.$el.show();\n\n      this.scrollTop();\n      $('#item').focus();\n      return this;\n    },\n    /**\n     * Show a message if no item is found.\n     * @returns {object} This view.\n     */\n    nothingFound: function() {\n      this.$el.html(\n        '<p><br><br>Ouch. I am unable to find any item that match the current query.</p>'\n      );\n      App.pageView.hideContentViews();\n      this.$el.show();\n\n      return this;\n    },\n    /**\n     * Scroll to the top of the window with an animation.\n     */\n    scrollTop: function() {\n      // Hack for Chrome/Firefox scroll animation\n      // Chrome scrolls 'body', Firefox scrolls 'html'\n      var scroll = this.$body.scrollTop() > 0 || this.$html.scrollTop() > 0;\n      if (scroll) {\n        this.$scrollBody.animate({ scrollTop: 0 }, 600);\n      }\n    },\n    /**\n     * Helper method to capitalize the first letter of a string\n     * @param {string} str\n     * @returns {string} Returns the string.\n     */\n    capitalizeFirst: function(str) {\n      return str.substr(0, 1).toUpperCase() + str.substr(1);\n    }\n  });\n\n  return itemView;\n});\n\n",
             "\ndefine('text!tpl/menu.html',[],function () { return '<div>\\n  <br>\\n  <span id=\"reference-description1\">Can\\'t find what you\\'re looking for? You may want to check out</span>\\n  <a href=\"#/libraries/p5.sound\">p5.sound</a>.<br><a href=\\'https://p5js.org/offline-reference/p5-reference.zip\\' target=_blank><span id=\"reference-description3\">You can also download an offline version of the reference.</span></a>\\n</div>\\n\\n<div id=\\'collection-list-categories\\'>\\n<h2 class=\"sr-only\" id=\"categories\">Categories</h2>\\n<% var i=0; %>\\n<% var max=Math.floor(groups.length/4); %>\\n<% var rem=groups.length%4; %>\\n\\n<% _.each(groups, function(group){ %>\\n  <% var m = rem > 0 ? 1 : 0 %>\\n  <% if (i === 0) { %>\\n    <ul aria-labelledby=\"categories\">\\n    <% } %>\\n    <li><a href=\"#group-<%=group%>\"><%=group%></a></li>\\n    <% if (i === (max+m-1)) { %>\\n    </ul>\\n  \\t<% rem-- %>\\n  \\t<% i=0 %>\\n  <% } else { %>\\n  \\t<% i++ %>\\n  <% } %>\\n<% }); %>\\n</div>\\n';});\n\n",
             "define('menuView',[\n  'App',\n  'text!tpl/menu.html'\n], function(App, menuTpl) {\n\n  var menuView = Backbone.View.extend({\n    el: '#collection-list-nav',\n    /**\n     * Init.\n     * @returns {object} This view.\n     */\n    init: function() {\n      this.menuTpl = _.template(menuTpl);\n      return this;\n    },\n    /**\n     * Render.\n     * @returns {object} This view.\n     */\n    render: function() {\n\n      var groups = [];\n      _.each(App.modules, function (item, i) {\n        if (!item.is_submodule) {\n          if (!item.file || item.file.indexOf('addons') === -1) { //addons don't get displayed on main page\n            groups.push(item.name);\n          }\n        }\n        //}\n      });\n\n      // Sort groups by name A-Z\n      groups.sort();\n\n      var menuHtml = this.menuTpl({\n        'groups': groups\n      });\n\n      // Render the view\n      this.$el.html(menuHtml);\n    },\n\n    hide: function() {\n      this.$el.hide();\n    },\n\n    show: function() {\n      this.$el.show();\n    },\n\n    /**\n     * Update the menu.\n     * @param {string} el The name of the current route.\n     */\n    update: function(menuItem) {\n      //console.log(menuItem);\n      // this.$menuItems.removeClass('active');\n      // this.$menuItems.find('a[href=#'+menuItem+']').parent().addClass('active');\n\n    }\n  });\n\n  return menuView;\n\n});\n\n",
             "\ndefine('text!tpl/library.html',[],function () { return '<h3><%= module.name %> library</h3>\\n\\n<p><%= module.description %></p>\\n\\n<div id=\"library-page\" class=\"reference-group clearfix\">  \\n\\n<% var t = 0; col = 0; %>\\n\\n<% _.each(groups, function(group){ %>\\n  <% if (t == 0) { %> \\n    <div class=\"column_<%=col%>\">\\n  <% } %>\\n  <% if (group.name !== module.name && group.name !== \\'p5\\') { %>\\n    <% if (group.hash) { %> <a href=\"<%=group.hash%>\" <% if (group.module !== module.name) { %>class=\"core\"<% } %>><% } %>  \\n    <h4 class=\"group-name <% if (t == 0) { %> first<%}%>\"><%=group.name%></h4>\\n    <% if (group.hash) { %> </a><br> <% } %>\\n  <% } %>\\n  <% _.each(group.items.filter(function(item) {return item.access !== \\'private\\'}), function(item) { %>\\n    <a href=\"<%=item.hash%>\" <% if (item.module !== module.name) { %>class=\"core\"<% } %>><%=item.name%><% if (item.itemtype === \\'method\\') { %>()<%}%></a><br>\\n    <% t++; %>\\n  <% }); %>\\n  <% if (t >= Math.floor(totalItems/4)) { col++; t = 0; %>\\n    </div>\\n  <% } %>\\n<% }); %>\\n</div>\\n';});\n\n",
             "define(\n  'libraryView',[\n    'App',\n    // Templates\n    'text!tpl/library.html'\n  ],\n  function(App, libraryTpl) {\n    var libraryView = Backbone.View.extend({\n      el: '#list',\n      events: {},\n      /**\n       * Init.\n       */\n      init: function() {\n        this.libraryTpl = _.template(libraryTpl);\n\n        return this;\n      },\n      /**\n       * Render the list.\n       */\n      render: function(m, listCollection) {\n        if (m && listCollection) {\n          var self = this;\n\n          // Render items and group them by module\n          // module === group\n          this.groups = {};\n          _.each(m.items, function(item, i) {\n            var module = item.module || '_';\n            var group;\n            // Override default group with a selected category\n            // TODO: Overwriting with the first category might not be the best choice\n            // We might also want to have links for categories\n            if (item.category && item.category[0]) {\n              group = item.category[0];\n              // Populate item.hash\n              App.router.getHash(item);\n\n              // Create a group list without link hash\n              if (!self.groups[group]) {\n                self.groups[group] = {\n                  name: group.replace('_', '&nbsp;'),\n                  module: module,\n                  hash: undefined,\n                  items: []\n                };\n              }\n            } else {\n              group = item.class || '_';\n              var hash = App.router.getHash(item);\n\n              var ind = hash.lastIndexOf('/');\n              hash = hash.substring(0, ind);\n\n              // Create a group list\n              if (!self.groups[group]) {\n                self.groups[group] = {\n                  name: group.replace('_', '&nbsp;'),\n                  module: module,\n                  hash: hash,\n                  items: []\n                };\n              }\n            }\n\n            self.groups[group].items.push(item);\n          });\n\n          // Sort groups by name A-Z\n          self.groups = _.sortBy(self.groups, this.sortByName);\n\n          // Put the <li> items html into the list <ul>\n          var libraryHtml = self.libraryTpl({\n            title: self.capitalizeFirst(listCollection),\n            module: m.module,\n            totalItems: m.items.length,\n            groups: self.groups\n          });\n\n          // Render the view\n          this.$el.html(libraryHtml);\n        }\n\n        return this;\n      },\n      /**\n       * Show a list of items.\n       * @param {array} items Array of item objects.\n       * @returns {object} This view.\n       */\n      show: function(listGroup) {\n        if (App[listGroup]) {\n          this.render(App[listGroup], listGroup);\n        }\n        App.pageView.hideContentViews();\n\n        this.$el.show();\n\n        return this;\n      },\n      /**\n       * Helper method to capitalize the first letter of a string\n       * @param {string} str\n       * @returns {string} Returns the string.\n       */\n      capitalizeFirst: function(str) {\n        return str.substr(0, 1).toUpperCase() + str.substr(1);\n      },\n      /**\n       * Sort function (for the Array.prototype.sort() native method): from A to Z.\n       * @param {string} a\n       * @param {string} b\n       * @returns {Array} Returns an array with elements sorted from A to Z.\n       */\n      sortAZ: function(a, b) {\n        return a.innerHTML.toLowerCase() > b.innerHTML.toLowerCase() ? 1 : -1;\n      },\n\n      sortByName: function(a, b) {\n        if (a.name === 'p5') return -1;\n        else return 0;\n      }\n    });\n\n    return libraryView;\n  }\n);\n\n",
        -    "define('pageView',[\n  'App',\n\n  // Views\n  'searchView',\n  'listView',\n  'itemView',\n  'menuView',\n  'libraryView'\n], function(App, searchView, listView, itemView, menuView, libraryView) {\n\n  // Store the original title parts so we can substitue different endings.\n  var _originalDocumentTitle = window.document.title;\n\n  var pageView = Backbone.View.extend({\n    el: 'body',\n    /**\n     * Init.\n     */\n    init: function() {\n      App.$container = $('#container');\n      App.contentViews = [];\n\n      return this;\n    },\n    /**\n     * Render.\n     */\n    render: function() {\n\n      // Menu view\n      if (!App.menuView) {\n        App.menuView = new menuView();\n        App.menuView.init().render();\n      }\n\n      // Item view\n      if (!App.itemView) {\n        App.itemView = new itemView();\n        App.itemView.init().render();\n        // Add the item view to the views array\n        App.contentViews.push(App.itemView);\n      }\n\n      // List view\n      if (!App.listView) {\n        App.listView = new listView();\n        App.listView.init().render();\n        // Add the list view to the views array\n        App.contentViews.push(App.listView);\n      }\n\n      // Library view\n      if (!App.libraryView) {\n        App.libraryView = new libraryView();\n        App.libraryView.init().render();\n        // Add the list view to the views array\n        App.contentViews.push(App.libraryView);\n      }\n\n      // Search\n      if (!App.searchView) {\n        App.searchView = new searchView();\n        App.searchView.init().render();\n      }\n      return this;\n    },\n    /**\n     * Hide item and list views.\n     * @returns {object} This view.\n     */\n    hideContentViews: function() {\n      _.each(App.contentViews, function(view, i) {\n        view.$el.hide();\n      });\n\n      return this;\n    },\n    /**\n     * Append the supplied name to the first part of original document title.\n     * If no name is supplied, the title will reset to the original one.\n     */\n    appendToDocumentTitle: function(name){\n      if(name){\n        let firstTitlePart = _originalDocumentTitle.split(\" | \")[0];\n        window.document.title = [firstTitlePart, name].join(\" | \");\n      } else {\n        window.document.title = _originalDocumentTitle;\n      }\n    }    \n  });\n\n  return pageView;\n\n});\n\n",
        +    "define('pageView',[\n  'App',\n\n  // Views\n  'searchView',\n  'listView',\n  'itemView',\n  'menuView',\n  'libraryView'\n], function(App, searchView, listView, itemView, menuView, libraryView) {\n\n  // Store the original title parts so we can substitute different endings.\n  var _originalDocumentTitle = window.document.title;\n\n  var pageView = Backbone.View.extend({\n    el: 'body',\n    /**\n     * Init.\n     */\n    init: function() {\n      App.$container = $('#container');\n      App.contentViews = [];\n\n      return this;\n    },\n    /**\n     * Render.\n     */\n    render: function() {\n\n      // Menu view\n      if (!App.menuView) {\n        App.menuView = new menuView();\n        App.menuView.init().render();\n      }\n\n      // Item view\n      if (!App.itemView) {\n        App.itemView = new itemView();\n        App.itemView.init().render();\n        // Add the item view to the views array\n        App.contentViews.push(App.itemView);\n      }\n\n      // List view\n      if (!App.listView) {\n        App.listView = new listView();\n        App.listView.init().render();\n        // Add the list view to the views array\n        App.contentViews.push(App.listView);\n      }\n\n      // Library view\n      if (!App.libraryView) {\n        App.libraryView = new libraryView();\n        App.libraryView.init().render();\n        // Add the list view to the views array\n        App.contentViews.push(App.libraryView);\n      }\n\n      // Search\n      if (!App.searchView) {\n        App.searchView = new searchView();\n        App.searchView.init().render();\n      }\n      return this;\n    },\n    /**\n     * Hide item and list views.\n     * @returns {object} This view.\n     */\n    hideContentViews: function() {\n      _.each(App.contentViews, function(view, i) {\n        view.$el.hide();\n      });\n\n      return this;\n    },\n    /**\n     * Append the supplied name to the first part of original document title.\n     * If no name is supplied, the title will reset to the original one.\n     */\n    appendToDocumentTitle: function(name){\n      if(name){\n        let firstTitlePart = _originalDocumentTitle.split(\" | \")[0];\n        window.document.title = [firstTitlePart, name].join(\" | \");\n      } else {\n        window.document.title = _originalDocumentTitle;\n      }\n    }    \n  });\n\n  return pageView;\n\n});\n\n",
             "define('router',[\n  'App'\n], function(App) {\n\n  'use strict'; //\n\n  var Router = Backbone.Router.extend({\n\n    routes: {\n      '': 'list',\n      'p5': 'list',\n      'p5/': 'list',\n      'classes': 'list',\n      'search': 'search',\n      'libraries/:lib': 'library',\n      ':searchClass(/:searchItem)': 'get'\n    },\n    /**\n     * Whether the json API data was loaded.\n     */\n    _initialized: false,\n    /**\n     * Initialize the app: load json API data and create searchable arrays.\n     */\n    init: function(callback) {\n      var self = this;\n      require(['pageView'], function(pageView) {\n\n        // If already initialized, move away from here!\n        if (self._initialized) {\n          if (callback)\n            callback();\n          return;\n        }\n\n        // Update initialization state: must be done now to avoid recursive mess\n        self._initialized = true;\n\n        // Render views\n        if (!App.pageView) {\n          App.pageView = new pageView();\n          App.pageView.init().render();\n        }\n\n        // If a callback is set (a route has already been called), run it\n        // otherwise, show the default list\n        if (callback)\n          callback();\n        else\n          self.list();\n      });\n    },\n    /**\n     * Start route. Simply check if initialized.\n     */\n    start: function() {\n      this.init();\n    },\n    /**\n     * Show item details by searching a class or a class item (method, property or event).\n     * @param {string} searchClass The class name (mandatory).\n     * @param {string} searchItem The class item name: can be a method, property or event name.\n     */\n    get: function(searchClass, searchItem) {\n\n      // if looking for a library page, redirect\n      if (searchClass === 'p5.sound' && !searchItem) {\n        window.location.hash = '/libraries/'+searchClass;\n        return;\n      }\n\n      var self = this;\n      this.init(function() {\n        var item = self.getItem(searchClass, searchItem);\n\n        App.menuView.hide();\n\n        if (item) {\n          App.itemView.show(item);\n        } else {\n          //App.itemView.nothingFound();\n\n          self.list();\n        }\n\n        styleCodeLinks();\n      });\n    },\n    /**\n     * Returns one item object by searching a class or a class item (method, property or event).\n     * @param {string} searchClass The class name (mandatory).\n     * @param {string} searchItem The class item name: can be a method, property or event name.\n     * @returns {object} The item found or undefined if nothing was found.\n     */\n    getItem: function(searchClass, searchItem) {\n      var classes = App.classes,\n              items = App.allItems,\n              classesCount = classes.length,\n              itemsCount = items.length,\n              className = searchClass ? searchClass.toLowerCase() : undefined,\n              itemName = searchItem ? searchItem : undefined,\n              found;\n\n      // Only search for a class, if itemName is undefined\n      if (className && !itemName) {\n        for (var i = 0; i < classesCount; i++) {\n          if (classes[i].name.toLowerCase() === className) {\n            found = classes[i];\n            _.each(found.items, function(i, idx) {\n              i.hash = App.router.getHash(i);\n            });\n            break;\n          }\n        }\n        // Search for a class item\n      } else if (className && itemName) {\n        // Search case sensitively\n        for (var i = 0; i < itemsCount; i++) {\n          if (items[i].class.toLowerCase() === className &&\n            items[i].name === itemName) {\n            found = items[i];\n            break;\n          }\n        }\n\n        // If no match was found, fallback to search case insensitively\n        if(!found){\n          for (var i = 0; i < itemsCount; i++) {\n            if(items[i].class.toLowerCase() === className &&\n              items[i].name.toLowerCase() === itemName.toLowerCase()){\n              found = items[i];\n              break;\n            }\n          }\n        }\n      }\n\n      return found;\n    },\n    /**\n     * List items.\n     * @param {string} collection The name of the collection to list.\n     */\n    list: function(collection) {\n\n      collection = 'allItems';\n\n      // Make sure collection is valid\n      if (App.collections.indexOf(collection) < 0) {\n        return;\n      }\n\n      this.init(function() {\n        App.menuView.show(collection);\n        App.menuView.update(collection);\n        App.listView.show(collection);\n        styleCodeLinks();\n      });\n    },\n    /**\n     * Display information for a library.\n     * @param {string} collection The name of the collection to list.\n     */\n    library: function(collection) {\n      this.init(function() {\n        App.menuView.hide();\n        App.libraryView.show(collection.substring(3)); //remove p5.\n        styleCodeLinks();\n      });\n    },\n    /**\n     * Close all content views.\n     */\n    search: function() {\n      this.init(function() {\n        App.menuView.hide();\n        App.pageView.hideContentViews();\n      });\n    },\n\n    /**\n     * Create an hash/url for the item.\n     * @param {Object} item A class, method, property or event object.\n     * @returns {String} The hash string, including the '#'.\n     */\n     getHash: function(item) {\n\n       if (!item.hash) {\n\n         // FIX TO INVISIBLE OBJECTS: DH (see also listView.js)\n\n         if (item.class) {\n           var clsFunc = '#/' + item.class + '.' + item.name;\n           var idx = clsFunc.lastIndexOf('.');\n           item.hash = clsFunc.substring(0,idx) + '/' + clsFunc.substring(idx+1);\n         } else {\n          item.hash = '#/' + item.name;\n         }\n       }\n\n       return item.hash;\n    }\n  });\n\n  \n  function styleCodeLinks() {\n    var links = document.getElementsByTagName(\"a\");\n    for (var iLink = 0; iLink < links.length; iLink++) {\n      var link = links[iLink];\n      if (link.hash.startsWith('#/p5')) {\n        link.classList.add('code');\n      }\n    }\n  }\n\n\n  // Get the router\n  App.router = new Router();\n\n  // Start history\n  Backbone.history.start();\n\n  return App.router;\n\n});\n\n",
             "/**\n * Define global App.\n */\nvar App = window.App || {};\ndefine('App', [],function() {\n  return App;\n});\n\n/**\n * Load json API data and start the router.\n * @param {module} App\n * @param {module} router\n */\nrequire([\n  'App',\n  './documented-method'], function(App, DocumentedMethod) {\n\n  // Set collections\n  App.collections = ['allItems', 'classes', 'events', 'methods', 'properties', 'p5.sound'];\n\n  // Get json API data\n  $.getJSON('data.min.json', function(data) {\n    App.data = data;\n    App.classes = [];\n    App.methods = [];\n    App.properties = [];\n    App.events = [];\n    App.allItems = [];\n    App.sound = { items: [] };\n    App.dom = { items: [] };\n    App.modules = [];\n    App.project = data.project;\n\n\n    var modules = data.modules;\n\n    // Get class items (methods, properties, events)\n    _.each(modules, function(m, idx, array) {\n      App.modules.push(m);\n      if (m.name == \"p5.sound\") {\n        App.sound.module = m;\n      }\n    });\n\n\n    var items = data.classitems;\n    var classes = data.classes;\n\n    // Get classes\n    _.each(classes, function(c, idx, array) {\n      if (!c.private) {\n        App.classes.push(c);\n      }\n    });\n\n\n    // Get class items (methods, properties, events)\n    _.each(items, function(el, idx, array) {\n      if (el.itemtype) {\n        if (el.itemtype === \"method\") {\n          el = new DocumentedMethod(el);\n          App.methods.push(el);\n          App.allItems.push(el);\n        } else if (el.itemtype === \"property\") {\n          App.properties.push(el);\n          App.allItems.push(el);\n        } else if (el.itemtype === \"event\") {\n          App.events.push(el);\n          App.allItems.push(el);\n        }\n\n        // libraries\n        if (el.module === \"p5.sound\") {\n          App.sound.items.push(el);\n        }\n      }\n    });\n\n    _.each(App.classes, function(c, idx) {\n      c.items = _.filter(App.allItems, function(it){ return it.class === c.name; });\n    });\n\n    require(['router']);\n  });\n});\n\ndefine(\"main\", function(){});\n\n",
             "}());"
           ]
        -}
        \ No newline at end of file
        +}
        
        From 9ee3b484d47460b5ba2d05ff6e3ba6685f51bb89 Mon Sep 17 00:00:00 2001
        From: sukrucildirr <sukrucildirr@gmail.com>
        Date: Wed, 4 Jun 2025 14:10:02 +0300
        Subject: [PATCH 169/282] Update books.xml
        
        ---
         test/unit/assets/books.xml | 4 ++--
         1 file changed, 2 insertions(+), 2 deletions(-)
        
        diff --git a/test/unit/assets/books.xml b/test/unit/assets/books.xml
        index baf002f7f7..3d54056b05 100644
        --- a/test/unit/assets/books.xml
        +++ b/test/unit/assets/books.xml
        @@ -83,7 +83,7 @@
               <genre>Science Fiction</genre>
               <price>6.95</price>
               <publish_date>2000-11-02</publish_date>
        -      <description>After an inadvertant trip through a Heisenberg
        +      <description>After an inadvertent trip through a Heisenberg
               Uncertainty Device, James Salway discovers the problems
               of being quantum.</description>
            </book>
        @@ -117,4 +117,4 @@
               integrated into a comprehensive development
               environment.</description>
            </book>
        -</catalog>
        \ No newline at end of file
        +</catalog>
        
        From 53eb8a4d2d341fbe56b1ac8040c518f581bdbafc Mon Sep 17 00:00:00 2001
        From: sukrucildirr <sukrucildirr@gmail.com>
        Date: Wed, 4 Jun 2025 14:11:07 +0300
        Subject: [PATCH 170/282] Update error_helpers.js
        
        ---
         test/unit/core/error_helpers.js | 8 ++++----
         1 file changed, 4 insertions(+), 4 deletions(-)
        
        diff --git a/test/unit/core/error_helpers.js b/test/unit/core/error_helpers.js
        index 50f5d2bd55..ccdd9d3047 100644
        --- a/test/unit/core/error_helpers.js
        +++ b/test/unit/core/error_helpers.js
        @@ -237,7 +237,7 @@ suite('Error Helpers', function() {
         
           suite('validateParameters: argument tree', function() {
             // should not throw a validation error for the same kind of wrong args
        -    // more than once. This prevents repetetive validation logs for a
        +    // more than once. This prevents repetitive validation logs for a
             // function that is called in a loop or draw()
             testUnMinified(
               'no repeated validation error for the same wrong arguments',
        @@ -440,7 +440,7 @@ suite('Error Helpers', function() {
               }
             );
         
        -    testUnMinified('detects spelling + captialization mistakes', function() {
        +    testUnMinified('detects spelling + capitalization mistakes', function() {
               const logMsg = help(new ReferenceError('RandomGossian is not defined'));
               assert.match(
                 logMsg,
        @@ -566,7 +566,7 @@ suite('Global Error Handling', function() {
             return iframe;
           };
         
        -  testUnMinified('identifies errors happenning internally', function() {
        +  testUnMinified('identifies errors happening internally', function() {
             return new Promise(function(resolve) {
               // quite an unusual way to test, but the error listener doesn't work
               // under mocha. Also the stacktrace gets filled with mocha internal
        @@ -590,7 +590,7 @@ suite('Global Error Handling', function() {
           });
         
           testUnMinified(
        -    'identifies errors happenning internally in ES6 classes',
        +    'identifies errors happening internally in ES6 classes',
             function() {
               return new Promise(function(resolve) {
                 prepSyntaxTest(
        
        From df3f10e4ad45d5246124afa48131debe3111330b Mon Sep 17 00:00:00 2001
        From: sukrucildirr <sukrucildirr@gmail.com>
        Date: Wed, 4 Jun 2025 14:11:52 +0300
        Subject: [PATCH 171/282] Update sketch.js
        
        ---
         test/manual-test-examples/tutorials/DOM-extensions/7/sketch.js | 2 +-
         1 file changed, 1 insertion(+), 1 deletion(-)
        
        diff --git a/test/manual-test-examples/tutorials/DOM-extensions/7/sketch.js b/test/manual-test-examples/tutorials/DOM-extensions/7/sketch.js
        index 3ad19088fe..c43241d7b2 100644
        --- a/test/manual-test-examples/tutorials/DOM-extensions/7/sketch.js
        +++ b/test/manual-test-examples/tutorials/DOM-extensions/7/sketch.js
        @@ -39,7 +39,7 @@ function draw() {
           drawRectCanvas();
         }
         
        -// Addtional drawing functions.
        +// Additional drawing functions.
         function drawEllipseCanvas() {
           background(120, 180, 200);
           ellipse(width / 2, height / 2, 100, 100);
        
        From f90a6db2bbd873d847ab59ff4d89bd6bd7e92044 Mon Sep 17 00:00:00 2001
        From: sukrucildirr <sukrucildirr@gmail.com>
        Date: Wed, 4 Jun 2025 14:12:11 +0300
        Subject: [PATCH 172/282] Update sketch.js
        
        ---
         test/manual-test-examples/tutorials/DOM-extensions/6/sketch.js | 2 +-
         1 file changed, 1 insertion(+), 1 deletion(-)
        
        diff --git a/test/manual-test-examples/tutorials/DOM-extensions/6/sketch.js b/test/manual-test-examples/tutorials/DOM-extensions/6/sketch.js
        index 1bf5484a72..d1df4138ad 100644
        --- a/test/manual-test-examples/tutorials/DOM-extensions/6/sketch.js
        +++ b/test/manual-test-examples/tutorials/DOM-extensions/6/sketch.js
        @@ -35,7 +35,7 @@ function draw() {
           //drawEllipseCanvas();
         }
         
        -// Addtional drawing functions.
        +// Additional drawing functions.
         function drawEllipseCanvas() {
           background(120, 180, 200);
           ellipse(width / 2, height / 2, 100, 100);
        
        From 71b3bfd347d4676f13dd54a54513686e553efd15 Mon Sep 17 00:00:00 2001
        From: sukrucildirr <sukrucildirr@gmail.com>
        Date: Wed, 4 Jun 2025 14:12:55 +0300
        Subject: [PATCH 173/282] Update p5.Table.js
        
        ---
         src/io/p5.Table.js | 4 ++--
         1 file changed, 2 insertions(+), 2 deletions(-)
        
        diff --git a/src/io/p5.Table.js b/src/io/p5.Table.js
        index 4e05615bee..cc0e3f92e9 100644
        --- a/src/io/p5.Table.js
        +++ b/src/io/p5.Table.js
        @@ -1196,7 +1196,7 @@ p5.Table = class {
          *
          * function preload() {
          *   // table is comma separated value "CSV"
        - *   // and has specifiying header for column labels
        + *   // and has specifying header for column labels
          *   table = loadTable('assets/mammals.csv', 'csv', 'header');
          * }
          *
        @@ -1303,7 +1303,7 @@ p5.Table = class {
          *
          * function preload() {
          *   // table is comma separated value "CSV"
        - *   // and has specifiying header for column labels
        + *   // and has specifying header for column labels
          *   table = loadTable('assets/mammals.csv', 'csv', 'header');
          * }
          *
        
        From b52f4435e7346927b6572e11e624621303934080 Mon Sep 17 00:00:00 2001
        From: sukrucildirr <sukrucildirr@gmail.com>
        Date: Wed, 4 Jun 2025 14:13:27 +0300
        Subject: [PATCH 174/282] Update p5.Image.js
        
        ---
         src/image/p5.Image.js | 2 +-
         1 file changed, 1 insertion(+), 1 deletion(-)
        
        diff --git a/src/image/p5.Image.js b/src/image/p5.Image.js
        index 8ab3175afc..1db788cd9c 100644
        --- a/src/image/p5.Image.js
        +++ b/src/image/p5.Image.js
        @@ -798,7 +798,7 @@ p5.Image = class {
            *   // Display the image.
            *   image(img, 17, 17);
            *
        -   *   describe('A square with a horiztonal color gradient from black to white drawn on a gray background.');
        +   *   describe('A square with a horizontal color gradient from black to white drawn on a gray background.');
            * }
            * </code>
            * </div>
        
        From ea57fff11df0a6ce40efab16b682a2429efb0027 Mon Sep 17 00:00:00 2001
        From: sukrucildirr <sukrucildirr@gmail.com>
        Date: Wed, 4 Jun 2025 14:13:52 +0300
        Subject: [PATCH 175/282] Update pixels.js
        
        ---
         src/image/pixels.js | 2 +-
         1 file changed, 1 insertion(+), 1 deletion(-)
        
        diff --git a/src/image/pixels.js b/src/image/pixels.js
        index effda98199..aeaf6761a2 100644
        --- a/src/image/pixels.js
        +++ b/src/image/pixels.js
        @@ -1083,7 +1083,7 @@ p5.prototype.loadPixels = function(...args) {
          *   // Update the canvas.
          *   updatePixels();
          *
        - *   describe('A horiztonal color gradient from black to white.');
        + *   describe('A horizontal color gradient from black to white.');
          * }
          * </code>
          * </div>
        
        From a91ae62fd1f7f8f2226c7d3213cf67583d79a050 Mon Sep 17 00:00:00 2001
        From: sukrucildirr <sukrucildirr@gmail.com>
        Date: Wed, 4 Jun 2025 18:28:42 +0000
        Subject: [PATCH 176/282] Remove generated reference.js.map from PR
        
        ---
         .../assets/js/reference.js.map                | 54 -------------------
         1 file changed, 54 deletions(-)
         delete mode 100644 docs/yuidoc-p5-theme/assets/js/reference.js.map
        
        diff --git a/docs/yuidoc-p5-theme/assets/js/reference.js.map b/docs/yuidoc-p5-theme/assets/js/reference.js.map
        deleted file mode 100644
        index acd5500701..0000000000
        --- a/docs/yuidoc-p5-theme/assets/js/reference.js.map
        +++ /dev/null
        @@ -1,54 +0,0 @@
        -{
        -  "version": 3,
        -  "sources": [
        -    "../../../config-wrap-start-default.js",
        -    "documented-method.js",
        -    "vendor/require/text.js",
        -    "tpl/search.html!text",
        -    "tpl/search_suggestion.html!text",
        -    "vendor/typeahead-amd/typeahead.bundle.js",
        -    "views/searchView.js",
        -    "tpl/list.html!text",
        -    "views/listView.js",
        -    "tpl/item.html!text",
        -    "tpl/class.html!text",
        -    "tpl/itemEnd.html!text",
        -    "vendor/prettify/prettify.js",
        -    "views/itemView.js",
        -    "tpl/menu.html!text",
        -    "views/menuView.js",
        -    "tpl/library.html!text",
        -    "views/libraryView.js",
        -    "views/pageView.js",
        -    "router.js",
        -    "main.js",
        -    "../../../config-wrap-end-default.js"
        -  ],
        -  "names": [],
        -  "mappings": "AAAA;AACA,ACDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC7DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACnYA;AACA;AACA;AACA,ACHA;AACA;AACA;AACA,ACHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC9rDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC3HA;AACA;AACA;AACA,ACHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC3IA;AACA;AACA;AACA,ACHA;AACA;AACA;AACA,ACHA;AACA;AACA;AACA,ACHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC1nDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC/NA;AACA;AACA;AACA,ACHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AClEA;AACA;AACA;AACA,ACHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACjIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AChGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AClOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACxFA",
        -  "file": "reference.js",
        -  "sourcesContent": [
        -    "(function () {\n",
        -    "// https://github.com/umdjs/umd/blob/master/templates/returnExports.js\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    define('documented-method',[], factory);\n  } else if (typeof module === 'object' && module.exports) {\n    module.exports = factory();\n  } else {\n    root.DocumentedMethod = factory();\n  }\n}(this, function () {\n  function extend(target, src) {\n    Object.keys(src).forEach(function(prop) {\n      target[prop] = src[prop];\n    });\n    return target;\n  }\n\n  function DocumentedMethod(classitem) {\n    extend(this, classitem);\n\n    if (this.overloads) {\n      // Make each overload inherit properties from their parent\n      // classitem.\n      this.overloads = this.overloads.map(function(overload) {\n        return extend(Object.create(this), overload);\n      }, this);\n\n      if (this.params) {\n        throw new Error('params for overloaded methods should be undefined');\n      }\n\n      this.params = this._getMergedParams();\n    }\n  }\n\n  DocumentedMethod.prototype = {\n    // Merge parameters across all overloaded versions of this item.\n    _getMergedParams: function() {\n      var paramNames = {};\n      var params = [];\n\n      this.overloads.forEach(function(overload) {\n        if (!overload.params) {\n          return;\n        }\n        overload.params.forEach(function(param) {\n          if (param.name in paramNames) {\n            return;\n          }\n          paramNames[param.name] = param;\n          params.push(param);\n        });\n      });\n\n      return params;\n    }\n  };\n\n  return DocumentedMethod;\n}));\n\n",
        -    "/**\n * @license RequireJS text 2.0.10 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.\n * Available via the MIT or new BSD license.\n * see: http://github.com/requirejs/text for details\n */\n/*jslint regexp: true */\n/*global require, XMLHttpRequest, ActiveXObject,\n  define, window, process, Packages,\n  java, location, Components, FileUtils */\n\ndefine('text',['module'], function (module) {\n    'use strict';\n\n    var text, fs, Cc, Ci, xpcIsWindows,\n        progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'],\n        xmlRegExp = /^\\s*<\\?xml(\\s)+version=[\\'\\\"](\\d)*.(\\d)*[\\'\\\"](\\s)*\\?>/im,\n        bodyRegExp = /<body[^>]*>\\s*([\\s\\S]+)\\s*<\\/body>/im,\n        hasLocation = typeof location !== 'undefined' && location.href,\n        defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\\:/, ''),\n        defaultHostName = hasLocation && location.hostname,\n        defaultPort = hasLocation && (location.port || undefined),\n        buildMap = {},\n        masterConfig = (module.config && module.config()) || {};\n\n    text = {\n        version: '2.0.10',\n\n        strip: function (content) {\n            //Strips <?xml ...?> declarations so that external SVG and XML\n            //documents can be added to a document without worry. Also, if the string\n            //is an HTML document, only the part inside the body tag is returned.\n            if (content) {\n                content = content.replace(xmlRegExp, \"\");\n                var matches = content.match(bodyRegExp);\n                if (matches) {\n                    content = matches[1];\n                }\n            } else {\n                content = \"\";\n            }\n            return content;\n        },\n\n        jsEscape: function (content) {\n            return content.replace(/(['\\\\])/g, '\\\\$1')\n                .replace(/[\\f]/g, \"\\\\f\")\n                .replace(/[\\b]/g, \"\\\\b\")\n                .replace(/[\\n]/g, \"\\\\n\")\n                .replace(/[\\t]/g, \"\\\\t\")\n                .replace(/[\\r]/g, \"\\\\r\")\n                .replace(/[\\u2028]/g, \"\\\\u2028\")\n                .replace(/[\\u2029]/g, \"\\\\u2029\");\n        },\n\n        createXhr: masterConfig.createXhr || function () {\n            //Would love to dump the ActiveX crap in here. Need IE 6 to die first.\n            var xhr, i, progId;\n            if (typeof XMLHttpRequest !== \"undefined\") {\n                return new XMLHttpRequest();\n            } else if (typeof ActiveXObject !== \"undefined\") {\n                for (i = 0; i < 3; i += 1) {\n                    progId = progIds[i];\n                    try {\n                        xhr = new ActiveXObject(progId);\n                    } catch (e) {}\n\n                    if (xhr) {\n                        progIds = [progId];  // so faster next time\n                        break;\n                    }\n                }\n            }\n\n            return xhr;\n        },\n\n        /**\n         * Parses a resource name into its component parts. Resource names\n         * look like: module/name.ext!strip, where the !strip part is\n         * optional.\n         * @param {String} name the resource name\n         * @returns {Object} with properties \"moduleName\", \"ext\" and \"strip\"\n         * where strip is a boolean.\n         */\n        parseName: function (name) {\n            var modName, ext, temp,\n                strip = false,\n                index = name.indexOf(\".\"),\n                isRelative = name.indexOf('./') === 0 ||\n                             name.indexOf('../') === 0;\n\n            if (index !== -1 && (!isRelative || index > 1)) {\n                modName = name.substring(0, index);\n                ext = name.substring(index + 1, name.length);\n            } else {\n                modName = name;\n            }\n\n            temp = ext || modName;\n            index = temp.indexOf(\"!\");\n            if (index !== -1) {\n                //Pull off the strip arg.\n                strip = temp.substring(index + 1) === \"strip\";\n                temp = temp.substring(0, index);\n                if (ext) {\n                    ext = temp;\n                } else {\n                    modName = temp;\n                }\n            }\n\n            return {\n                moduleName: modName,\n                ext: ext,\n                strip: strip\n            };\n        },\n\n        xdRegExp: /^((\\w+)\\:)?\\/\\/([^\\/\\\\]+)/,\n\n        /**\n         * Is an URL on another domain. Only works for browser use, returns\n         * false in non-browser environments. Only used to know if an\n         * optimized .js version of a text resource should be loaded\n         * instead.\n         * @param {String} url\n         * @returns Boolean\n         */\n        useXhr: function (url, protocol, hostname, port) {\n            var uProtocol, uHostName, uPort,\n                match = text.xdRegExp.exec(url);\n            if (!match) {\n                return true;\n            }\n            uProtocol = match[2];\n            uHostName = match[3];\n\n            uHostName = uHostName.split(':');\n            uPort = uHostName[1];\n            uHostName = uHostName[0];\n\n            return (!uProtocol || uProtocol === protocol) &&\n                   (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) &&\n                   ((!uPort && !uHostName) || uPort === port);\n        },\n\n        finishLoad: function (name, strip, content, onLoad) {\n            content = strip ? text.strip(content) : content;\n            if (masterConfig.isBuild) {\n                buildMap[name] = content;\n            }\n            onLoad(content);\n        },\n\n        load: function (name, req, onLoad, config) {\n            //Name has format: some.module.filext!strip\n            //The strip part is optional.\n            //if strip is present, then that means only get the string contents\n            //inside a body tag in an HTML string. For XML/SVG content it means\n            //removing the <?xml ...?> declarations so the content can be inserted\n            //into the current doc without problems.\n\n            // Do not bother with the work if a build and text will\n            // not be inlined.\n            if (config.isBuild && !config.inlineText) {\n                onLoad();\n                return;\n            }\n\n            masterConfig.isBuild = config.isBuild;\n\n            var parsed = text.parseName(name),\n                nonStripName = parsed.moduleName +\n                    (parsed.ext ? '.' + parsed.ext : ''),\n                url = req.toUrl(nonStripName),\n                useXhr = (masterConfig.useXhr) ||\n                         text.useXhr;\n\n            // Do not load if it is an empty: url\n            if (url.indexOf('empty:') === 0) {\n                onLoad();\n                return;\n            }\n\n            //Load the text. Use XHR if possible and in a browser.\n            if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) {\n                text.get(url, function (content) {\n                    text.finishLoad(name, parsed.strip, content, onLoad);\n                }, function (err) {\n                    if (onLoad.error) {\n                        onLoad.error(err);\n                    }\n                });\n            } else {\n                //Need to fetch the resource across domains. Assume\n                //the resource has been optimized into a JS module. Fetch\n                //by the module name + extension, but do not include the\n                //!strip part to avoid file system issues.\n                req([nonStripName], function (content) {\n                    text.finishLoad(parsed.moduleName + '.' + parsed.ext,\n                                    parsed.strip, content, onLoad);\n                });\n            }\n        },\n\n        write: function (pluginName, moduleName, write, config) {\n            if (buildMap.hasOwnProperty(moduleName)) {\n                var content = text.jsEscape(buildMap[moduleName]);\n                write.asModule(pluginName + \"!\" + moduleName,\n                               \"define(function () { return '\" +\n                                   content +\n                               \"';});\\n\");\n            }\n        },\n\n        writeFile: function (pluginName, moduleName, req, write, config) {\n            var parsed = text.parseName(moduleName),\n                extPart = parsed.ext ? '.' + parsed.ext : '',\n                nonStripName = parsed.moduleName + extPart,\n                //Use a '.js' file name so that it indicates it is a\n                //script that can be loaded across domains.\n                fileName = req.toUrl(parsed.moduleName + extPart) + '.js';\n\n            //Leverage own load() method to load plugin value, but only\n            //write out values that do not have the strip argument,\n            //to avoid any potential issues with ! in file names.\n            text.load(nonStripName, req, function (value) {\n                //Use own write() method to construct full module value.\n                //But need to create shell that translates writeFile's\n                //write() to the right interface.\n                var textWrite = function (contents) {\n                    return write(fileName, contents);\n                };\n                textWrite.asModule = function (moduleName, contents) {\n                    return write.asModule(moduleName, fileName, contents);\n                };\n\n                text.write(pluginName, nonStripName, textWrite, config);\n            }, config);\n        }\n    };\n\n    if (masterConfig.env === 'node' || (!masterConfig.env &&\n            typeof process !== \"undefined\" &&\n            process.versions &&\n            !!process.versions.node &&\n            !process.versions['node-webkit'])) {\n        //Using special require.nodeRequire, something added by r.js.\n        fs = require.nodeRequire('fs');\n\n        text.get = function (url, callback, errback) {\n            try {\n                var file = fs.readFileSync(url, 'utf8');\n                //Remove BOM (Byte Mark Order) from utf8 files if it is there.\n                if (file.indexOf('\\uFEFF') === 0) {\n                    file = file.substring(1);\n                }\n                callback(file);\n            } catch (e) {\n                errback(e);\n            }\n        };\n    } else if (masterConfig.env === 'xhr' || (!masterConfig.env &&\n            text.createXhr())) {\n        text.get = function (url, callback, errback, headers) {\n            var xhr = text.createXhr(), header;\n            xhr.open('GET', url, true);\n\n            //Allow plugins direct access to xhr headers\n            if (headers) {\n                for (header in headers) {\n                    if (headers.hasOwnProperty(header)) {\n                        xhr.setRequestHeader(header.toLowerCase(), headers[header]);\n                    }\n                }\n            }\n\n            //Allow overrides specified in config\n            if (masterConfig.onXhr) {\n                masterConfig.onXhr(xhr, url);\n            }\n\n            xhr.onreadystatechange = function (evt) {\n                var status, err;\n                //Do not explicitly handle errors, those should be\n                //visible via console output in the browser.\n                if (xhr.readyState === 4) {\n                    status = xhr.status;\n                    if (status > 399 && status < 600) {\n                        //An http 4xx or 5xx error. Signal an error.\n                        err = new Error(url + ' HTTP status: ' + status);\n                        err.xhr = xhr;\n                        errback(err);\n                    } else {\n                        callback(xhr.responseText);\n                    }\n\n                    if (masterConfig.onXhrComplete) {\n                        masterConfig.onXhrComplete(xhr, url);\n                    }\n                }\n            };\n            xhr.send(null);\n        };\n    } else if (masterConfig.env === 'rhino' || (!masterConfig.env &&\n            typeof Packages !== 'undefined' && typeof java !== 'undefined')) {\n        //Why Java, why is this so awkward?\n        text.get = function (url, callback) {\n            var stringBuffer, line,\n                encoding = \"utf-8\",\n                file = new java.io.File(url),\n                lineSeparator = java.lang.System.getProperty(\"line.separator\"),\n                input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),\n                content = '';\n            try {\n                stringBuffer = new java.lang.StringBuffer();\n                line = input.readLine();\n\n                // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324\n                // http://www.unicode.org/faq/utf_bom.html\n\n                // Note that when we use utf-8, the BOM should appear as \"EF BB BF\", but it doesn't due to this bug in the JDK:\n                // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058\n                if (line && line.length() && line.charAt(0) === 0xfeff) {\n                    // Eat the BOM, since we've already found the encoding on this file,\n                    // and we plan to concatenating this buffer with others; the BOM should\n                    // only appear at the top of a file.\n                    line = line.substring(1);\n                }\n\n                if (line !== null) {\n                    stringBuffer.append(line);\n                }\n\n                while ((line = input.readLine()) !== null) {\n                    stringBuffer.append(lineSeparator);\n                    stringBuffer.append(line);\n                }\n                //Make sure we return a JavaScript string and not a Java string.\n                content = String(stringBuffer.toString()); //String\n            } finally {\n                input.close();\n            }\n            callback(content);\n        };\n    } else if (masterConfig.env === 'xpconnect' || (!masterConfig.env &&\n            typeof Components !== 'undefined' && Components.classes &&\n            Components.interfaces)) {\n        //Avert your gaze!\n        Cc = Components.classes,\n        Ci = Components.interfaces;\n        Components.utils['import']('resource://gre/modules/FileUtils.jsm');\n        xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc);\n\n        text.get = function (url, callback) {\n            var inStream, convertStream, fileObj,\n                readData = {};\n\n            if (xpcIsWindows) {\n                url = url.replace(/\\//g, '\\\\');\n            }\n\n            fileObj = new FileUtils.File(url);\n\n            //XPCOM, you so crazy\n            try {\n                inStream = Cc['@mozilla.org/network/file-input-stream;1']\n                           .createInstance(Ci.nsIFileInputStream);\n                inStream.init(fileObj, 1, 0, false);\n\n                convertStream = Cc['@mozilla.org/intl/converter-input-stream;1']\n                                .createInstance(Ci.nsIConverterInputStream);\n                convertStream.init(inStream, \"utf-8\", inStream.available(),\n                Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);\n\n                convertStream.readString(inStream.available(), readData);\n                convertStream.close();\n                inStream.close();\n                callback(readData.value);\n            } catch (e) {\n                throw new Error((fileObj && fileObj.path || '') + ': ' + e);\n            }\n        };\n    }\n    return text;\n});\n\n",
        -    "\ndefine('text!tpl/search.html',[],function () { return '<h2 class=\"sr-only\">search</h2>\\n<form>\\n  <input id=\"search_reference_field\" type=\"text\" class=\"<%=className%>\" value=\"\" placeholder=\"<%=placeholder%>\" aria-label=\"search reference\">\\n  <label class=\"sr-only\" for=\"search_reference_field\">Search reference</label>\\n</form>\\n\\n';});\n\n",
        -    "\ndefine('text!tpl/search_suggestion.html',[],function () { return '<p id=\"index-<%=idx%>\" class=\"search-suggestion\">\\n\\n  <strong><%=name%></strong>\\n\\n  <span class=\"small\">\\n    <% if (final) { %>\\n    constant\\n    <% } else if (itemtype) { %>\\n    <%=itemtype%> \\n    <% } %>\\n\\n    <% if (className) { %>\\n    in <strong><%=className%></strong>\\n    <% } %>\\n\\n    <% if (typeof is_constructor !== \\'undefined\\' && is_constructor) { %>\\n    <strong><span class=\"glyphicon glyphicon-star\"></span> constructor</strong>\\n    <% } %>\\n  </span>\\n\\n</p>';});\n\n",
        -    "/*!\n * typeahead.js 0.10.2\n * https://github.com/twitter/typeahead.js\n * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT\n */\ndefine('typeahead',[], function() {\n\n//(function($) {\n\n\n    var _ = {\n        isMsie: function() {\n            return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\\d+(.\\d+)?)/i)[2] : false;\n        },\n        isBlankString: function(str) {\n            return !str || /^\\s*$/.test(str);\n        },\n        escapeRegExChars: function(str) {\n            return str.replace(/[\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|]/g, \"\\\\$&\");\n        },\n        isString: function(obj) {\n            return typeof obj === \"string\";\n        },\n        isNumber: function(obj) {\n            return typeof obj === \"number\";\n        },\n        isArray: $.isArray,\n        isFunction: $.isFunction,\n        isObject: $.isPlainObject,\n        isUndefined: function(obj) {\n            return typeof obj === \"undefined\";\n        },\n        bind: $.proxy,\n        each: function(collection, cb) {\n            $.each(collection, reverseArgs);\n            function reverseArgs(index, value) {\n                return cb(value, index);\n            }\n        },\n        map: $.map,\n        filter: $.grep,\n        every: function(obj, test) {\n            var result = true;\n            if (!obj) {\n                return result;\n            }\n            $.each(obj, function(key, val) {\n                if (!(result = test.call(null, val, key, obj))) {\n                    return false;\n                }\n            });\n            return !!result;\n        },\n        some: function(obj, test) {\n            var result = false;\n            if (!obj) {\n                return result;\n            }\n            $.each(obj, function(key, val) {\n                if (result = test.call(null, val, key, obj)) {\n                    return false;\n                }\n            });\n            return !!result;\n        },\n        mixin: $.extend,\n        getUniqueId: function() {\n            var counter = 0;\n            return function() {\n                return counter++;\n            };\n        }(),\n        templatify: function templatify(obj) {\n            return $.isFunction(obj) ? obj : template;\n            function template() {\n                return String(obj);\n            }\n        },\n        defer: function(fn) {\n            setTimeout(fn, 0);\n        },\n        debounce: function(func, wait, immediate) {\n            var timeout, result;\n            return function() {\n                var context = this, args = arguments, later, callNow;\n                later = function() {\n                    timeout = null;\n                    if (!immediate) {\n                        result = func.apply(context, args);\n                    }\n                };\n                callNow = immediate && !timeout;\n                clearTimeout(timeout);\n                timeout = setTimeout(later, wait);\n                if (callNow) {\n                    result = func.apply(context, args);\n                }\n                return result;\n            };\n        },\n        throttle: function(func, wait) {\n            var context, args, timeout, result, previous, later;\n            previous = 0;\n            later = function() {\n                previous = new Date();\n                timeout = null;\n                result = func.apply(context, args);\n            };\n            return function() {\n                var now = new Date(), remaining = wait - (now - previous);\n                context = this;\n                args = arguments;\n                if (remaining <= 0) {\n                    clearTimeout(timeout);\n                    timeout = null;\n                    previous = now;\n                    result = func.apply(context, args);\n                } else if (!timeout) {\n                    timeout = setTimeout(later, remaining);\n                }\n                return result;\n            };\n        },\n        noop: function() {}\n    };\n    var VERSION = \"0.10.2\";\n    var tokenizers = function(root) {\n        return {\n            nonword: nonword,\n            whitespace: whitespace,\n            obj: {\n                nonword: getObjTokenizer(nonword),\n                whitespace: getObjTokenizer(whitespace)\n            }\n        };\n        function whitespace(s) {\n            return s.split(/\\s+/);\n        }\n        function nonword(s) {\n            return s.split(/\\W+/);\n        }\n        function getObjTokenizer(tokenizer) {\n            return function setKey(key) {\n                return function tokenize(o) {\n                    return tokenizer(o[key]);\n                };\n            };\n        }\n    }();\n    var LruCache = function() {\n        function LruCache(maxSize) {\n            this.maxSize = maxSize || 100;\n            this.size = 0;\n            this.hash = {};\n            this.list = new List();\n        }\n        _.mixin(LruCache.prototype, {\n            set: function set(key, val) {\n                var tailItem = this.list.tail, node;\n                if (this.size >= this.maxSize) {\n                    this.list.remove(tailItem);\n                    delete this.hash[tailItem.key];\n                }\n                if (node = this.hash[key]) {\n                    node.val = val;\n                    this.list.moveToFront(node);\n                } else {\n                    node = new Node(key, val);\n                    this.list.add(node);\n                    this.hash[key] = node;\n                    this.size++;\n                }\n            },\n            get: function get(key) {\n                var node = this.hash[key];\n                if (node) {\n                    this.list.moveToFront(node);\n                    return node.val;\n                }\n            }\n        });\n        function List() {\n            this.head = this.tail = null;\n        }\n        _.mixin(List.prototype, {\n            add: function add(node) {\n                if (this.head) {\n                    node.next = this.head;\n                    this.head.prev = node;\n                }\n                this.head = node;\n                this.tail = this.tail || node;\n            },\n            remove: function remove(node) {\n                node.prev ? node.prev.next = node.next : this.head = node.next;\n                node.next ? node.next.prev = node.prev : this.tail = node.prev;\n            },\n            moveToFront: function(node) {\n                this.remove(node);\n                this.add(node);\n            }\n        });\n        function Node(key, val) {\n            this.key = key;\n            this.val = val;\n            this.prev = this.next = null;\n        }\n        return LruCache;\n    }();\n    var PersistentStorage = function() {\n        var ls, methods;\n        try {\n            ls = window.localStorage;\n            ls.setItem(\"~~~\", \"!\");\n            ls.removeItem(\"~~~\");\n        } catch (err) {\n            ls = null;\n        }\n        function PersistentStorage(namespace) {\n            this.prefix = [ \"__\", namespace, \"__\" ].join(\"\");\n            this.ttlKey = \"__ttl__\";\n            this.keyMatcher = new RegExp(\"^\" + this.prefix);\n        }\n        if (ls && window.JSON) {\n            methods = {\n                _prefix: function(key) {\n                    return this.prefix + key;\n                },\n                _ttlKey: function(key) {\n                    return this._prefix(key) + this.ttlKey;\n                },\n                get: function(key) {\n                    if (this.isExpired(key)) {\n                        this.remove(key);\n                    }\n                    return decode(ls.getItem(this._prefix(key)));\n                },\n                set: function(key, val, ttl) {\n                    if (_.isNumber(ttl)) {\n                        ls.setItem(this._ttlKey(key), encode(now() + ttl));\n                    } else {\n                        ls.removeItem(this._ttlKey(key));\n                    }\n                    return ls.setItem(this._prefix(key), encode(val));\n                },\n                remove: function(key) {\n                    ls.removeItem(this._ttlKey(key));\n                    ls.removeItem(this._prefix(key));\n                    return this;\n                },\n                clear: function() {\n                    var i, key, keys = [], len = ls.length;\n                    for (i = 0; i < len; i++) {\n                        if ((key = ls.key(i)).match(this.keyMatcher)) {\n                            keys.push(key.replace(this.keyMatcher, \"\"));\n                        }\n                    }\n                    for (i = keys.length; i--; ) {\n                        this.remove(keys[i]);\n                    }\n                    return this;\n                },\n                isExpired: function(key) {\n                    var ttl = decode(ls.getItem(this._ttlKey(key)));\n                    return _.isNumber(ttl) && now() > ttl ? true : false;\n                }\n            };\n        } else {\n            methods = {\n                get: _.noop,\n                set: _.noop,\n                remove: _.noop,\n                clear: _.noop,\n                isExpired: _.noop\n            };\n        }\n        _.mixin(PersistentStorage.prototype, methods);\n        return PersistentStorage;\n        function now() {\n            return new Date().getTime();\n        }\n        function encode(val) {\n            return JSON.stringify(_.isUndefined(val) ? null : val);\n        }\n        function decode(val) {\n            return JSON.parse(val);\n        }\n    }();\n    var Transport = function() {\n        var pendingRequestsCount = 0, pendingRequests = {}, maxPendingRequests = 6, requestCache = new LruCache(10);\n        function Transport(o) {\n            o = o || {};\n            this._send = o.transport ? callbackToDeferred(o.transport) : $.ajax;\n            this._get = o.rateLimiter ? o.rateLimiter(this._get) : this._get;\n        }\n        Transport.setMaxPendingRequests = function setMaxPendingRequests(num) {\n            maxPendingRequests = num;\n        };\n        Transport.resetCache = function clearCache() {\n            requestCache = new LruCache(10);\n        };\n        _.mixin(Transport.prototype, {\n            _get: function(url, o, cb) {\n                var that = this, jqXhr;\n                if (jqXhr = pendingRequests[url]) {\n                    jqXhr.done(done).fail(fail);\n                } else if (pendingRequestsCount < maxPendingRequests) {\n                    pendingRequestsCount++;\n                    pendingRequests[url] = this._send(url, o).done(done).fail(fail).always(always);\n                } else {\n                    this.onDeckRequestArgs = [].slice.call(arguments, 0);\n                }\n                function done(resp) {\n                    cb && cb(null, resp);\n                    requestCache.set(url, resp);\n                }\n                function fail() {\n                    cb && cb(true);\n                }\n                function always() {\n                    pendingRequestsCount--;\n                    delete pendingRequests[url];\n                    if (that.onDeckRequestArgs) {\n                        that._get.apply(that, that.onDeckRequestArgs);\n                        that.onDeckRequestArgs = null;\n                    }\n                }\n            },\n            get: function(url, o, cb) {\n                var resp;\n                if (_.isFunction(o)) {\n                    cb = o;\n                    o = {};\n                }\n                if (resp = requestCache.get(url)) {\n                    _.defer(function() {\n                        cb && cb(null, resp);\n                    });\n                } else {\n                    this._get(url, o, cb);\n                }\n                return !!resp;\n            }\n        });\n        return Transport;\n        function callbackToDeferred(fn) {\n            return function customSendWrapper(url, o) {\n                var deferred = $.Deferred();\n                fn(url, o, onSuccess, onError);\n                return deferred;\n                function onSuccess(resp) {\n                    _.defer(function() {\n                        deferred.resolve(resp);\n                    });\n                }\n                function onError(err) {\n                    _.defer(function() {\n                        deferred.reject(err);\n                    });\n                }\n            };\n        }\n    }();\n    var SearchIndex = function() {\n        function SearchIndex(o) {\n            o = o || {};\n            if (!o.datumTokenizer || !o.queryTokenizer) {\n                $.error(\"datumTokenizer and queryTokenizer are both required\");\n            }\n            this.datumTokenizer = o.datumTokenizer;\n            this.queryTokenizer = o.queryTokenizer;\n            this.reset();\n        }\n        _.mixin(SearchIndex.prototype, {\n            bootstrap: function bootstrap(o) {\n                this.datums = o.datums;\n                this.trie = o.trie;\n            },\n            add: function(data) {\n                var that = this;\n                data = _.isArray(data) ? data : [ data ];\n                _.each(data, function(datum) {\n                    var id, tokens;\n                    id = that.datums.push(datum) - 1;\n                    tokens = normalizeTokens(that.datumTokenizer(datum));\n                    _.each(tokens, function(token) {\n                        var node, chars, ch;\n                        node = that.trie;\n                        chars = token.split(\"\");\n                        while (ch = chars.shift()) {\n                            node = node.children[ch] || (node.children[ch] = newNode());\n                            node.ids.push(id);\n                        }\n                    });\n                });\n            },\n            get: function get(query) {\n                var that = this, tokens, matches;\n                tokens = normalizeTokens(this.queryTokenizer(query));\n                _.each(tokens, function(token) {\n                    var node, chars, ch, ids;\n                    if (matches && matches.length === 0) {\n                        return false;\n                    }\n                    node = that.trie;\n                    chars = token.split(\"\");\n                    while (node && (ch = chars.shift())) {\n                        node = node.children[ch];\n                    }\n                    if (node && chars.length === 0) {\n                        ids = node.ids.slice(0);\n                        matches = matches ? getIntersection(matches, ids) : ids;\n                    } else {\n                        matches = [];\n                        return false;\n                    }\n                });\n                return matches ? _.map(unique(matches), function(id) {\n                    return that.datums[id];\n                }) : [];\n            },\n            reset: function reset() {\n                this.datums = [];\n                this.trie = newNode();\n            },\n            serialize: function serialize() {\n                return {\n                    datums: this.datums,\n                    trie: this.trie\n                };\n            }\n        });\n        return SearchIndex;\n        function normalizeTokens(tokens) {\n            tokens = _.filter(tokens, function(token) {\n                return !!token;\n            });\n            tokens = _.map(tokens, function(token) {\n                return token.toLowerCase();\n            });\n            return tokens;\n        }\n        function newNode() {\n            return {\n                ids: [],\n                children: {}\n            };\n        }\n        function unique(array) {\n            var seen = {}, uniques = [];\n            for (var i = 0; i < array.length; i++) {\n                if (!seen[array[i]]) {\n                    seen[array[i]] = true;\n                    uniques.push(array[i]);\n                }\n            }\n            return uniques;\n        }\n        function getIntersection(arrayA, arrayB) {\n            var ai = 0, bi = 0, intersection = [];\n            arrayA = arrayA.sort(compare);\n            arrayB = arrayB.sort(compare);\n            while (ai < arrayA.length && bi < arrayB.length) {\n                if (arrayA[ai] < arrayB[bi]) {\n                    ai++;\n                } else if (arrayA[ai] > arrayB[bi]) {\n                    bi++;\n                } else {\n                    intersection.push(arrayA[ai]);\n                    ai++;\n                    bi++;\n                }\n            }\n            return intersection;\n            function compare(a, b) {\n                return a - b;\n            }\n        }\n    }();\n    var oParser = function() {\n        return {\n            local: getLocal,\n            prefetch: getPrefetch,\n            remote: getRemote\n        };\n        function getLocal(o) {\n            return o.local || null;\n        }\n        function getPrefetch(o) {\n            var prefetch, defaults;\n            defaults = {\n                url: null,\n                thumbprint: \"\",\n                ttl: 24 * 60 * 60 * 1e3,\n                filter: null,\n                ajax: {}\n            };\n            if (prefetch = o.prefetch || null) {\n                prefetch = _.isString(prefetch) ? {\n                    url: prefetch\n                } : prefetch;\n                prefetch = _.mixin(defaults, prefetch);\n                prefetch.thumbprint = VERSION + prefetch.thumbprint;\n                prefetch.ajax.type = prefetch.ajax.type || \"GET\";\n                prefetch.ajax.dataType = prefetch.ajax.dataType || \"json\";\n                !prefetch.url && $.error(\"prefetch requires url to be set\");\n            }\n            return prefetch;\n        }\n        function getRemote(o) {\n            var remote, defaults;\n            defaults = {\n                url: null,\n                wildcard: \"%QUERY\",\n                replace: null,\n                rateLimitBy: \"debounce\",\n                rateLimitWait: 300,\n                send: null,\n                filter: null,\n                ajax: {}\n            };\n            if (remote = o.remote || null) {\n                remote = _.isString(remote) ? {\n                    url: remote\n                } : remote;\n                remote = _.mixin(defaults, remote);\n                remote.rateLimiter = /^throttle$/i.test(remote.rateLimitBy) ? byThrottle(remote.rateLimitWait) : byDebounce(remote.rateLimitWait);\n                remote.ajax.type = remote.ajax.type || \"GET\";\n                remote.ajax.dataType = remote.ajax.dataType || \"json\";\n                delete remote.rateLimitBy;\n                delete remote.rateLimitWait;\n                !remote.url && $.error(\"remote requires url to be set\");\n            }\n            return remote;\n            function byDebounce(wait) {\n                return function(fn) {\n                    return _.debounce(fn, wait);\n                };\n            }\n            function byThrottle(wait) {\n                return function(fn) {\n                    return _.throttle(fn, wait);\n                };\n            }\n        }\n    }();\n    (function(root) {\n        var old, keys;\n        old = root.Bloodhound;\n        keys = {\n            data: \"data\",\n            protocol: \"protocol\",\n            thumbprint: \"thumbprint\"\n        };\n        root.Bloodhound = Bloodhound;\n        function Bloodhound(o) {\n            if (!o || !o.local && !o.prefetch && !o.remote) {\n                $.error(\"one of local, prefetch, or remote is required\");\n            }\n            this.limit = o.limit || 5;\n            this.sorter = getSorter(o.sorter);\n            this.dupDetector = o.dupDetector || ignoreDuplicates;\n            this.local = oParser.local(o);\n            this.prefetch = oParser.prefetch(o);\n            this.remote = oParser.remote(o);\n            this.cacheKey = this.prefetch ? this.prefetch.cacheKey || this.prefetch.url : null;\n            this.index = new SearchIndex({\n                datumTokenizer: o.datumTokenizer,\n                queryTokenizer: o.queryTokenizer\n            });\n            this.storage = this.cacheKey ? new PersistentStorage(this.cacheKey) : null;\n        }\n        Bloodhound.noConflict = function noConflict() {\n            root.Bloodhound = old;\n            return Bloodhound;\n        };\n        Bloodhound.tokenizers = tokenizers;\n        _.mixin(Bloodhound.prototype, {\n            _loadPrefetch: function loadPrefetch(o) {\n                var that = this, serialized, deferred;\n                if (serialized = this._readFromStorage(o.thumbprint)) {\n                    this.index.bootstrap(serialized);\n                    deferred = $.Deferred().resolve();\n                } else {\n                    deferred = $.ajax(o.url, o.ajax).done(handlePrefetchResponse);\n                }\n                return deferred;\n                function handlePrefetchResponse(resp) {\n                    that.clear();\n                    that.add(o.filter ? o.filter(resp) : resp);\n                    that._saveToStorage(that.index.serialize(), o.thumbprint, o.ttl);\n                }\n            },\n            _getFromRemote: function getFromRemote(query, cb) {\n                var that = this, url, uriEncodedQuery;\n                query = query || \"\";\n                uriEncodedQuery = encodeURIComponent(query);\n                url = this.remote.replace ? this.remote.replace(this.remote.url, query) : this.remote.url.replace(this.remote.wildcard, uriEncodedQuery);\n                return this.transport.get(url, this.remote.ajax, handleRemoteResponse);\n                function handleRemoteResponse(err, resp) {\n                    err ? cb([]) : cb(that.remote.filter ? that.remote.filter(resp) : resp);\n                }\n            },\n            _saveToStorage: function saveToStorage(data, thumbprint, ttl) {\n                if (this.storage) {\n                    this.storage.set(keys.data, data, ttl);\n                    this.storage.set(keys.protocol, location.protocol, ttl);\n                    this.storage.set(keys.thumbprint, thumbprint, ttl);\n                }\n            },\n            _readFromStorage: function readFromStorage(thumbprint) {\n                var stored = {}, isExpired;\n                if (this.storage) {\n                    stored.data = this.storage.get(keys.data);\n                    stored.protocol = this.storage.get(keys.protocol);\n                    stored.thumbprint = this.storage.get(keys.thumbprint);\n                }\n                isExpired = stored.thumbprint !== thumbprint || stored.protocol !== location.protocol;\n                return stored.data && !isExpired ? stored.data : null;\n            },\n            _initialize: function initialize() {\n                var that = this, local = this.local, deferred;\n                deferred = this.prefetch ? this._loadPrefetch(this.prefetch) : $.Deferred().resolve();\n                local && deferred.done(addLocalToIndex);\n                this.transport = this.remote ? new Transport(this.remote) : null;\n                return this.initPromise = deferred.promise();\n                function addLocalToIndex() {\n                    that.add(_.isFunction(local) ? local() : local);\n                }\n            },\n            initialize: function initialize(force) {\n                return !this.initPromise || force ? this._initialize() : this.initPromise;\n            },\n            add: function add(data) {\n                this.index.add(data);\n            },\n            get: function get(query, cb) {\n                var that = this, matches = [], cacheHit = false;\n                matches = this.index.get(query);\n                matches = this.sorter(matches).slice(0, this.limit);\n                if (matches.length < this.limit && this.transport) {\n                    cacheHit = this._getFromRemote(query, returnRemoteMatches);\n                }\n                if (!cacheHit) {\n                    (matches.length > 0 || !this.transport) && cb && cb(matches);\n                }\n                function returnRemoteMatches(remoteMatches) {\n                    var matchesWithBackfill = matches.slice(0);\n                    _.each(remoteMatches, function(remoteMatch) {\n                        var isDuplicate;\n                        isDuplicate = _.some(matchesWithBackfill, function(match) {\n                            return that.dupDetector(remoteMatch, match);\n                        });\n                        !isDuplicate && matchesWithBackfill.push(remoteMatch);\n                        return matchesWithBackfill.length < that.limit;\n                    });\n                    cb && cb(that.sorter(matchesWithBackfill));\n                }\n            },\n            clear: function clear() {\n                this.index.reset();\n            },\n            clearPrefetchCache: function clearPrefetchCache() {\n                this.storage && this.storage.clear();\n            },\n            clearRemoteCache: function clearRemoteCache() {\n                this.transport && Transport.resetCache();\n            },\n            ttAdapter: function ttAdapter() {\n                return _.bind(this.get, this);\n            }\n        });\n        return Bloodhound;\n        function getSorter(sortFn) {\n            return _.isFunction(sortFn) ? sort : noSort;\n            function sort(array) {\n                return array.sort(sortFn);\n            }\n            function noSort(array) {\n                return array;\n            }\n        }\n        function ignoreDuplicates() {\n            return false;\n        }\n    })(this);\n    var html = {\n        wrapper: '<span class=\"twitter-typeahead\"></span>',\n        dropdown: '<span class=\"tt-dropdown-menu\"></span>',\n        dataset: '<div class=\"tt-dataset-%CLASS%\"></div>',\n        suggestions: '<span class=\"tt-suggestions\"></span>',\n        suggestion: '<div class=\"tt-suggestion\"></div>'\n    };\n    var css = {\n        wrapper: {\n            position: \"relative\",\n            display: \"inline-block\"\n        },\n        hint: {\n            position: \"absolute\",\n            top: \"0\",\n            left: \"0\",\n            borderColor: \"transparent\",\n            boxShadow: \"none\"\n        },\n        input: {\n            position: \"relative\",\n            verticalAlign: \"top\",\n            backgroundColor: \"transparent\"\n        },\n        inputWithNoHint: {\n            position: \"relative\",\n            verticalAlign: \"top\"\n        },\n        dropdown: {\n            position: \"absolute\",\n            top: \"100%\",\n            left: \"0\",\n            zIndex: \"100\",\n            display: \"none\"\n        },\n        suggestions: {\n            display: \"block\"\n        },\n        suggestion: {\n            whiteSpace: \"nowrap\",\n            cursor: \"pointer\"\n        },\n        suggestionChild: {\n            whiteSpace: \"normal\"\n        },\n        ltr: {\n            left: \"0\",\n            right: \"auto\"\n        },\n        rtl: {\n            left: \"auto\",\n            right: \" 0\"\n        }\n    };\n    if (_.isMsie()) {\n        _.mixin(css.input, {\n            backgroundImage: \"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)\"\n        });\n    }\n    if (_.isMsie() && _.isMsie() <= 7) {\n        _.mixin(css.input, {\n            marginTop: \"-1px\"\n        });\n    }\n    var EventBus = function() {\n        var namespace = \"typeahead:\";\n        function EventBus(o) {\n            if (!o || !o.el) {\n                $.error(\"EventBus initialized without el\");\n            }\n            this.$el = $(o.el);\n        }\n        _.mixin(EventBus.prototype, {\n            trigger: function(type) {\n                var args = [].slice.call(arguments, 1);\n                this.$el.trigger(namespace + type, args);\n            }\n        });\n        return EventBus;\n    }();\n    var EventEmitter = function() {\n        var splitter = /\\s+/, nextTick = getNextTick();\n        return {\n            onSync: onSync,\n            onAsync: onAsync,\n            off: off,\n            trigger: trigger\n        };\n        function on(method, types, cb, context) {\n            var type;\n            if (!cb) {\n                return this;\n            }\n            types = types.split(splitter);\n            cb = context ? bindContext(cb, context) : cb;\n            this._callbacks = this._callbacks || {};\n            while (type = types.shift()) {\n                this._callbacks[type] = this._callbacks[type] || {\n                    sync: [],\n                    async: []\n                };\n                this._callbacks[type][method].push(cb);\n            }\n            return this;\n        }\n        function onAsync(types, cb, context) {\n            return on.call(this, \"async\", types, cb, context);\n        }\n        function onSync(types, cb, context) {\n            return on.call(this, \"sync\", types, cb, context);\n        }\n        function off(types) {\n            var type;\n            if (!this._callbacks) {\n                return this;\n            }\n            types = types.split(splitter);\n            while (type = types.shift()) {\n                delete this._callbacks[type];\n            }\n            return this;\n        }\n        function trigger(types) {\n            var type, callbacks, args, syncFlush, asyncFlush;\n            if (!this._callbacks) {\n                return this;\n            }\n            types = types.split(splitter);\n            args = [].slice.call(arguments, 1);\n            while ((type = types.shift()) && (callbacks = this._callbacks[type])) {\n                syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args));\n                asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args));\n                syncFlush() && nextTick(asyncFlush);\n            }\n            return this;\n        }\n        function getFlush(callbacks, context, args) {\n            return flush;\n            function flush() {\n                var cancelled;\n                for (var i = 0; !cancelled && i < callbacks.length; i += 1) {\n                    cancelled = callbacks[i].apply(context, args) === false;\n                }\n                return !cancelled;\n            }\n        }\n        function getNextTick() {\n            var nextTickFn;\n            if (window.setImmediate) {\n                nextTickFn = function nextTickSetImmediate(fn) {\n                    setImmediate(function() {\n                        fn();\n                    });\n                };\n            } else {\n                nextTickFn = function nextTickSetTimeout(fn) {\n                    setTimeout(function() {\n                        fn();\n                    }, 0);\n                };\n            }\n            return nextTickFn;\n        }\n        function bindContext(fn, context) {\n            return fn.bind ? fn.bind(context) : function() {\n                fn.apply(context, [].slice.call(arguments, 0));\n            };\n        }\n    }();\n    var highlight = function(doc) {\n        var defaults = {\n            node: null,\n            pattern: null,\n            tagName: \"strong\",\n            className: null,\n            wordsOnly: false,\n            caseSensitive: false\n        };\n        return function highlight(o) {\n            var regex;\n            o = _.mixin({}, defaults, o);\n            if (!o.node || !o.pattern) {\n                return;\n            }\n            o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ];\n            regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly);\n            traverse(o.node, highlightTextNode);\n            function highlightTextNode(textNode) {\n                var match, patternNode;\n                if (match = regex.exec(textNode.data)) {\n                    wrapperNode = doc.createElement(o.tagName);\n                    o.className && (wrapperNode.className = o.className);\n                    patternNode = textNode.splitText(match.index);\n                    patternNode.splitText(match[0].length);\n                    wrapperNode.appendChild(patternNode.cloneNode(true));\n                    textNode.parentNode.replaceChild(wrapperNode, patternNode);\n                }\n                return !!match;\n            }\n            function traverse(el, highlightTextNode) {\n                var childNode, TEXT_NODE_TYPE = 3;\n                for (var i = 0; i < el.childNodes.length; i++) {\n                    childNode = el.childNodes[i];\n                    if (childNode.nodeType === TEXT_NODE_TYPE) {\n                        i += highlightTextNode(childNode) ? 1 : 0;\n                    } else {\n                        traverse(childNode, highlightTextNode);\n                    }\n                }\n            }\n        };\n        function getRegex(patterns, caseSensitive, wordsOnly) {\n            var escapedPatterns = [], regexStr;\n            for (var i = 0; i < patterns.length; i++) {\n                escapedPatterns.push(_.escapeRegExChars(patterns[i]));\n            }\n            regexStr = wordsOnly ? \"\\\\b(\" + escapedPatterns.join(\"|\") + \")\\\\b\" : \"(\" + escapedPatterns.join(\"|\") + \")\";\n            return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, \"i\");\n        }\n    }(window.document);\n    var Input = function() {\n        var specialKeyCodeMap;\n        specialKeyCodeMap = {\n            9: \"tab\",\n            27: \"esc\",\n            37: \"left\",\n            39: \"right\",\n            13: \"enter\",\n            38: \"up\",\n            40: \"down\"\n        };\n        function Input(o) {\n            var that = this, onBlur, onFocus, onKeydown, onInput;\n            o = o || {};\n            if (!o.input) {\n                $.error(\"input is missing\");\n            }\n            onBlur = _.bind(this._onBlur, this);\n            onFocus = _.bind(this._onFocus, this);\n            onKeydown = _.bind(this._onKeydown, this);\n            onInput = _.bind(this._onInput, this);\n            this.$hint = $(o.hint);\n            this.$input = $(o.input).on(\"blur.tt\", onBlur).on(\"focus.tt\", onFocus).on(\"keydown.tt\", onKeydown);\n            if (this.$hint.length === 0) {\n                this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop;\n            }\n            if (!_.isMsie()) {\n                this.$input.on(\"input.tt\", onInput);\n            } else {\n                this.$input.on(\"keydown.tt keypress.tt cut.tt paste.tt\", function($e) {\n                    if (specialKeyCodeMap[$e.which || $e.keyCode]) {\n                        return;\n                    }\n                    _.defer(_.bind(that._onInput, that, $e));\n                });\n            }\n            this.query = this.$input.val();\n            this.$overflowHelper = buildOverflowHelper(this.$input);\n        }\n        Input.normalizeQuery = function(str) {\n            return (str || \"\").replace(/^\\s*/g, \"\").replace(/\\s{2,}/g, \" \");\n        };\n        _.mixin(Input.prototype, EventEmitter, {\n            _onBlur: function onBlur() {\n                this.resetInputValue();\n                this.trigger(\"blurred\");\n            },\n            _onFocus: function onFocus() {\n                this.trigger(\"focused\");\n            },\n            _onKeydown: function onKeydown($e) {\n                var keyName = specialKeyCodeMap[$e.which || $e.keyCode];\n                this._managePreventDefault(keyName, $e);\n                if (keyName && this._shouldTrigger(keyName, $e)) {\n                    this.trigger(keyName + \"Keyed\", $e);\n                }\n            },\n            _onInput: function onInput() {\n                this._checkInputValue();\n            },\n            _managePreventDefault: function managePreventDefault(keyName, $e) {\n                var preventDefault, hintValue, inputValue;\n                switch (keyName) {\n                  case \"tab\":\n                    hintValue = this.getHint();\n                    inputValue = this.getInputValue();\n                    preventDefault = hintValue && hintValue !== inputValue && !withModifier($e);\n                    break;\n\n                  case \"up\":\n                  case \"down\":\n                    preventDefault = !withModifier($e);\n                    break;\n\n                  default:\n                    preventDefault = false;\n                }\n                preventDefault && $e.preventDefault();\n            },\n            _shouldTrigger: function shouldTrigger(keyName, $e) {\n                var trigger;\n                switch (keyName) {\n                  case \"tab\":\n                    trigger = !withModifier($e);\n                    break;\n\n                  default:\n                    trigger = true;\n                }\n                return trigger;\n            },\n            _checkInputValue: function checkInputValue() {\n                var inputValue, areEquivalent, hasDifferentWhitespace;\n                inputValue = this.getInputValue();\n                areEquivalent = areQueriesEquivalent(inputValue, this.query);\n                hasDifferentWhitespace = areEquivalent ? this.query.length !== inputValue.length : false;\n                if (!areEquivalent) {\n                    this.trigger(\"queryChanged\", this.query = inputValue);\n                } else if (hasDifferentWhitespace) {\n                    this.trigger(\"whitespaceChanged\", this.query);\n                }\n            },\n            focus: function focus() {\n                this.$input.focus();\n            },\n            blur: function blur() {\n                this.$input.blur();\n            },\n            getQuery: function getQuery() {\n                return this.query;\n            },\n            setQuery: function setQuery(query) {\n                this.query = query;\n            },\n            getInputValue: function getInputValue() {\n                return this.$input.val();\n            },\n            setInputValue: function setInputValue(value, silent) {\n                this.$input.val(value);\n                silent ? this.clearHint() : this._checkInputValue();\n            },\n            resetInputValue: function resetInputValue() {\n                this.setInputValue(this.query, true);\n            },\n            getHint: function getHint() {\n                return this.$hint.val();\n            },\n            setHint: function setHint(value) {\n                this.$hint.val(value);\n            },\n            clearHint: function clearHint() {\n                this.setHint(\"\");\n            },\n            clearHintIfInvalid: function clearHintIfInvalid() {\n                var val, hint, valIsPrefixOfHint, isValid;\n                val = this.getInputValue();\n                hint = this.getHint();\n                valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0;\n                isValid = val !== \"\" && valIsPrefixOfHint && !this.hasOverflow();\n                !isValid && this.clearHint();\n            },\n            getLanguageDirection: function getLanguageDirection() {\n                return (this.$input.css(\"direction\") || \"ltr\").toLowerCase();\n            },\n            hasOverflow: function hasOverflow() {\n                var constraint = this.$input.width() - 2;\n                this.$overflowHelper.text(this.getInputValue());\n                return this.$overflowHelper.width() >= constraint;\n            },\n            isCursorAtEnd: function() {\n                var valueLength, selectionStart, range;\n                valueLength = this.$input.val().length;\n                selectionStart = this.$input[0].selectionStart;\n                if (_.isNumber(selectionStart)) {\n                    return selectionStart === valueLength;\n                } else if (document.selection) {\n                    range = document.selection.createRange();\n                    range.moveStart(\"character\", -valueLength);\n                    return valueLength === range.text.length;\n                }\n                return true;\n            },\n            destroy: function destroy() {\n                this.$hint.off(\".tt\");\n                this.$input.off(\".tt\");\n                this.$hint = this.$input = this.$overflowHelper = null;\n            }\n        });\n        return Input;\n        function buildOverflowHelper($input) {\n            return $('<pre aria-hidden=\"true\"></pre>').css({\n                position: \"absolute\",\n                visibility: \"hidden\",\n                whiteSpace: \"pre\",\n                fontFamily: $input.css(\"font-family\"),\n                fontSize: $input.css(\"font-size\"),\n                fontStyle: $input.css(\"font-style\"),\n                fontVariant: $input.css(\"font-variant\"),\n                fontWeight: $input.css(\"font-weight\"),\n                wordSpacing: $input.css(\"word-spacing\"),\n                letterSpacing: $input.css(\"letter-spacing\"),\n                textIndent: $input.css(\"text-indent\"),\n                textRendering: $input.css(\"text-rendering\"),\n                textTransform: $input.css(\"text-transform\")\n            }).insertAfter($input);\n        }\n        function areQueriesEquivalent(a, b) {\n            return Input.normalizeQuery(a) === Input.normalizeQuery(b);\n        }\n        function withModifier($e) {\n            return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey;\n        }\n    }();\n    var Dataset = function() {\n        var datasetKey = \"ttDataset\", valueKey = \"ttValue\", datumKey = \"ttDatum\";\n        function Dataset(o) {\n            o = o || {};\n            o.templates = o.templates || {};\n            if (!o.source) {\n                $.error(\"missing source\");\n            }\n            if (o.name && !isValidName(o.name)) {\n                $.error(\"invalid dataset name: \" + o.name);\n            }\n            this.query = null;\n            this.highlight = !!o.highlight;\n            this.name = o.name || _.getUniqueId();\n            this.source = o.source;\n            this.displayFn = getDisplayFn(o.display || o.displayKey);\n            this.templates = getTemplates(o.templates, this.displayFn);\n            this.$el = $(html.dataset.replace(\"%CLASS%\", this.name));\n        }\n        Dataset.extractDatasetName = function extractDatasetName(el) {\n            return $(el).data(datasetKey);\n        };\n        Dataset.extractValue = function extractDatum(el) {\n            return $(el).data(valueKey);\n        };\n        Dataset.extractDatum = function extractDatum(el) {\n            return $(el).data(datumKey);\n        };\n        _.mixin(Dataset.prototype, EventEmitter, {\n            _render: function render(query, suggestions) {\n                if (!this.$el) {\n                    return;\n                }\n                var that = this, hasSuggestions;\n                this.$el.empty();\n                hasSuggestions = suggestions && suggestions.length;\n                if (!hasSuggestions && this.templates.empty) {\n                    this.$el.html(getEmptyHtml()).prepend(that.templates.header ? getHeaderHtml() : null).append(that.templates.footer ? getFooterHtml() : null);\n                } else if (hasSuggestions) {\n                    this.$el.html(getSuggestionsHtml()).prepend(that.templates.header ? getHeaderHtml() : null).append(that.templates.footer ? getFooterHtml() : null);\n                }\n                this.trigger(\"rendered\");\n                function getEmptyHtml() {\n                    return that.templates.empty({\n                        query: query,\n                        isEmpty: true\n                    });\n                }\n                function getSuggestionsHtml() {\n                    var $suggestions, nodes;\n                    $suggestions = $(html.suggestions).css(css.suggestions);\n                    nodes = _.map(suggestions, getSuggestionNode);\n                    $suggestions.append.apply($suggestions, nodes);\n                    that.highlight && highlight({\n                        node: $suggestions[0],\n                        pattern: query\n                    });\n                    return $suggestions;\n                    function getSuggestionNode(suggestion) {\n                        var $el;\n                        $el = $(html.suggestion).append(that.templates.suggestion(suggestion)).data(datasetKey, that.name).data(valueKey, that.displayFn(suggestion)).data(datumKey, suggestion);\n                        $el.children().each(function() {\n                            $(this).css(css.suggestionChild);\n                        });\n                        return $el;\n                    }\n                }\n                function getHeaderHtml() {\n                    return that.templates.header({\n                        query: query,\n                        isEmpty: !hasSuggestions\n                    });\n                }\n                function getFooterHtml() {\n                    return that.templates.footer({\n                        query: query,\n                        isEmpty: !hasSuggestions\n                    });\n                }\n            },\n            getRoot: function getRoot() {\n                return this.$el;\n            },\n            update: function update(query) {\n                var that = this;\n                this.query = query;\n                this.canceled = false;\n                this.source(query, render);\n                function render(suggestions) {\n                    if (!that.canceled && query === that.query) {\n                        that._render(query, suggestions);\n                    }\n                }\n            },\n            cancel: function cancel() {\n                this.canceled = true;\n            },\n            clear: function clear() {\n                this.cancel();\n                this.$el.empty();\n                this.trigger(\"rendered\");\n            },\n            isEmpty: function isEmpty() {\n                return this.$el.is(\":empty\");\n            },\n            destroy: function destroy() {\n                this.$el = null;\n            }\n        });\n        return Dataset;\n        function getDisplayFn(display) {\n            display = display || \"value\";\n            return _.isFunction(display) ? display : displayFn;\n            function displayFn(obj) {\n                return obj[display];\n            }\n        }\n        function getTemplates(templates, displayFn) {\n            return {\n                empty: templates.empty && _.templatify(templates.empty),\n                header: templates.header && _.templatify(templates.header),\n                footer: templates.footer && _.templatify(templates.footer),\n                suggestion: templates.suggestion || suggestionTemplate\n            };\n            function suggestionTemplate(context) {\n                return \"<p>\" + displayFn(context) + \"</p>\";\n            }\n        }\n        function isValidName(str) {\n            return /^[_a-zA-Z0-9-]+$/.test(str);\n        }\n    }();\n    var Dropdown = function() {\n        function Dropdown(o) {\n            var that = this, onSuggestionClick, onSuggestionMouseEnter, onSuggestionMouseLeave;\n            o = o || {};\n            if (!o.menu) {\n                $.error(\"menu is required\");\n            }\n            this.isOpen = false;\n            this.isEmpty = true;\n            this.datasets = _.map(o.datasets, initializeDataset);\n            onSuggestionClick = _.bind(this._onSuggestionClick, this);\n            onSuggestionMouseEnter = _.bind(this._onSuggestionMouseEnter, this);\n            onSuggestionMouseLeave = _.bind(this._onSuggestionMouseLeave, this);\n            this.$menu = $(o.menu).on(\"click.tt\", \".tt-suggestion\", onSuggestionClick).on(\"mouseenter.tt\", \".tt-suggestion\", onSuggestionMouseEnter).on(\"mouseleave.tt\", \".tt-suggestion\", onSuggestionMouseLeave);\n            _.each(this.datasets, function(dataset) {\n                that.$menu.append(dataset.getRoot());\n                dataset.onSync(\"rendered\", that._onRendered, that);\n            });\n        }\n        _.mixin(Dropdown.prototype, EventEmitter, {\n            _onSuggestionClick: function onSuggestionClick($e) {\n                this.trigger(\"suggestionClicked\", $($e.currentTarget));\n            },\n            _onSuggestionMouseEnter: function onSuggestionMouseEnter($e) {\n                this._removeCursor();\n                this._setCursor($($e.currentTarget), true);\n            },\n            _onSuggestionMouseLeave: function onSuggestionMouseLeave() {\n                this._removeCursor();\n            },\n            _onRendered: function onRendered() {\n                this.isEmpty = _.every(this.datasets, isDatasetEmpty);\n                this.isEmpty ? this._hide() : this.isOpen && this._show();\n                this.trigger(\"datasetRendered\");\n                function isDatasetEmpty(dataset) {\n                    return dataset.isEmpty();\n                }\n            },\n            _hide: function() {\n                this.$menu.hide();\n            },\n            _show: function() {\n                this.$menu.css(\"display\", \"block\");\n            },\n            _getSuggestions: function getSuggestions() {\n                return this.$menu.find(\".tt-suggestion\");\n            },\n            _getCursor: function getCursor() {\n                return this.$menu.find(\".tt-cursor\").first();\n            },\n            _setCursor: function setCursor($el, silent) {\n                $el.first().addClass(\"tt-cursor\");\n                !silent && this.trigger(\"cursorMoved\");\n            },\n            _removeCursor: function removeCursor() {\n                this._getCursor().removeClass(\"tt-cursor\");\n            },\n            _moveCursor: function moveCursor(increment) {\n                var $suggestions, $oldCursor, newCursorIndex, $newCursor;\n                if (!this.isOpen) {\n                    return;\n                }\n                $oldCursor = this._getCursor();\n                $suggestions = this._getSuggestions();\n                this._removeCursor();\n                newCursorIndex = $suggestions.index($oldCursor) + increment;\n                newCursorIndex = (newCursorIndex + 1) % ($suggestions.length + 1) - 1;\n                if (newCursorIndex === -1) {\n                    this.trigger(\"cursorRemoved\");\n                    return;\n                } else if (newCursorIndex < -1) {\n                    newCursorIndex = $suggestions.length - 1;\n                }\n                this._setCursor($newCursor = $suggestions.eq(newCursorIndex));\n                this._ensureVisible($newCursor);\n            },\n            _ensureVisible: function ensureVisible($el) {\n                var elTop, elBottom, menuScrollTop, menuHeight;\n                elTop = $el.position().top;\n                elBottom = elTop + $el.outerHeight(true);\n                menuScrollTop = this.$menu.scrollTop();\n                menuHeight = this.$menu.height() + parseInt(this.$menu.css(\"paddingTop\"), 10) + parseInt(this.$menu.css(\"paddingBottom\"), 10);\n                if (elTop < 0) {\n                    this.$menu.scrollTop(menuScrollTop + elTop);\n                } else if (menuHeight < elBottom) {\n                    this.$menu.scrollTop(menuScrollTop + (elBottom - menuHeight));\n                }\n            },\n            close: function close() {\n                if (this.isOpen) {\n                    this.isOpen = false;\n                    this._removeCursor();\n                    this._hide();\n                    this.trigger(\"closed\");\n                }\n            },\n            open: function open() {\n                if (!this.isOpen) {\n                    this.isOpen = true;\n                    !this.isEmpty && this._show();\n                    this.trigger(\"opened\");\n                }\n            },\n            setLanguageDirection: function setLanguageDirection(dir) {\n                this.$menu.css(dir === \"ltr\" ? css.ltr : css.rtl);\n            },\n            moveCursorUp: function moveCursorUp() {\n                this._moveCursor(-1);\n            },\n            moveCursorDown: function moveCursorDown() {\n                this._moveCursor(+1);\n            },\n            getDatumForSuggestion: function getDatumForSuggestion($el) {\n                var datum = null;\n                if ($el.length) {\n                    datum = {\n                        raw: Dataset.extractDatum($el),\n                        value: Dataset.extractValue($el),\n                        datasetName: Dataset.extractDatasetName($el)\n                    };\n                }\n                return datum;\n            },\n            getDatumForCursor: function getDatumForCursor() {\n                return this.getDatumForSuggestion(this._getCursor().first());\n            },\n            getDatumForTopSuggestion: function getDatumForTopSuggestion() {\n                return this.getDatumForSuggestion(this._getSuggestions().first());\n            },\n            update: function update(query) {\n                _.each(this.datasets, updateDataset);\n                function updateDataset(dataset) {\n                    dataset.update(query);\n                }\n            },\n            empty: function empty() {\n                _.each(this.datasets, clearDataset);\n                this.isEmpty = true;\n                function clearDataset(dataset) {\n                    dataset.clear();\n                }\n            },\n            isVisible: function isVisible() {\n                return this.isOpen && !this.isEmpty;\n            },\n            destroy: function destroy() {\n                this.$menu.off(\".tt\");\n                this.$menu = null;\n                _.each(this.datasets, destroyDataset);\n                function destroyDataset(dataset) {\n                    dataset.destroy();\n                }\n            }\n        });\n        return Dropdown;\n        function initializeDataset(oDataset) {\n            return new Dataset(oDataset);\n        }\n    }();\n    var Typeahead = function() {\n        var attrsKey = \"ttAttrs\";\n        function Typeahead(o) {\n            var $menu, $input, $hint;\n            o = o || {};\n            if (!o.input) {\n                $.error(\"missing input\");\n            }\n            this.isActivated = false;\n            this.autoselect = !!o.autoselect;\n            this.minLength = _.isNumber(o.minLength) ? o.minLength : 1;\n            this.$node = buildDomStructure(o.input, o.withHint);\n            $menu = this.$node.find(\".tt-dropdown-menu\");\n            $input = this.$node.find(\".tt-input\");\n            $hint = this.$node.find(\".tt-hint\");\n            $input.on(\"blur.tt\", function($e) {\n                var active, isActive, hasActive;\n                active = document.activeElement;\n                isActive = $menu.is(active);\n                hasActive = $menu.has(active).length > 0;\n                if (_.isMsie() && (isActive || hasActive)) {\n                    $e.preventDefault();\n                    $e.stopImmediatePropagation();\n                    _.defer(function() {\n                        $input.focus();\n                    });\n                }\n            });\n            $menu.on(\"mousedown.tt\", function($e) {\n                $e.preventDefault();\n            });\n            this.eventBus = o.eventBus || new EventBus({\n                el: $input\n            });\n            this.dropdown = new Dropdown({\n                menu: $menu,\n                datasets: o.datasets\n            }).onSync(\"suggestionClicked\", this._onSuggestionClicked, this).onSync(\"cursorMoved\", this._onCursorMoved, this).onSync(\"cursorRemoved\", this._onCursorRemoved, this).onSync(\"opened\", this._onOpened, this).onSync(\"closed\", this._onClosed, this).onAsync(\"datasetRendered\", this._onDatasetRendered, this);\n            this.input = new Input({\n                input: $input,\n                hint: $hint\n            }).onSync(\"focused\", this._onFocused, this).onSync(\"blurred\", this._onBlurred, this).onSync(\"enterKeyed\", this._onEnterKeyed, this).onSync(\"tabKeyed\", this._onTabKeyed, this).onSync(\"escKeyed\", this._onEscKeyed, this).onSync(\"upKeyed\", this._onUpKeyed, this).onSync(\"downKeyed\", this._onDownKeyed, this).onSync(\"leftKeyed\", this._onLeftKeyed, this).onSync(\"rightKeyed\", this._onRightKeyed, this).onSync(\"queryChanged\", this._onQueryChanged, this).onSync(\"whitespaceChanged\", this._onWhitespaceChanged, this);\n            this._setLanguageDirection();\n        }\n        _.mixin(Typeahead.prototype, {\n            _onSuggestionClicked: function onSuggestionClicked(type, $el) {\n                var datum;\n                if (datum = this.dropdown.getDatumForSuggestion($el)) {\n                    this._select(datum);\n                }\n            },\n            _onCursorMoved: function onCursorMoved() {\n                var datum = this.dropdown.getDatumForCursor();\n                this.input.setInputValue(datum.value, true);\n                this.eventBus.trigger(\"cursorchanged\", datum.raw, datum.datasetName);\n            },\n            _onCursorRemoved: function onCursorRemoved() {\n                this.input.resetInputValue();\n                this._updateHint();\n            },\n            _onDatasetRendered: function onDatasetRendered() {\n                this._updateHint();\n            },\n            _onOpened: function onOpened() {\n                this._updateHint();\n                this.eventBus.trigger(\"opened\");\n            },\n            _onClosed: function onClosed() {\n                this.input.clearHint();\n                this.eventBus.trigger(\"closed\");\n            },\n            _onFocused: function onFocused() {\n                this.isActivated = true;\n                this.dropdown.open();\n            },\n            _onBlurred: function onBlurred() {\n                this.isActivated = false;\n                this.dropdown.empty();\n                this.dropdown.close();\n                this.setVal(\"\", true); //LM\n            },\n            _onEnterKeyed: function onEnterKeyed(type, $e) {\n                var cursorDatum, topSuggestionDatum;\n                cursorDatum = this.dropdown.getDatumForCursor();\n                topSuggestionDatum = this.dropdown.getDatumForTopSuggestion();\n                if (cursorDatum) {\n                    this._select(cursorDatum);\n                    $e.preventDefault();\n                } else if (this.autoselect && topSuggestionDatum) {\n                    this._select(topSuggestionDatum);\n                    $e.preventDefault();\n                }\n            },\n            _onTabKeyed: function onTabKeyed(type, $e) {\n                var datum;\n                if (datum = this.dropdown.getDatumForCursor()) {\n                    this._select(datum);\n                    $e.preventDefault();\n                } else {\n                    this._autocomplete(true);\n                }\n            },\n            _onEscKeyed: function onEscKeyed() {\n                this.dropdown.close();\n                this.input.resetInputValue();\n            },\n            _onUpKeyed: function onUpKeyed() {\n                var query = this.input.getQuery();\n                this.dropdown.isEmpty && query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.moveCursorUp();\n                this.dropdown.open();\n            },\n            _onDownKeyed: function onDownKeyed() {\n                var query = this.input.getQuery();\n                this.dropdown.isEmpty && query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.moveCursorDown();\n                this.dropdown.open();\n            },\n            _onLeftKeyed: function onLeftKeyed() {\n                this.dir === \"rtl\" && this._autocomplete();\n            },\n            _onRightKeyed: function onRightKeyed() {\n                this.dir === \"ltr\" && this._autocomplete();\n            },\n            _onQueryChanged: function onQueryChanged(e, query) {\n                this.input.clearHintIfInvalid();\n                query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.empty();\n                this.dropdown.open();\n                this._setLanguageDirection();\n            },\n            _onWhitespaceChanged: function onWhitespaceChanged() {\n                this._updateHint();\n                this.dropdown.open();\n            },\n            _setLanguageDirection: function setLanguageDirection() {\n                var dir;\n                if (this.dir !== (dir = this.input.getLanguageDirection())) {\n                    this.dir = dir;\n                    this.$node.css(\"direction\", dir);\n                    this.dropdown.setLanguageDirection(dir);\n                }\n            },\n            _updateHint: function updateHint() {\n                var datum, val, query, escapedQuery, frontMatchRegEx, match;\n                datum = this.dropdown.getDatumForTopSuggestion();\n                if (datum && this.dropdown.isVisible() && !this.input.hasOverflow()) {\n                    val = this.input.getInputValue();\n                    query = Input.normalizeQuery(val);\n                    escapedQuery = _.escapeRegExChars(query);\n                    frontMatchRegEx = new RegExp(\"^(?:\" + escapedQuery + \")(.+$)\", \"i\");\n                    match = frontMatchRegEx.exec(datum.value);\n                    match ? this.input.setHint(val + match[1]) : this.input.clearHint();\n                } else {\n                    this.input.clearHint();\n                }\n            },\n            _autocomplete: function autocomplete(laxCursor) {\n                var hint, query, isCursorAtEnd, datum;\n                hint = this.input.getHint();\n                query = this.input.getQuery();\n                isCursorAtEnd = laxCursor || this.input.isCursorAtEnd();\n                if (hint && query !== hint && isCursorAtEnd) {\n                    datum = this.dropdown.getDatumForTopSuggestion();\n                    datum && this.input.setInputValue(datum.value);\n                    this.eventBus.trigger(\"autocompleted\", datum.raw, datum.datasetName);\n                }\n            },\n            _select: function select(datum) {\n                this.input.setQuery(datum.value);\n                this.input.setInputValue(datum.value, true);\n                this._setLanguageDirection();\n                this.eventBus.trigger(\"selected\", datum.raw, datum.datasetName);\n                this.dropdown.close();\n                _.defer(_.bind(this.dropdown.empty, this.dropdown));\n            },\n            open: function open() {\n                this.dropdown.open();\n            },\n            close: function close() {\n                this.dropdown.close();\n            },\n            setVal: function setVal(val) {\n                if (this.isActivated) {\n                    this.input.setInputValue(val);\n                } else {\n                    this.input.setQuery(val);\n                    this.input.setInputValue(val, true);\n                }\n                this._setLanguageDirection();\n            },\n            getVal: function getVal() {\n                return this.input.getQuery();\n            },\n            destroy: function destroy() {\n                this.input.destroy();\n                this.dropdown.destroy();\n                destroyDomStructure(this.$node);\n                this.$node = null;\n            }\n        });\n        return Typeahead;\n        function buildDomStructure(input, withHint) {\n            var $input, $wrapper, $dropdown, $hint;\n            $input = $(input);\n            $wrapper = $(html.wrapper).css(css.wrapper);\n            $dropdown = $(html.dropdown).css(css.dropdown);\n            $hint = $input.clone().css(css.hint).css(getBackgroundStyles($input));\n            $hint.val(\"\").removeData().addClass(\"tt-hint\").removeAttr(\"id name placeholder\").prop(\"disabled\", true).attr({\n                autocomplete: \"off\",\n                spellcheck: \"false\"\n            });\n            $input.data(attrsKey, {\n                dir: $input.attr(\"dir\"),\n                autocomplete: $input.attr(\"autocomplete\"),\n                spellcheck: $input.attr(\"spellcheck\"),\n                style: $input.attr(\"style\")\n            });\n            $input.addClass(\"tt-input\").attr({\n                autocomplete: \"off\",\n                spellcheck: false\n            }).css(withHint ? css.input : css.inputWithNoHint);\n            try {\n                !$input.attr(\"dir\") && $input.attr(\"dir\", \"auto\");\n            } catch (e) {}\n            return $input.wrap($wrapper).parent().prepend(withHint ? $hint : null).append($dropdown);\n        }\n        function getBackgroundStyles($el) {\n            return {\n                backgroundAttachment: $el.css(\"background-attachment\"),\n                backgroundClip: $el.css(\"background-clip\"),\n                backgroundColor: $el.css(\"background-color\"),\n                backgroundImage: $el.css(\"background-image\"),\n                backgroundOrigin: $el.css(\"background-origin\"),\n                backgroundPosition: $el.css(\"background-position\"),\n                backgroundRepeat: $el.css(\"background-repeat\"),\n                backgroundSize: $el.css(\"background-size\")\n            };\n        }\n        function destroyDomStructure($node) {\n            var $input = $node.find(\".tt-input\");\n            _.each($input.data(attrsKey), function(val, key) {\n                _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val);\n            });\n            $input.detach().removeData(attrsKey).removeClass(\"tt-input\").insertAfter($node);\n            $node.remove();\n        }\n    }();\n    (function() {\n        var old, typeaheadKey, methods;\n        old = $.fn.typeahead;\n        typeaheadKey = \"ttTypeahead\";\n        methods = {\n            initialize: function initialize(o, datasets) {\n                datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1);\n                o = o || {};\n                return this.each(attach);\n                function attach() {\n                    var $input = $(this), eventBus, typeahead;\n                    _.each(datasets, function(d) {\n                        d.highlight = !!o.highlight;\n                    });\n                    typeahead = new Typeahead({\n                        input: $input,\n                        eventBus: eventBus = new EventBus({\n                            el: $input\n                        }),\n                        withHint: _.isUndefined(o.hint) ? true : !!o.hint,\n                        minLength: o.minLength,\n                        autoselect: o.autoselect,\n                        datasets: datasets\n                    });\n                    $input.data(typeaheadKey, typeahead);\n                }\n            },\n            open: function open() {\n                return this.each(openTypeahead);\n                function openTypeahead() {\n                    var $input = $(this), typeahead;\n                    if (typeahead = $input.data(typeaheadKey)) {\n                        typeahead.open();\n                    }\n                }\n            },\n            close: function close() {\n                return this.each(closeTypeahead);\n                function closeTypeahead() {\n                    var $input = $(this), typeahead;\n                    if (typeahead = $input.data(typeaheadKey)) {\n                        typeahead.close();\n                    }\n                }\n            },\n            val: function val(newVal) {\n                return !arguments.length ? getVal(this.first()) : this.each(setVal);\n                function setVal() {\n                    var $input = $(this), typeahead;\n                    if (typeahead = $input.data(typeaheadKey)) {\n                        typeahead.setVal(newVal);\n                    }\n                }\n                function getVal($input) {\n                    var typeahead, query;\n                    if (typeahead = $input.data(typeaheadKey)) {\n                        query = typeahead.getVal();\n                    }\n                    return query;\n                }\n            },\n            destroy: function destroy() {\n                return this.each(unattach);\n                function unattach() {\n                    var $input = $(this), typeahead;\n                    if (typeahead = $input.data(typeaheadKey)) {\n                        typeahead.destroy();\n                        $input.removeData(typeaheadKey);\n                    }\n                }\n            }\n        };\n        $.fn.typeahead = function(method) {\n            if (methods[method]) {\n                return methods[method].apply(this, [].slice.call(arguments, 1));\n            } else {\n                return methods.initialize.apply(this, arguments);\n            }\n        };\n        $.fn.typeahead.noConflict = function noConflict() {\n            $.fn.typeahead = old;\n            return this;\n        };\n    })();\n    \n    \n    \n//})(window.jQuery);\n\n\n});\n",
        -    "define('searchView',[\n  'App',\n  // Templates\n  'text!tpl/search.html',\n  'text!tpl/search_suggestion.html',\n  // Tools\n  'typeahead'\n], function(App, searchTpl, suggestionTpl) {\n\n  var searchView = Backbone.View.extend({\n    el: '#search',\n    /**\n     * Init.\n     */\n    init: function() {\n      var tpl = _.template(searchTpl);\n      var className = 'form-control input-lg';\n      var placeholder = 'Search reference';\n      this.searchHtml = tpl({\n        'placeholder': placeholder,\n        'className': className\n      });\n      this.items = App.classes.concat(App.allItems);\n\n      return this;\n    },\n    /**\n     * Render input field with Typehead activated.\n     */\n    render: function() {\n      // Append the view to the dom\n      this.$el.append(this.searchHtml);\n\n      // Render Typeahead\n      var $searchInput = this.$el.find('input[type=text]');\n      this.typeaheadRender($searchInput);\n      this.typeaheadEvents($searchInput);\n\n      return this;\n    },\n    /**\n     * Apply Twitter Typeahead to the search input field.\n     * @param {jquery} $input\n     */\n    typeaheadRender: function($input) {\n      var self = this;\n      $input.typeahead(null, {\n        'displayKey': 'name',\n        'minLength': 2,\n        //'highlight': true,\n        'source': self.substringMatcher(this.items),\n        'templates': {\n          'empty': '<p class=\"empty-message\">Unable to find any item that match the current query</p>',\n          'suggestion': _.template(suggestionTpl)\n        }\n      });\n    },\n    /**\n     * Setup typeahead custom events (item selected).\n     */\n    typeaheadEvents: function($input) {\n      var self = this;\n      $input.on('typeahead:selected', function(e, item, datasetName) {\n        var selectedItem = self.items[item.idx];\n        select(selectedItem);\n      });\n      $input.on('keydown', function(e) {\n        if (e.which === 13) { // enter\n          var txt = $input.val();\n          var f = _.find(self.items, function(it) { return it.name == txt; });\n          if (f) {\n            select(f);\n          }\n        } else if (e.which === 27) {\n          $input.blur();\n        }\n      });\n\n      function select(selectedItem) {\n        var hash = App.router.getHash(selectedItem);//\n        App.router.navigate(hash, {'trigger': true});\n        $('#item').focus();\n      }\n    },\n    /**\n     * substringMatcher function for Typehead (search for strings in an array).\n     * @param {array} array\n     * @returns {Function}\n     */\n    substringMatcher: function(array) {\n      return function findMatches(query, callback) {\n        var matches = [], substrRegex, arrayLength = array.length;\n\n        // regex used to determine if a string contains the substring `query`\n        substrRegex = new RegExp(query, 'i');\n\n        // iterate through the pool of strings and for any string that\n        // contains the substring `query`, add it to the `matches` array\n        for (var i=0; i < arrayLength; i++) {\n          var item = array[i];\n          if (substrRegex.test(item.name)) {\n            // typeahead expects suggestions to be a js object\n            matches.push({\n              'itemtype': item.itemtype,\n              'name': item.name,\n              'className': item.class,\n              'is_constructor': !!item.is_constructor,\n              'final': item.final,\n              'idx': i\n            });\n          }\n        }\n\n        callback(matches);\n      };\n    }\n\n  });\n\n  return searchView;\n\n});\n\n",
        -    "\ndefine('text!tpl/list.html',[],function () { return '<% _.each(groups, function(group){ %>\\n  <div class=\"reference-group clearfix main-ref-page\">  \\n    <h2 class=\"group-name\" id=\"group-<%=group.name%>\" tab-index=\"-1\"><%=group.name%></h2>\\n    <div class=\"reference-subgroups clearfix main-ref-page\">  \\n    <% _.each(group.subgroups, function(subgroup, ind) { %>\\n      <div class=\"reference-subgroup\">\\n        <% if (subgroup.name !== \\'0\\') { %>\\n          <h3 id=\"<%=group.name%><%=ind%>\" class=\"subgroup-name subgroup-<%=subgroup.name%>\"><%=subgroup.name%></h3>\\n        <% } %>\\n        <ul aria-labelledby=\"<%=group.name%> <%=ind%>\">\\n        <% _.each(subgroup.items, function(item) { %>\\n        <li><a href=\"<%=item.hash%>\"><%=item.name%><% if (item.itemtype === \\'method\\') { %>()<%}%></a></li>\\n        <% }); %>\\n        </ul>\\n      </div>\\n    <% }); %>\\n    </div>\\n  </div>\\n<% }); %>\\n';});\n\n",
        -    "define('listView',[\n  'App',\n  // Templates\n  'text!tpl/list.html'\n], function (App, listTpl) {\n  var striptags = function(html) {\n    var div = document.createElement('div');\n    div.innerHTML = html;\n    return div.textContent;\n  };\n\n  var listView = Backbone.View.extend({\n    el: '#list',\n    events: {},\n    /**\n     * Init.\n     */\n    init: function () {\n      this.listTpl = _.template(listTpl);\n\n      return this;\n    },\n    /**\n     * Render the list.\n     */\n    render: function (items, listCollection) {\n      if (items && listCollection) {\n        var self = this;\n\n        // Render items and group them by module\n        // module === group\n        this.groups = {};\n        _.each(items, function (item, i) {\n\n          if (!item.private && item.file.indexOf('addons') === -1) { //addons don't get displayed on main page\n\n            var group = item.module || '_';\n            var subgroup = item.submodule || '_';\n            if (group === subgroup) {\n              subgroup = '0';\n            }\n            var hash = App.router.getHash(item);\n\n            // fixes broken links for #/p5/> and #/p5/>=\n            item.hash = item.hash.replace('>', '&gt;');\n\n            // Create a group list\n            if (!self.groups[group]) {\n              self.groups[group] = {\n                name: group.replace('_', '&nbsp;'),\n                subgroups: {}\n              };\n            }\n\n            // Create a subgroup list\n            if (!self.groups[group].subgroups[subgroup]) {\n              self.groups[group].subgroups[subgroup] = {\n                name: subgroup.replace('_', '&nbsp;'),\n                items: []\n              };\n            }\n\n            // hide the un-interesting constants\n            if (group === 'Constants' && !item.example)\n              return;\n\n            if (item.class === 'p5') {\n\n              self.groups[group].subgroups[subgroup].items.push(item);\n\n            } else {\n\n              var found = _.find(self.groups[group].subgroups[subgroup].items,\n                function(i){ return i.name == item.class; });\n\n              if (!found) {\n\n                // FIX TO INVISIBLE OBJECTS: DH (see also router.js)\n                var ind = hash.lastIndexOf('/');\n                hash = item.hash.substring(0, ind).replace('p5/','p5.');\n                self.groups[group].subgroups[subgroup].items.push({\n                  name: item.class,\n                  hash: hash\n                });\n              }\n\n            }\n          }\n        });\n\n        // Put the <li> items html into the list <ul>\n        var listHtml = self.listTpl({\n          'striptags': striptags,\n          'title': self.capitalizeFirst(listCollection),\n          'groups': self.groups,\n          'listCollection': listCollection\n        });\n\n        // Render the view\n        this.$el.html(listHtml);\n      }\n\n      var renderEvent = new Event('reference-rendered');\n      window.dispatchEvent(renderEvent);\n\n      return this;\n    },\n    /**\n     * Show a list of items.\n     * @param {array} items Array of item objects.\n     * @returns {object} This view.\n     */\n    show: function (listGroup) {\n      if (App[listGroup]) {\n        this.render(App[listGroup], listGroup);\n      }\n      App.pageView.hideContentViews();\n\n      this.$el.show();\n\n      return this;\n    },\n    /**\n     * Helper method to capitalize the first letter of a string\n     * @param {string} str\n     * @returns {string} Returns the string.\n     */\n    capitalizeFirst: function (str) {\n      return str.substr(0, 1).toUpperCase() + str.substr(1);\n    }\n\n\n\n  });\n\n  return listView;\n\n});\n\n",
        -    "\ndefine('text!tpl/item.html',[],function () { return '<h2><%=item.name%><% if (item.isMethod) { %>()<% } %></h2>\\n\\n<% if (item.example) { %>\\n<div class=\"example\">\\n  <h3 id=\"reference-example\">Examples</h3>\\n\\n  <div class=\"example-content\" data-alt=\"<%= item.alt %>\">\\n    <% _.each(item.example, function(example, i){ %>\\n      <%= example %>\\n    <% }); %>\\n  </div>\\n</div>\\n<% } %>\\n\\n<div class=\"description\">\\n    \\n  <h3 id=\"reference-description\">Description</h3>\\n\\n  <% if (item.deprecated) { %>\\n    <p>\\n      Deprecated: <%=item.name%><% if (item.isMethod) { %>()<% } %> is deprecated and will be removed in a future version of p5. <% if (item.deprecationMessage) { %><%=item.deprecationMessage%><% } %>\\n    </p>\\n  <% } %>\\n      \\n\\n  <span class=\\'description-text\\'><%= item.description %></span>\\n\\n  <% if (item.extends) { %>\\n    <p><span id=\"reference-extends\">Extends</span> <a href=\"/reference/#/<%=item.extends%>\" title=\"<%=item.extends%> reference\"><%=item.extends%></a></p>\\n  <% } %>\\n\\n  <% if (item.module === \\'p5.sound\\') { %>\\n    <p>This function requires you include the p5.sound library.  Add the following into the head of your index.html file:\\n      <pre><code class=\"language-javascript\">&lt;script src=\"path/to/p5.sound.js\"&gt;&lt;/script&gt;</code></pre>\\n    </p>\\n  <% } %>\\n\\n  <% if (item.constRefs) { %>\\n    <p>Used by:\\n  <%\\n      var refs = item.constRefs;\\n      for (var i = 0; i < refs.length; i ++) {\\n        var ref = refs[i];\\n        var name = ref;\\n        if (name.substr(0, 3) === \\'p5.\\') {\\n          name = name.substr(3);\\n        }\\n  if (i !== 0) {\\n          if (i == refs.length - 1) {\\n            %> and <%\\n          } else {\\n            %>, <%\\n          }\\n        }\\n        %><a href=\"./#/<%= ref.replace(\\'.\\', \\'/\\') %>\"><%= name %>()</a><%\\n      }\\n  %>\\n    </p>\\n  <% } %>\\n</div>\\n\\n<% if (isConstructor || !isClass) { %>\\n\\n<div>\\n  <h3 id=\"reference-syntax\">Syntax</h3>\\n  <p>\\n    <% syntaxes.forEach(function(syntax) { %>\\n    <pre><code class=\"language-javascript\"><%= syntax %></code></pre>\\n    <% }) %>\\n  </p>\\n</div>\\n\\n\\n<% if (item.params) { %>\\n  <div class=\"params\">\\n    <h3 id=\"reference-parameters\">Parameters</h3>\\n    <ul aria-labelledby=\\'reference-parameters\\'>\\n    <% for (var i=0; i<item.params.length; i++) { %>\\n      <% var p = item.params[i] %>\\n      <li>\\n        <div class=\\'paramname\\'><%=p.name%></div>\\n        <% if (p.type) { %>\\n          <div class=\\'paramtype\\'>\\n          <% var type = p.type.replace(/(p5\\\\.[A-Z][A-Za-z]*)/, \\'<a href=\"#/$1\">$1</a>\\'); %>\\n          <span class=\"param-type label label-info\"><%=type%></span>: <%=p.description%>\\n          <% if (p.optional) { %> (Optional)<% } %>\\n          </div>\\n        <% } %>\\n      </li>\\n    <% } %>\\n    </ul>\\n  </div>\\n<% } %>\\n\\n<% if (item.return && item.return.type) { %>\\n  <div>\\n    <h3 id=\"reference-returns\">Returns</h3>\\n    <p class=\\'returns\\'><span class=\"param-type label label-info\"><%=item.return.type%></span>: <%= item.return.description %></p>\\n  </div>\\n<% } %>\\n\\n<% } %>\\n';});\n\n",
        -    "\ndefine('text!tpl/class.html',[],function () { return '\\n<% if (typeof constructor !== \\'undefined\\') { %>\\n<div class=\"constructor\">\\n  <%=constructor%>\\n</div>\\n<% } %>\\n\\n<% let fields = _.filter(things, function(item) { return item.itemtype === \\'property\\' && item.access !== \\'private\\' }); %>\\n<% if (fields.length > 0) { %>\\n  <h3 id=\\'reference-fields\\'>Fields</h3>\\n  <ul aria-labelledby=\\'reference-fields\\'>\\n  <% _.each(fields, function(item) { %>\\n    <li>\\n      <div class=\\'paramname\\'><a href=\"<%=item.hash%>\" <% if (item.module !== module) { %>class=\"addon\"<% } %>><%=item.name%></a></div>\\n      <div class=\\'paramtype\\'><%= item.description %></div>\\n    </li>\\n  <% }); %>\\n  </ul>\\n<% } %>\\n\\n<% let methods = _.filter(things, function(item) { return item.itemtype === \\'method\\' && item.access !== \\'private\\' }); %>\\n<% if (methods.length > 0) { %>\\n  <h3 id=\\'reference-methods\\'>Methods</h3>\\n  <ul aria-labelledby=\\'reference-methods\\'>\\n    <% _.each(methods, function(item) { %>\\n      <li>\\n        <div class=\\'paramname\\'><a href=\"<%=item.hash%>\" <% if (item.module !== module) { %>class=\"addon\"<% } %>><%=item.name%><% if (item.itemtype === \\'method\\') { %>()<%}%></a></div>\\n        <div class=\\'paramtype\\'><%= item.description %></div>\\n      </li>\\n    <% }); %>\\n  </ul>\\n<% } %>\\n';});\n\n",
        -    "\ndefine('text!tpl/itemEnd.html',[],function () { return '\\n<br><br>\\n\\n<div>\\n<% if (item.file && item.line) { %>\\n<span id=\"reference-error1\">Notice any errors or typos?</span> <a href=\"https://github.com/processing/p5.js/issues\"><span id=\"reference-contribute2\">Please let us know.</span></a> <span id=\"reference-error3\">Please feel free to edit</span> <a href=\"https://github.com/processing/p5.js/blob/<%= appVersion %>/<%= item.file %>#L<%= item.line %>\" target=\"_blank\" ><%= item.file %></a> <span id=\"reference-error5\">and issue a pull request!</span>\\n<% } %>\\n</div>\\n\\n<a style=\"border-bottom:none !important;\" href=\"http://creativecommons.org/licenses/by-nc-sa/4.0/\" target=_blank><img src=\"https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png\" style=\"width:88px\" alt=\"creative commons logo\"/></a>\\n<br><br>\\n';});\n\n",
        -    "// Copyright (C) 2006 Google Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n\n/**\n * @fileoverview\n * some functions for browser-side pretty printing of code contained in html.\n *\n * <p>\n * For a fairly comprehensive set of languages see the\n * <a href=\"http://google-code-prettify.googlecode.com/svn/trunk/README.html#langs\">README</a>\n * file that came with this source.  At a minimum, the lexer should work on a\n * number of languages including C and friends, Java, Python, Bash, SQL, HTML,\n * XML, CSS, Javascript, and Makefiles.  It works passably on Ruby, PHP and Awk\n * and a subset of Perl, but, because of commenting conventions, doesn't work on\n * Smalltalk, Lisp-like, or CAML-like languages without an explicit lang class.\n * <p>\n * Usage: <ol>\n * <li> include this source file in an html page via\n *   {@code <script src=\"/path/to/prettify.js\"></script>}\n * <li> define style rules.  See the example page for examples.\n * <li> mark the {@code <pre>} and {@code <code>} tags in your source with\n *    {@code class=prettyprint.}\n *    You can also use the (html deprecated) {@code <xmp>} tag, but the pretty\n *    printer needs to do more substantial DOM manipulations to support that, so\n *    some css styles may not be preserved.\n * </ol>\n * That's it.  I wanted to keep the API as simple as possible, so there's no\n * need to specify which language the code is in, but if you wish, you can add\n * another class to the {@code <pre>} or {@code <code>} element to specify the\n * language, as in {@code <pre class=\"prettyprint lang-java\">}.  Any class that\n * starts with \"lang-\" followed by a file extension, specifies the file type.\n * See the \"lang-*.js\" files in this directory for code that implements\n * per-language file handlers.\n * <p>\n * Change log:<br>\n * cbeust, 2006/08/22\n * <blockquote>\n *   Java annotations (start with \"@\") are now captured as literals (\"lit\")\n * </blockquote>\n * @requires console\n */\n\n// JSLint declarations\n/*global console, document, navigator, setTimeout, window, define */\n\n/** @define {boolean} */\nvar IN_GLOBAL_SCOPE = true;\n\n/**\n * Split {@code prettyPrint} into multiple timeouts so as not to interfere with\n * UI events.\n * If set to {@code false}, {@code prettyPrint()} is synchronous.\n */\nwindow['PR_SHOULD_USE_CONTINUATION'] = true;\n\n/**\n * Pretty print a chunk of code.\n * @param {string} sourceCodeHtml The HTML to pretty print.\n * @param {string} opt_langExtension The language name to use.\n *     Typically, a filename extension like 'cpp' or 'java'.\n * @param {number|boolean} opt_numberLines True to number lines,\n *     or the 1-indexed number of the first line in sourceCodeHtml.\n * @return {string} code as html, but prettier\n */\nvar prettyPrintOne;\n/**\n * Find all the {@code <pre>} and {@code <code>} tags in the DOM with\n * {@code class=prettyprint} and prettify them.\n *\n * @param {Function} opt_whenDone called when prettifying is done.\n * @param {HTMLElement|HTMLDocument} opt_root an element or document\n *   containing all the elements to pretty print.\n *   Defaults to {@code document.body}.\n */\nvar prettyPrint;\n\n\n(function () {\n  var win = window;\n  // Keyword lists for various languages.\n  // We use things that coerce to strings to make them compact when minified\n  // and to defeat aggressive optimizers that fold large string constants.\n  var FLOW_CONTROL_KEYWORDS = [\"break,continue,do,else,for,if,return,while\"];\n  var C_KEYWORDS = [FLOW_CONTROL_KEYWORDS,\"auto,case,char,const,default,\" + \n      \"double,enum,extern,float,goto,inline,int,long,register,short,signed,\" +\n      \"sizeof,static,struct,switch,typedef,union,unsigned,void,volatile\"];\n  var COMMON_KEYWORDS = [C_KEYWORDS,\"catch,class,delete,false,import,\" +\n      \"new,operator,private,protected,public,this,throw,true,try,typeof\"];\n  var CPP_KEYWORDS = [COMMON_KEYWORDS,\"alignof,align_union,asm,axiom,bool,\" +\n      \"concept,concept_map,const_cast,constexpr,decltype,delegate,\" +\n      \"dynamic_cast,explicit,export,friend,generic,late_check,\" +\n      \"mutable,namespace,nullptr,property,reinterpret_cast,static_assert,\" +\n      \"static_cast,template,typeid,typename,using,virtual,where\"];\n  var JAVA_KEYWORDS = [COMMON_KEYWORDS,\n      \"abstract,assert,boolean,byte,extends,final,finally,implements,import,\" +\n      \"instanceof,interface,null,native,package,strictfp,super,synchronized,\" +\n      \"throws,transient\"];\n  var CSHARP_KEYWORDS = [JAVA_KEYWORDS,\n      \"as,base,by,checked,decimal,delegate,descending,dynamic,event,\" +\n      \"fixed,foreach,from,group,implicit,in,internal,into,is,let,\" +\n      \"lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,\" +\n      \"sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,\" +\n      \"var,virtual,where\"];\n  var COFFEE_KEYWORDS = \"all,and,by,catch,class,else,extends,false,finally,\" +\n      \"for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,\" +\n      \"throw,true,try,unless,until,when,while,yes\";\n  var JSCRIPT_KEYWORDS = [COMMON_KEYWORDS,\n      \"debugger,eval,export,function,get,null,set,undefined,var,with,\" +\n      \"Infinity,NaN\"];\n  var PERL_KEYWORDS = \"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,\" +\n      \"goto,if,import,last,local,my,next,no,our,print,package,redo,require,\" +\n      \"sub,undef,unless,until,use,wantarray,while,BEGIN,END\";\n  var PYTHON_KEYWORDS = [FLOW_CONTROL_KEYWORDS, \"and,as,assert,class,def,del,\" +\n      \"elif,except,exec,finally,from,global,import,in,is,lambda,\" +\n      \"nonlocal,not,or,pass,print,raise,try,with,yield,\" +\n      \"False,True,None\"];\n  var RUBY_KEYWORDS = [FLOW_CONTROL_KEYWORDS, \"alias,and,begin,case,class,\" +\n      \"def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,\" +\n      \"rescue,retry,self,super,then,true,undef,unless,until,when,yield,\" +\n      \"BEGIN,END\"];\n   var RUST_KEYWORDS = [FLOW_CONTROL_KEYWORDS, \"as,assert,const,copy,drop,\" +\n      \"enum,extern,fail,false,fn,impl,let,log,loop,match,mod,move,mut,priv,\" +\n      \"pub,pure,ref,self,static,struct,true,trait,type,unsafe,use\"];\n  var SH_KEYWORDS = [FLOW_CONTROL_KEYWORDS, \"case,done,elif,esac,eval,fi,\" +\n      \"function,in,local,set,then,until\"];\n  var ALL_KEYWORDS = [\n      CPP_KEYWORDS, CSHARP_KEYWORDS, JSCRIPT_KEYWORDS, PERL_KEYWORDS,\n      PYTHON_KEYWORDS, RUBY_KEYWORDS, SH_KEYWORDS];\n  var C_TYPES = /^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\\d*)\\b/;\n\n  // token style names.  correspond to css classes\n  /**\n   * token style for a string literal\n   * @const\n   */\n  var PR_STRING = 'str';\n  /**\n   * token style for a keyword\n   * @const\n   */\n  var PR_KEYWORD = 'kwd';\n  /**\n   * token style for a comment\n   * @const\n   */\n  var PR_COMMENT = 'com';\n  /**\n   * token style for a type\n   * @const\n   */\n  var PR_TYPE = 'typ';\n  /**\n   * token style for a literal value.  e.g. 1, null, true.\n   * @const\n   */\n  var PR_LITERAL = 'lit';\n  /**\n   * token style for a punctuation string.\n   * @const\n   */\n  var PR_PUNCTUATION = 'pun';\n  /**\n   * token style for plain text.\n   * @const\n   */\n  var PR_PLAIN = 'pln';\n\n  /**\n   * token style for an sgml tag.\n   * @const\n   */\n  var PR_TAG = 'tag';\n  /**\n   * token style for a markup declaration such as a DOCTYPE.\n   * @const\n   */\n  var PR_DECLARATION = 'dec';\n  /**\n   * token style for embedded source.\n   * @const\n   */\n  var PR_SOURCE = 'src';\n  /**\n   * token style for an sgml attribute name.\n   * @const\n   */\n  var PR_ATTRIB_NAME = 'atn';\n  /**\n   * token style for an sgml attribute value.\n   * @const\n   */\n  var PR_ATTRIB_VALUE = 'atv';\n\n  /**\n   * A class that indicates a section of markup that is not code, e.g. to allow\n   * embedding of line numbers within code listings.\n   * @const\n   */\n  var PR_NOCODE = 'nocode';\n\n  \n  \n  /**\n   * A set of tokens that can precede a regular expression literal in\n   * javascript\n   * http://web.archive.org/web/20070717142515/http://www.mozilla.org/js/language/js20/rationale/syntax.html\n   * has the full list, but I've removed ones that might be problematic when\n   * seen in languages that don't support regular expression literals.\n   *\n   * <p>Specifically, I've removed any keywords that can't precede a regexp\n   * literal in a syntactically legal javascript program, and I've removed the\n   * \"in\" keyword since it's not a keyword in many languages, and might be used\n   * as a count of inches.\n   *\n   * <p>The link above does not accurately describe EcmaScript rules since\n   * it fails to distinguish between (a=++/b/i) and (a++/b/i) but it works\n   * very well in practice.\n   *\n   * @private\n   * @const\n   */\n  var REGEXP_PRECEDER_PATTERN = '(?:^^\\\\.?|[+-]|[!=]=?=?|\\\\#|%=?|&&?=?|\\\\(|\\\\*=?|[+\\\\-]=|->|\\\\/=?|::?|<<?=?|>>?>?=?|,|;|\\\\?|@|\\\\[|~|{|\\\\^\\\\^?=?|\\\\|\\\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\\\s*';\n  \n  // CAVEAT: this does not properly handle the case where a regular\n  // expression immediately follows another since a regular expression may\n  // have flags for case-sensitivity and the like.  Having regexp tokens\n  // adjacent is not valid in any language I'm aware of, so I'm punting.\n  // TODO: maybe style special characters inside a regexp as punctuation.\n\n  /**\n   * Given a group of {@link RegExp}s, returns a {@code RegExp} that globally\n   * matches the union of the sets of strings matched by the input RegExp.\n   * Since it matches globally, if the input strings have a start-of-input\n   * anchor (/^.../), it is ignored for the purposes of unioning.\n   * @param {Array.<RegExp>} regexs non multiline, non-global regexs.\n   * @return {RegExp} a global regex.\n   */\n  function combinePrefixPatterns(regexs) {\n    var capturedGroupIndex = 0;\n  \n    var needToFoldCase = false;\n    var ignoreCase = false;\n    for (var i = 0, n = regexs.length; i < n; ++i) {\n      var regex = regexs[i];\n      if (regex.ignoreCase) {\n        ignoreCase = true;\n      } else if (/[a-z]/i.test(regex.source.replace(\n                     /\\\\u[0-9a-f]{4}|\\\\x[0-9a-f]{2}|\\\\[^ux]/gi, ''))) {\n        needToFoldCase = true;\n        ignoreCase = false;\n        break;\n      }\n    }\n  \n    var escapeCharToCodeUnit = {\n      'b': 8,\n      't': 9,\n      'n': 0xa,\n      'v': 0xb,\n      'f': 0xc,\n      'r': 0xd\n    };\n  \n    function decodeEscape(charsetPart) {\n      var cc0 = charsetPart.charCodeAt(0);\n      if (cc0 !== 92 /* \\\\ */) {\n        return cc0;\n      }\n      var c1 = charsetPart.charAt(1);\n      cc0 = escapeCharToCodeUnit[c1];\n      if (cc0) {\n        return cc0;\n      } else if ('0' <= c1 && c1 <= '7') {\n        return parseInt(charsetPart.substring(1), 8);\n      } else if (c1 === 'u' || c1 === 'x') {\n        return parseInt(charsetPart.substring(2), 16);\n      } else {\n        return charsetPart.charCodeAt(1);\n      }\n    }\n  \n    function encodeEscape(charCode) {\n      if (charCode < 0x20) {\n        return (charCode < 0x10 ? '\\\\x0' : '\\\\x') + charCode.toString(16);\n      }\n      var ch = String.fromCharCode(charCode);\n      return (ch === '\\\\' || ch === '-' || ch === ']' || ch === '^')\n          ? \"\\\\\" + ch : ch;\n    }\n  \n    function caseFoldCharset(charSet) {\n      var charsetParts = charSet.substring(1, charSet.length - 1).match(\n          new RegExp(\n              '\\\\\\\\u[0-9A-Fa-f]{4}'\n              + '|\\\\\\\\x[0-9A-Fa-f]{2}'\n              + '|\\\\\\\\[0-3][0-7]{0,2}'\n              + '|\\\\\\\\[0-7]{1,2}'\n              + '|\\\\\\\\[\\\\s\\\\S]'\n              + '|-'\n              + '|[^-\\\\\\\\]',\n              'g'));\n      var ranges = [];\n      var inverse = charsetParts[0] === '^';\n  \n      var out = ['['];\n      if (inverse) { out.push('^'); }\n  \n      for (var i = inverse ? 1 : 0, n = charsetParts.length; i < n; ++i) {\n        var p = charsetParts[i];\n        if (/\\\\[bdsw]/i.test(p)) {  // Don't muck with named groups.\n          out.push(p);\n        } else {\n          var start = decodeEscape(p);\n          var end;\n          if (i + 2 < n && '-' === charsetParts[i + 1]) {\n            end = decodeEscape(charsetParts[i + 2]);\n            i += 2;\n          } else {\n            end = start;\n          }\n          ranges.push([start, end]);\n          // If the range might intersect letters, then expand it.\n          // This case handling is too simplistic.\n          // It does not deal with non-latin case folding.\n          // It works for latin source code identifiers though.\n          if (!(end < 65 || start > 122)) {\n            if (!(end < 65 || start > 90)) {\n              ranges.push([Math.max(65, start) | 32, Math.min(end, 90) | 32]);\n            }\n            if (!(end < 97 || start > 122)) {\n              ranges.push([Math.max(97, start) & ~32, Math.min(end, 122) & ~32]);\n            }\n          }\n        }\n      }\n  \n      // [[1, 10], [3, 4], [8, 12], [14, 14], [16, 16], [17, 17]]\n      // -> [[1, 12], [14, 14], [16, 17]]\n      ranges.sort(function (a, b) { return (a[0] - b[0]) || (b[1]  - a[1]); });\n      var consolidatedRanges = [];\n      var lastRange = [];\n      for (var i = 0; i < ranges.length; ++i) {\n        var range = ranges[i];\n        if (range[0] <= lastRange[1] + 1) {\n          lastRange[1] = Math.max(lastRange[1], range[1]);\n        } else {\n          consolidatedRanges.push(lastRange = range);\n        }\n      }\n  \n      for (var i = 0; i < consolidatedRanges.length; ++i) {\n        var range = consolidatedRanges[i];\n        out.push(encodeEscape(range[0]));\n        if (range[1] > range[0]) {\n          if (range[1] + 1 > range[0]) { out.push('-'); }\n          out.push(encodeEscape(range[1]));\n        }\n      }\n      out.push(']');\n      return out.join('');\n    }\n  \n    function allowAnywhereFoldCaseAndRenumberGroups(regex) {\n      // Split into character sets, escape sequences, punctuation strings\n      // like ('(', '(?:', ')', '^'), and runs of characters that do not\n      // include any of the above.\n      var parts = regex.source.match(\n          new RegExp(\n              '(?:'\n              + '\\\\[(?:[^\\\\x5C\\\\x5D]|\\\\\\\\[\\\\s\\\\S])*\\\\]'  // a character set\n              + '|\\\\\\\\u[A-Fa-f0-9]{4}'  // a unicode escape\n              + '|\\\\\\\\x[A-Fa-f0-9]{2}'  // a hex escape\n              + '|\\\\\\\\[0-9]+'  // a back-reference or octal escape\n              + '|\\\\\\\\[^ux0-9]'  // other escape sequence\n              + '|\\\\(\\\\?[:!=]'  // start of a non-capturing group\n              + '|[\\\\(\\\\)\\\\^]'  // start/end of a group, or line start\n              + '|[^\\\\x5B\\\\x5C\\\\(\\\\)\\\\^]+'  // run of other characters\n              + ')',\n              'g'));\n      var n = parts.length;\n  \n      // Maps captured group numbers to the number they will occupy in\n      // the output or to -1 if that has not been determined, or to\n      // undefined if they need not be capturing in the output.\n      var capturedGroups = [];\n  \n      // Walk over and identify back references to build the capturedGroups\n      // mapping.\n      for (var i = 0, groupIndex = 0; i < n; ++i) {\n        var p = parts[i];\n        if (p === '(') {\n          // groups are 1-indexed, so max group index is count of '('\n          ++groupIndex;\n        } else if ('\\\\' === p.charAt(0)) {\n          var decimalValue = +p.substring(1);\n          if (decimalValue) {\n            if (decimalValue <= groupIndex) {\n              capturedGroups[decimalValue] = -1;\n            } else {\n              // Replace with an unambiguous escape sequence so that\n              // an octal escape sequence does not turn into a backreference\n              // to a capturing group from an earlier regex.\n              parts[i] = encodeEscape(decimalValue);\n            }\n          }\n        }\n      }\n  \n      // Renumber groups and reduce capturing groups to non-capturing groups\n      // where possible.\n      for (var i = 1; i < capturedGroups.length; ++i) {\n        if (-1 === capturedGroups[i]) {\n          capturedGroups[i] = ++capturedGroupIndex;\n        }\n      }\n      for (var i = 0, groupIndex = 0; i < n; ++i) {\n        var p = parts[i];\n        if (p === '(') {\n          ++groupIndex;\n          if (!capturedGroups[groupIndex]) {\n            parts[i] = '(?:';\n          }\n        } else if ('\\\\' === p.charAt(0)) {\n          var decimalValue = +p.substring(1);\n          if (decimalValue && decimalValue <= groupIndex) {\n            parts[i] = '\\\\' + capturedGroups[decimalValue];\n          }\n        }\n      }\n  \n      // Remove any prefix anchors so that the output will match anywhere.\n      // ^^ really does mean an anchored match though.\n      for (var i = 0; i < n; ++i) {\n        if ('^' === parts[i] && '^' !== parts[i + 1]) { parts[i] = ''; }\n      }\n  \n      // Expand letters to groups to handle mixing of case-sensitive and\n      // case-insensitive patterns if necessary.\n      if (regex.ignoreCase && needToFoldCase) {\n        for (var i = 0; i < n; ++i) {\n          var p = parts[i];\n          var ch0 = p.charAt(0);\n          if (p.length >= 2 && ch0 === '[') {\n            parts[i] = caseFoldCharset(p);\n          } else if (ch0 !== '\\\\') {\n            // TODO: handle letters in numeric escapes.\n            parts[i] = p.replace(\n                /[a-zA-Z]/g,\n                function (ch) {\n                  var cc = ch.charCodeAt(0);\n                  return '[' + String.fromCharCode(cc & ~32, cc | 32) + ']';\n                });\n          }\n        }\n      }\n  \n      return parts.join('');\n    }\n  \n    var rewritten = [];\n    for (var i = 0, n = regexs.length; i < n; ++i) {\n      var regex = regexs[i];\n      if (regex.global || regex.multiline) { throw new Error('' + regex); }\n      rewritten.push(\n          '(?:' + allowAnywhereFoldCaseAndRenumberGroups(regex) + ')');\n    }\n  \n    return new RegExp(rewritten.join('|'), ignoreCase ? 'gi' : 'g');\n  }\n\n  /**\n   * Split markup into a string of source code and an array mapping ranges in\n   * that string to the text nodes in which they appear.\n   *\n   * <p>\n   * The HTML DOM structure:</p>\n   * <pre>\n   * (Element   \"p\"\n   *   (Element \"b\"\n   *     (Text  \"print \"))       ; #1\n   *   (Text    \"'Hello '\")      ; #2\n   *   (Element \"br\")            ; #3\n   *   (Text    \"  + 'World';\")) ; #4\n   * </pre>\n   * <p>\n   * corresponds to the HTML\n   * {@code <p><b>print </b>'Hello '<br>  + 'World';</p>}.</p>\n   *\n   * <p>\n   * It will produce the output:</p>\n   * <pre>\n   * {\n   *   sourceCode: \"print 'Hello '\\n  + 'World';\",\n   *   //                     1          2\n   *   //           012345678901234 5678901234567\n   *   spans: [0, #1, 6, #2, 14, #3, 15, #4]\n   * }\n   * </pre>\n   * <p>\n   * where #1 is a reference to the {@code \"print \"} text node above, and so\n   * on for the other text nodes.\n   * </p>\n   *\n   * <p>\n   * The {@code} spans array is an array of pairs.  Even elements are the start\n   * indices of substrings, and odd elements are the text nodes (or BR elements)\n   * that contain the text for those substrings.\n   * Substrings continue until the next index or the end of the source.\n   * </p>\n   *\n   * @param {Node} node an HTML DOM subtree containing source-code.\n   * @param {boolean} isPreformatted true if white-space in text nodes should\n   *    be considered significant.\n   * @return {Object} source code and the text nodes in which they occur.\n   */\n  function extractSourceSpans(node, isPreformatted) {\n    var nocode = /(?:^|\\s)nocode(?:\\s|$)/;\n  \n    var chunks = [];\n    var length = 0;\n    var spans = [];\n    var k = 0;\n  \n    function walk(node) {\n      var type = node.nodeType;\n      if (type == 1) {  // Element\n        if (nocode.test(node.className)) { return; }\n        for (var child = node.firstChild; child; child = child.nextSibling) {\n          walk(child);\n        }\n        var nodeName = node.nodeName.toLowerCase();\n        if ('br' === nodeName || 'li' === nodeName) {\n          chunks[k] = '\\n';\n          spans[k << 1] = length++;\n          spans[(k++ << 1) | 1] = node;\n        }\n      } else if (type == 3 || type == 4) {  // Text\n        var text = node.nodeValue;\n        if (text.length) {\n          if (!isPreformatted) {\n            text = text.replace(/[ \\t\\r\\n]+/g, ' ');\n          } else {\n            text = text.replace(/\\r\\n?/g, '\\n');  // Normalize newlines.\n          }\n          // TODO: handle tabs here?\n          chunks[k] = text;\n          spans[k << 1] = length;\n          length += text.length;\n          spans[(k++ << 1) | 1] = node;\n        }\n      }\n    }\n  \n    walk(node);\n  \n    return {\n      sourceCode: chunks.join('').replace(/\\n$/, ''),\n      spans: spans\n    };\n  }\n\n  /**\n   * Apply the given language handler to sourceCode and add the resulting\n   * decorations to out.\n   * @param {number} basePos the index of sourceCode within the chunk of source\n   *    whose decorations are already present on out.\n   */\n  function appendDecorations(basePos, sourceCode, langHandler, out) {\n    if (!sourceCode) { return; }\n    var job = {\n      sourceCode: sourceCode,\n      basePos: basePos\n    };\n    langHandler(job);\n    out.push.apply(out, job.decorations);\n  }\n\n  var notWs = /\\S/;\n\n  /**\n   * Given an element, if it contains only one child element and any text nodes\n   * it contains contain only space characters, return the sole child element.\n   * Otherwise returns undefined.\n   * <p>\n   * This is meant to return the CODE element in {@code <pre><code ...>} when\n   * there is a single child element that contains all the non-space textual\n   * content, but not to return anything where there are multiple child elements\n   * as in {@code <pre><code>...</code><code>...</code></pre>} or when there\n   * is textual content.\n   */\n  function childContentWrapper(element) {\n    var wrapper = undefined;\n    for (var c = element.firstChild; c; c = c.nextSibling) {\n      var type = c.nodeType;\n      wrapper = (type === 1)  // Element Node\n          ? (wrapper ? element : c)\n          : (type === 3)  // Text Node\n          ? (notWs.test(c.nodeValue) ? element : wrapper)\n          : wrapper;\n    }\n    return wrapper === element ? undefined : wrapper;\n  }\n\n  /** Given triples of [style, pattern, context] returns a lexing function,\n    * The lexing function interprets the patterns to find token boundaries and\n    * returns a decoration list of the form\n    * [index_0, style_0, index_1, style_1, ..., index_n, style_n]\n    * where index_n is an index into the sourceCode, and style_n is a style\n    * constant like PR_PLAIN.  index_n-1 <= index_n, and style_n-1 applies to\n    * all characters in sourceCode[index_n-1:index_n].\n    *\n    * The stylePatterns is a list whose elements have the form\n    * [style : string, pattern : RegExp, DEPRECATED, shortcut : string].\n    *\n    * Style is a style constant like PR_PLAIN, or can be a string of the\n    * form 'lang-FOO', where FOO is a language extension describing the\n    * language of the portion of the token in $1 after pattern executes.\n    * E.g., if style is 'lang-lisp', and group 1 contains the text\n    * '(hello (world))', then that portion of the token will be passed to the\n    * registered lisp handler for formatting.\n    * The text before and after group 1 will be restyled using this decorator\n    * so decorators should take care that this doesn't result in infinite\n    * recursion.  For example, the HTML lexer rule for SCRIPT elements looks\n    * something like ['lang-js', /<[s]cript>(.+?)<\\/script>/].  This may match\n    * '<script>foo()<\\/script>', which would cause the current decorator to\n    * be called with '<script>' which would not match the same rule since\n    * group 1 must not be empty, so it would be instead styled as PR_TAG by\n    * the generic tag rule.  The handler registered for the 'js' extension would\n    * then be called with 'foo()', and finally, the current decorator would\n    * be called with '<\\/script>' which would not match the original rule and\n    * so the generic tag rule would identify it as a tag.\n    *\n    * Pattern must only match prefixes, and if it matches a prefix, then that\n    * match is considered a token with the same style.\n    *\n    * Context is applied to the last non-whitespace, non-comment token\n    * recognized.\n    *\n    * Shortcut is an optional string of characters, any of which, if the first\n    * character, guarantee that this pattern and only this pattern matches.\n    *\n    * @param {Array} shortcutStylePatterns patterns that always start with\n    *   a known character.  Must have a shortcut string.\n    * @param {Array} fallthroughStylePatterns patterns that will be tried in\n    *   order if the shortcut ones fail.  May have shortcuts.\n    *\n    * @return {function (Object)} a\n    *   function that takes source code and returns a list of decorations.\n    */\n  function createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns) {\n    var shortcuts = {};\n    var tokenizer;\n    (function () {\n      var allPatterns = shortcutStylePatterns.concat(fallthroughStylePatterns);\n      var allRegexs = [];\n      var regexKeys = {};\n      for (var i = 0, n = allPatterns.length; i < n; ++i) {\n        var patternParts = allPatterns[i];\n        var shortcutChars = patternParts[3];\n        if (shortcutChars) {\n          for (var c = shortcutChars.length; --c >= 0;) {\n            shortcuts[shortcutChars.charAt(c)] = patternParts;\n          }\n        }\n        var regex = patternParts[1];\n        var k = '' + regex;\n        if (!regexKeys.hasOwnProperty(k)) {\n          allRegexs.push(regex);\n          regexKeys[k] = null;\n        }\n      }\n      allRegexs.push(/[\\0-\\uffff]/);\n      tokenizer = combinePrefixPatterns(allRegexs);\n    })();\n\n    var nPatterns = fallthroughStylePatterns.length;\n\n    /**\n     * Lexes job.sourceCode and produces an output array job.decorations of\n     * style classes preceded by the position at which they start in\n     * job.sourceCode in order.\n     *\n     * @param {Object} job an object like <pre>{\n     *    sourceCode: {string} sourceText plain text,\n     *    basePos: {int} position of job.sourceCode in the larger chunk of\n     *        sourceCode.\n     * }</pre>\n     */\n    var decorate = function (job) {\n      var sourceCode = job.sourceCode, basePos = job.basePos;\n      /** Even entries are positions in source in ascending order.  Odd enties\n        * are style markers (e.g., PR_COMMENT) that run from that position until\n        * the end.\n        * @type {Array.<number|string>}\n        */\n      var decorations = [basePos, PR_PLAIN];\n      var pos = 0;  // index into sourceCode\n      var tokens = sourceCode.match(tokenizer) || [];\n      var styleCache = {};\n\n      for (var ti = 0, nTokens = tokens.length; ti < nTokens; ++ti) {\n        var token = tokens[ti];\n        var style = styleCache[token];\n        var match = void 0;\n\n        var isEmbedded;\n        if (typeof style === 'string') {\n          isEmbedded = false;\n        } else {\n          var patternParts = shortcuts[token.charAt(0)];\n          if (patternParts) {\n            match = token.match(patternParts[1]);\n            style = patternParts[0];\n          } else {\n            for (var i = 0; i < nPatterns; ++i) {\n              patternParts = fallthroughStylePatterns[i];\n              match = token.match(patternParts[1]);\n              if (match) {\n                style = patternParts[0];\n                break;\n              }\n            }\n\n            if (!match) {  // make sure that we make progress\n              style = PR_PLAIN;\n            }\n          }\n\n          isEmbedded = style.length >= 5 && 'lang-' === style.substring(0, 5);\n          if (isEmbedded && !(match && typeof match[1] === 'string')) {\n            isEmbedded = false;\n            style = PR_SOURCE;\n          }\n\n          if (!isEmbedded) { styleCache[token] = style; }\n        }\n\n        var tokenStart = pos;\n        pos += token.length;\n\n        if (!isEmbedded) {\n          decorations.push(basePos + tokenStart, style);\n        } else {  // Treat group 1 as an embedded block of source code.\n          var embeddedSource = match[1];\n          var embeddedSourceStart = token.indexOf(embeddedSource);\n          var embeddedSourceEnd = embeddedSourceStart + embeddedSource.length;\n          if (match[2]) {\n            // If embeddedSource can be blank, then it would match at the\n            // beginning which would cause us to infinitely recurse on the\n            // entire token, so we catch the right context in match[2].\n            embeddedSourceEnd = token.length - match[2].length;\n            embeddedSourceStart = embeddedSourceEnd - embeddedSource.length;\n          }\n          var lang = style.substring(5);\n          // Decorate the left of the embedded source\n          appendDecorations(\n              basePos + tokenStart,\n              token.substring(0, embeddedSourceStart),\n              decorate, decorations);\n          // Decorate the embedded source\n          appendDecorations(\n              basePos + tokenStart + embeddedSourceStart,\n              embeddedSource,\n              langHandlerForExtension(lang, embeddedSource),\n              decorations);\n          // Decorate the right of the embedded section\n          appendDecorations(\n              basePos + tokenStart + embeddedSourceEnd,\n              token.substring(embeddedSourceEnd),\n              decorate, decorations);\n        }\n      }\n      job.decorations = decorations;\n    };\n    return decorate;\n  }\n\n  /** returns a function that produces a list of decorations from source text.\n    *\n    * This code treats \", ', and ` as string delimiters, and \\ as a string\n    * escape.  It does not recognize perl's qq() style strings.\n    * It has no special handling for double delimiter escapes as in basic, or\n    * the tripled delimiters used in python, but should work on those regardless\n    * although in those cases a single string literal may be broken up into\n    * multiple adjacent string literals.\n    *\n    * It recognizes C, C++, and shell style comments.\n    *\n    * @param {Object} options a set of optional parameters.\n    * @return {function (Object)} a function that examines the source code\n    *     in the input job and builds the decoration list.\n    */\n  function sourceDecorator(options) {\n    var shortcutStylePatterns = [], fallthroughStylePatterns = [];\n    if (options['tripleQuotedStrings']) {\n      // '''multi-line-string''', 'single-line-string', and double-quoted\n      shortcutStylePatterns.push(\n          [PR_STRING,  /^(?:\\'\\'\\'(?:[^\\'\\\\]|\\\\[\\s\\S]|\\'{1,2}(?=[^\\']))*(?:\\'\\'\\'|$)|\\\"\\\"\\\"(?:[^\\\"\\\\]|\\\\[\\s\\S]|\\\"{1,2}(?=[^\\\"]))*(?:\\\"\\\"\\\"|$)|\\'(?:[^\\\\\\']|\\\\[\\s\\S])*(?:\\'|$)|\\\"(?:[^\\\\\\\"]|\\\\[\\s\\S])*(?:\\\"|$))/,\n           null, '\\'\"']);\n    } else if (options['multiLineStrings']) {\n      // 'multi-line-string', \"multi-line-string\"\n      shortcutStylePatterns.push(\n          [PR_STRING,  /^(?:\\'(?:[^\\\\\\']|\\\\[\\s\\S])*(?:\\'|$)|\\\"(?:[^\\\\\\\"]|\\\\[\\s\\S])*(?:\\\"|$)|\\`(?:[^\\\\\\`]|\\\\[\\s\\S])*(?:\\`|$))/,\n           null, '\\'\"`']);\n    } else {\n      // 'single-line-string', \"single-line-string\"\n      shortcutStylePatterns.push(\n          [PR_STRING,\n           /^(?:\\'(?:[^\\\\\\'\\r\\n]|\\\\.)*(?:\\'|$)|\\\"(?:[^\\\\\\\"\\r\\n]|\\\\.)*(?:\\\"|$))/,\n           null, '\"\\'']);\n    }\n    if (options['verbatimStrings']) {\n      // verbatim-string-literal production from the C# grammar.  See issue 93.\n      fallthroughStylePatterns.push(\n          [PR_STRING, /^@\\\"(?:[^\\\"]|\\\"\\\")*(?:\\\"|$)/, null]);\n    }\n    var hc = options['hashComments'];\n    if (hc) {\n      if (options['cStyleComments']) {\n        if (hc > 1) {  // multiline hash comments\n          shortcutStylePatterns.push(\n              [PR_COMMENT, /^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/, null, '#']);\n        } else {\n          // Stop C preprocessor declarations at an unclosed open comment\n          shortcutStylePatterns.push(\n              [PR_COMMENT, /^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\\b|[^\\r\\n]*)/,\n               null, '#']);\n        }\n        // #include <stdio.h>\n        fallthroughStylePatterns.push(\n            [PR_STRING,\n             /^<(?:(?:(?:\\.\\.\\/)*|\\/?)(?:[\\w-]+(?:\\/[\\w-]+)+)?[\\w-]+\\.h(?:h|pp|\\+\\+)?|[a-z]\\w*)>/,\n             null]);\n      } else {\n        shortcutStylePatterns.push([PR_COMMENT, /^#[^\\r\\n]*/, null, '#']);\n      }\n    }\n    if (options['cStyleComments']) {\n      fallthroughStylePatterns.push([PR_COMMENT, /^\\/\\/[^\\r\\n]*/, null]);\n      fallthroughStylePatterns.push(\n          [PR_COMMENT, /^\\/\\*[\\s\\S]*?(?:\\*\\/|$)/, null]);\n    }\n    var regexLiterals = options['regexLiterals'];\n    if (regexLiterals) {\n      /**\n       * @const\n       */\n      var regexExcls = regexLiterals > 1\n        ? ''  // Multiline regex literals\n        : '\\n\\r';\n      /**\n       * @const\n       */\n      var regexAny = regexExcls ? '.' : '[\\\\S\\\\s]';\n      /**\n       * @const\n       */\n      var REGEX_LITERAL = (\n          // A regular expression literal starts with a slash that is\n          // not followed by * or / so that it is not confused with\n          // comments.\n          '/(?=[^/*' + regexExcls + '])'\n          // and then contains any number of raw characters,\n          + '(?:[^/\\\\x5B\\\\x5C' + regexExcls + ']'\n          // escape sequences (\\x5C),\n          +    '|\\\\x5C' + regexAny\n          // or non-nesting character sets (\\x5B\\x5D);\n          +    '|\\\\x5B(?:[^\\\\x5C\\\\x5D' + regexExcls + ']'\n          +             '|\\\\x5C' + regexAny + ')*(?:\\\\x5D|$))+'\n          // finally closed by a /.\n          + '/');\n      fallthroughStylePatterns.push(\n          ['lang-regex',\n           RegExp('^' + REGEXP_PRECEDER_PATTERN + '(' + REGEX_LITERAL + ')')\n           ]);\n    }\n\n    var types = options['types'];\n    if (types) {\n      fallthroughStylePatterns.push([PR_TYPE, types]);\n    }\n\n    var keywords = (\"\" + options['keywords']).replace(/^ | $/g, '');\n    if (keywords.length) {\n      fallthroughStylePatterns.push(\n          [PR_KEYWORD,\n           new RegExp('^(?:' + keywords.replace(/[\\s,]+/g, '|') + ')\\\\b'),\n           null]);\n    }\n\n    shortcutStylePatterns.push([PR_PLAIN,       /^\\s+/, null, ' \\r\\n\\t\\xA0']);\n\n    var punctuation =\n      // The Bash man page says\n\n      // A word is a sequence of characters considered as a single\n      // unit by GRUB. Words are separated by metacharacters,\n      // which are the following plus space, tab, and newline: { }\n      // | & $ ; < >\n      // ...\n      \n      // A word beginning with # causes that word and all remaining\n      // characters on that line to be ignored.\n\n      // which means that only a '#' after /(?:^|[{}|&$;<>\\s])/ starts a\n      // comment but empirically\n      // $ echo {#}\n      // {#}\n      // $ echo \\$#\n      // $#\n      // $ echo }#\n      // }#\n\n      // so /(?:^|[|&;<>\\s])/ is more appropriate.\n\n      // http://gcc.gnu.org/onlinedocs/gcc-2.95.3/cpp_1.html#SEC3\n      // suggests that this definition is compatible with a\n      // default mode that tries to use a single token definition\n      // to recognize both bash/python style comments and C\n      // preprocessor directives.\n\n      // This definition of punctuation does not include # in the list of\n      // follow-on exclusions, so # will not be broken before if preceded\n      // by a punctuation character.  We could try to exclude # after\n      // [|&;<>] but that doesn't seem to cause many major problems.\n      // If that does turn out to be a problem, we should change the below\n      // when hc is truthy to include # in the run of punctuation characters\n      // only when not following [|&;<>].\n      '^.[^\\\\s\\\\w.$@\\'\"`/\\\\\\\\]*';\n    if (options['regexLiterals']) {\n      punctuation += '(?!\\s*\\/)';\n    }\n\n    fallthroughStylePatterns.push(\n        // TODO(mikesamuel): recognize non-latin letters and numerals in idents\n        [PR_LITERAL,     /^@[a-z_$][a-z_$@0-9]*/i, null],\n        [PR_TYPE,        /^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\\w+_t\\b)/, null],\n        [PR_PLAIN,       /^[a-z_$][a-z_$@0-9]*/i, null],\n        [PR_LITERAL,\n         new RegExp(\n             '^(?:'\n             // A hex number\n             + '0x[a-f0-9]+'\n             // or an octal or decimal number,\n             + '|(?:\\\\d(?:_\\\\d+)*\\\\d*(?:\\\\.\\\\d*)?|\\\\.\\\\d\\\\+)'\n             // possibly in scientific notation\n             + '(?:e[+\\\\-]?\\\\d+)?'\n             + ')'\n             // with an optional modifier like UL for unsigned long\n             + '[a-z]*', 'i'),\n         null, '0123456789'],\n        // Don't treat escaped quotes in bash as starting strings.\n        // See issue 144.\n        [PR_PLAIN,       /^\\\\[\\s\\S]?/, null],\n        [PR_PUNCTUATION, new RegExp(punctuation), null]);\n\n    return createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns);\n  }\n\n  var decorateSource = sourceDecorator({\n        'keywords': ALL_KEYWORDS,\n        'hashComments': true,\n        'cStyleComments': true,\n        'multiLineStrings': true,\n        'regexLiterals': true\n      });\n\n  /**\n   * Given a DOM subtree, wraps it in a list, and puts each line into its own\n   * list item.\n   *\n   * @param {Node} node modified in place.  Its content is pulled into an\n   *     HTMLOListElement, and each line is moved into a separate list item.\n   *     This requires cloning elements, so the input might not have unique\n   *     IDs after numbering.\n   * @param {boolean} isPreformatted true iff white-space in text nodes should\n   *     be treated as significant.\n   */\n  function numberLines(node, opt_startLineNum, isPreformatted) {\n    var nocode = /(?:^|\\s)nocode(?:\\s|$)/;\n    var lineBreak = /\\r\\n?|\\n/;\n  \n    var document = node.ownerDocument;\n  \n    var li = document.createElement('li');\n    while (node.firstChild) {\n      li.appendChild(node.firstChild);\n    }\n    // An array of lines.  We split below, so this is initialized to one\n    // un-split line.\n    var listItems = [li];\n  \n    function walk(node) {\n      var type = node.nodeType;\n      if (type == 1 && !nocode.test(node.className)) {  // Element\n        if ('br' === node.nodeName) {\n          breakAfter(node);\n          // Discard the <BR> since it is now flush against a </LI>.\n          if (node.parentNode) {\n            node.parentNode.removeChild(node);\n          }\n        } else {\n          for (var child = node.firstChild; child; child = child.nextSibling) {\n            walk(child);\n          }\n        }\n      } else if ((type == 3 || type == 4) && isPreformatted) {  // Text\n        var text = node.nodeValue;\n        var match = text.match(lineBreak);\n        if (match) {\n          var firstLine = text.substring(0, match.index);\n          node.nodeValue = firstLine;\n          var tail = text.substring(match.index + match[0].length);\n          if (tail) {\n            var parent = node.parentNode;\n            parent.insertBefore(\n              document.createTextNode(tail), node.nextSibling);\n          }\n          breakAfter(node);\n          if (!firstLine) {\n            // Don't leave blank text nodes in the DOM.\n            node.parentNode.removeChild(node);\n          }\n        }\n      }\n    }\n  \n    // Split a line after the given node.\n    function breakAfter(lineEndNode) {\n      // If there's nothing to the right, then we can skip ending the line\n      // here, and move root-wards since splitting just before an end-tag\n      // would require us to create a bunch of empty copies.\n      while (!lineEndNode.nextSibling) {\n        lineEndNode = lineEndNode.parentNode;\n        if (!lineEndNode) { return; }\n      }\n  \n      function breakLeftOf(limit, copy) {\n        // Clone shallowly if this node needs to be on both sides of the break.\n        var rightSide = copy ? limit.cloneNode(false) : limit;\n        var parent = limit.parentNode;\n        if (parent) {\n          // We clone the parent chain.\n          // This helps us resurrect important styling elements that cross lines.\n          // E.g. in <i>Foo<br>Bar</i>\n          // should be rewritten to <li><i>Foo</i></li><li><i>Bar</i></li>.\n          var parentClone = breakLeftOf(parent, 1);\n          // Move the clone and everything to the right of the original\n          // onto the cloned parent.\n          var next = limit.nextSibling;\n          parentClone.appendChild(rightSide);\n          for (var sibling = next; sibling; sibling = next) {\n            next = sibling.nextSibling;\n            parentClone.appendChild(sibling);\n          }\n        }\n        return rightSide;\n      }\n  \n      var copiedListItem = breakLeftOf(lineEndNode.nextSibling, 0);\n  \n      // Walk the parent chain until we reach an unattached LI.\n      for (var parent;\n           // Check nodeType since IE invents document fragments.\n           (parent = copiedListItem.parentNode) && parent.nodeType === 1;) {\n        copiedListItem = parent;\n      }\n      // Put it on the list of lines for later processing.\n      listItems.push(copiedListItem);\n    }\n  \n    // Split lines while there are lines left to split.\n    for (var i = 0;  // Number of lines that have been split so far.\n         i < listItems.length;  // length updated by breakAfter calls.\n         ++i) {\n      walk(listItems[i]);\n    }\n  \n    // Make sure numeric indices show correctly.\n    if (opt_startLineNum === (opt_startLineNum|0)) {\n      listItems[0].setAttribute('value', opt_startLineNum);\n    }\n  \n    var ol = document.createElement('ol');\n    ol.className = 'linenums';\n    var offset = Math.max(0, ((opt_startLineNum - 1 /* zero index */)) | 0) || 0;\n    for (var i = 0, n = listItems.length; i < n; ++i) {\n      li = listItems[i];\n      // Stick a class on the LIs so that stylesheets can\n      // color odd/even rows, or any other row pattern that\n      // is co-prime with 10.\n      li.className = 'L' + ((i + offset) % 10);\n      if (!li.firstChild) {\n        li.appendChild(document.createTextNode('\\xA0'));\n      }\n      ol.appendChild(li);\n    }\n  \n    node.appendChild(ol);\n  }\n  /**\n   * Breaks {@code job.sourceCode} around style boundaries in\n   * {@code job.decorations} and modifies {@code job.sourceNode} in place.\n   * @param {Object} job like <pre>{\n   *    sourceCode: {string} source as plain text,\n   *    sourceNode: {HTMLElement} the element containing the source,\n   *    spans: {Array.<number|Node>} alternating span start indices into source\n   *       and the text node or element (e.g. {@code <BR>}) corresponding to that\n   *       span.\n   *    decorations: {Array.<number|string} an array of style classes preceded\n   *       by the position at which they start in job.sourceCode in order\n   * }</pre>\n   * @private\n   */\n  function recombineTagsAndDecorations(job) {\n    var isIE8OrEarlier = /\\bMSIE\\s(\\d+)/.exec(navigator.userAgent);\n    isIE8OrEarlier = isIE8OrEarlier && +isIE8OrEarlier[1] <= 8;\n    var newlineRe = /\\n/g;\n  \n    var source = job.sourceCode;\n    var sourceLength = source.length;\n    // Index into source after the last code-unit recombined.\n    var sourceIndex = 0;\n  \n    var spans = job.spans;\n    var nSpans = spans.length;\n    // Index into spans after the last span which ends at or before sourceIndex.\n    var spanIndex = 0;\n  \n    var decorations = job.decorations;\n    var nDecorations = decorations.length;\n    // Index into decorations after the last decoration which ends at or before\n    // sourceIndex.\n    var decorationIndex = 0;\n  \n    // Remove all zero-length decorations.\n    decorations[nDecorations] = sourceLength;\n    var decPos, i;\n    for (i = decPos = 0; i < nDecorations;) {\n      if (decorations[i] !== decorations[i + 2]) {\n        decorations[decPos++] = decorations[i++];\n        decorations[decPos++] = decorations[i++];\n      } else {\n        i += 2;\n      }\n    }\n    nDecorations = decPos;\n  \n    // Simplify decorations.\n    for (i = decPos = 0; i < nDecorations;) {\n      var startPos = decorations[i];\n      // Conflate all adjacent decorations that use the same style.\n      var startDec = decorations[i + 1];\n      var end = i + 2;\n      while (end + 2 <= nDecorations && decorations[end + 1] === startDec) {\n        end += 2;\n      }\n      decorations[decPos++] = startPos;\n      decorations[decPos++] = startDec;\n      i = end;\n    }\n  \n    nDecorations = decorations.length = decPos;\n  \n    var sourceNode = job.sourceNode;\n    var oldDisplay;\n    if (sourceNode) {\n      oldDisplay = sourceNode.style.display;\n      sourceNode.style.display = 'none';\n    }\n    try {\n      var decoration = null;\n      while (spanIndex < nSpans) {\n        var spanStart = spans[spanIndex];\n        var spanEnd = spans[spanIndex + 2] || sourceLength;\n  \n        var decEnd = decorations[decorationIndex + 2] || sourceLength;\n  \n        var end = Math.min(spanEnd, decEnd);\n  \n        var textNode = spans[spanIndex + 1];\n        var styledText;\n        if (textNode.nodeType !== 1  // Don't muck with <BR>s or <LI>s\n            // Don't introduce spans around empty text nodes.\n            && (styledText = source.substring(sourceIndex, end))) {\n          // This may seem bizarre, and it is.  Emitting LF on IE causes the\n          // code to display with spaces instead of line breaks.\n          // Emitting Windows standard issue linebreaks (CRLF) causes a blank\n          // space to appear at the beginning of every line but the first.\n          // Emitting an old Mac OS 9 line separator makes everything spiffy.\n          if (isIE8OrEarlier) {\n            styledText = styledText.replace(newlineRe, '\\r');\n          }\n          textNode.nodeValue = styledText;\n          var document = textNode.ownerDocument;\n          var span = document.createElement('span');\n          span.className = decorations[decorationIndex + 1];\n          var parentNode = textNode.parentNode;\n          parentNode.replaceChild(span, textNode);\n          span.appendChild(textNode);\n          if (sourceIndex < spanEnd) {  // Split off a text node.\n            spans[spanIndex + 1] = textNode\n                // TODO: Possibly optimize by using '' if there's no flicker.\n                = document.createTextNode(source.substring(end, spanEnd));\n            parentNode.insertBefore(textNode, span.nextSibling);\n          }\n        }\n  \n        sourceIndex = end;\n  \n        if (sourceIndex >= spanEnd) {\n          spanIndex += 2;\n        }\n        if (sourceIndex >= decEnd) {\n          decorationIndex += 2;\n        }\n      }\n    } finally {\n      if (sourceNode) {\n        sourceNode.style.display = oldDisplay;\n      }\n    }\n  }\n\n  /** Maps language-specific file extensions to handlers. */\n  var langHandlerRegistry = {};\n  /** Register a language handler for the given file extensions.\n    * @param {function (Object)} handler a function from source code to a list\n    *      of decorations.  Takes a single argument job which describes the\n    *      state of the computation.   The single parameter has the form\n    *      {@code {\n    *        sourceCode: {string} as plain text.\n    *        decorations: {Array.<number|string>} an array of style classes\n    *                     preceded by the position at which they start in\n    *                     job.sourceCode in order.\n    *                     The language handler should assigned this field.\n    *        basePos: {int} the position of source in the larger source chunk.\n    *                 All positions in the output decorations array are relative\n    *                 to the larger source chunk.\n    *      } }\n    * @param {Array.<string>} fileExtensions\n    */\n  function registerLangHandler(handler, fileExtensions) {\n    for (var i = fileExtensions.length; --i >= 0;) {\n      var ext = fileExtensions[i];\n      if (!langHandlerRegistry.hasOwnProperty(ext)) {\n        langHandlerRegistry[ext] = handler;\n      } else if (win['console']) {\n        console['warn']('cannot override language handler %s', ext);\n      }\n    }\n  }\n  function langHandlerForExtension(extension, source) {\n    if (!(extension && langHandlerRegistry.hasOwnProperty(extension))) {\n      // Treat it as markup if the first non whitespace character is a < and\n      // the last non-whitespace character is a >.\n      extension = /^\\s*</.test(source)\n          ? 'default-markup'\n          : 'default-code';\n    }\n    return langHandlerRegistry[extension];\n  }\n  registerLangHandler(decorateSource, ['default-code']);\n  registerLangHandler(\n      createSimpleLexer(\n          [],\n          [\n           [PR_PLAIN,       /^[^<?]+/],\n           [PR_DECLARATION, /^<!\\w[^>]*(?:>|$)/],\n           [PR_COMMENT,     /^<\\!--[\\s\\S]*?(?:-\\->|$)/],\n           // Unescaped content in an unknown language\n           ['lang-',        /^<\\?([\\s\\S]+?)(?:\\?>|$)/],\n           ['lang-',        /^<%([\\s\\S]+?)(?:%>|$)/],\n           [PR_PUNCTUATION, /^(?:<[%?]|[%?]>)/],\n           ['lang-',        /^<xmp\\b[^>]*>([\\s\\S]+?)<\\/xmp\\b[^>]*>/i],\n           // Unescaped content in javascript.  (Or possibly vbscript).\n           ['lang-js',      /^<script\\b[^>]*>([\\s\\S]*?)(<\\/script\\b[^>]*>)/i],\n           // Contains unescaped stylesheet content\n           ['lang-css',     /^<style\\b[^>]*>([\\s\\S]*?)(<\\/style\\b[^>]*>)/i],\n           ['lang-in.tag',  /^(<\\/?[a-z][^<>]*>)/i]\n          ]),\n      ['default-markup', 'htm', 'html', 'mxml', 'xhtml', 'xml', 'xsl']);\n  registerLangHandler(\n      createSimpleLexer(\n          [\n           [PR_PLAIN,        /^[\\s]+/, null, ' \\t\\r\\n'],\n           [PR_ATTRIB_VALUE, /^(?:\\\"[^\\\"]*\\\"?|\\'[^\\']*\\'?)/, null, '\\\"\\'']\n           ],\n          [\n           [PR_TAG,          /^^<\\/?[a-z](?:[\\w.:-]*\\w)?|\\/?>$/i],\n           [PR_ATTRIB_NAME,  /^(?!style[\\s=]|on)[a-z](?:[\\w:-]*\\w)?/i],\n           ['lang-uq.val',   /^=\\s*([^>\\'\\\"\\s]*(?:[^>\\'\\\"\\s\\/]|\\/(?=\\s)))/],\n           [PR_PUNCTUATION,  /^[=<>\\/]+/],\n           ['lang-js',       /^on\\w+\\s*=\\s*\\\"([^\\\"]+)\\\"/i],\n           ['lang-js',       /^on\\w+\\s*=\\s*\\'([^\\']+)\\'/i],\n           ['lang-js',       /^on\\w+\\s*=\\s*([^\\\"\\'>\\s]+)/i],\n           ['lang-css',      /^style\\s*=\\s*\\\"([^\\\"]+)\\\"/i],\n           ['lang-css',      /^style\\s*=\\s*\\'([^\\']+)\\'/i],\n           ['lang-css',      /^style\\s*=\\s*([^\\\"\\'>\\s]+)/i]\n           ]),\n      ['in.tag']);\n  registerLangHandler(\n      createSimpleLexer([], [[PR_ATTRIB_VALUE, /^[\\s\\S]+/]]), ['uq.val']);\n  registerLangHandler(sourceDecorator({\n          'keywords': CPP_KEYWORDS,\n          'hashComments': true,\n          'cStyleComments': true,\n          'types': C_TYPES\n        }), ['c', 'cc', 'cpp', 'cxx', 'cyc', 'm']);\n  registerLangHandler(sourceDecorator({\n          'keywords': 'null,true,false'\n        }), ['json']);\n  registerLangHandler(sourceDecorator({\n          'keywords': CSHARP_KEYWORDS,\n          'hashComments': true,\n          'cStyleComments': true,\n          'verbatimStrings': true,\n          'types': C_TYPES\n        }), ['cs']);\n  registerLangHandler(sourceDecorator({\n          'keywords': JAVA_KEYWORDS,\n          'cStyleComments': true\n        }), ['java']);\n  registerLangHandler(sourceDecorator({\n          'keywords': SH_KEYWORDS,\n          'hashComments': true,\n          'multiLineStrings': true\n        }), ['bash', 'bsh', 'csh', 'sh']);\n  registerLangHandler(sourceDecorator({\n          'keywords': PYTHON_KEYWORDS,\n          'hashComments': true,\n          'multiLineStrings': true,\n          'tripleQuotedStrings': true\n        }), ['cv', 'py', 'python']);\n  registerLangHandler(sourceDecorator({\n          'keywords': PERL_KEYWORDS,\n          'hashComments': true,\n          'multiLineStrings': true,\n          'regexLiterals': 2  // multiline regex literals\n        }), ['perl', 'pl', 'pm']);\n  registerLangHandler(sourceDecorator({\n          'keywords': RUBY_KEYWORDS,\n          'hashComments': true,\n          'multiLineStrings': true,\n          'regexLiterals': true\n        }), ['rb', 'ruby']);\n  registerLangHandler(sourceDecorator({\n          'keywords': JSCRIPT_KEYWORDS,\n          'cStyleComments': true,\n          'regexLiterals': true\n        }), ['javascript', 'js']);\n  registerLangHandler(sourceDecorator({\n          'keywords': COFFEE_KEYWORDS,\n          'hashComments': 3,  // ### style block comments\n          'cStyleComments': true,\n          'multilineStrings': true,\n          'tripleQuotedStrings': true,\n          'regexLiterals': true\n        }), ['coffee']);\n  registerLangHandler(sourceDecorator({\n          'keywords': RUST_KEYWORDS,\n          'cStyleComments': true,\n          'multilineStrings': true\n        }), ['rc', 'rs', 'rust']);\n  registerLangHandler(\n      createSimpleLexer([], [[PR_STRING, /^[\\s\\S]+/]]), ['regex']);\n\n  function applyDecorator(job) {\n    var opt_langExtension = job.langExtension;\n\n    try {\n      // Extract tags, and convert the source code to plain text.\n      var sourceAndSpans = extractSourceSpans(job.sourceNode, job.pre);\n      /** Plain text. @type {string} */\n      var source = sourceAndSpans.sourceCode;\n      job.sourceCode = source;\n      job.spans = sourceAndSpans.spans;\n      job.basePos = 0;\n\n      // Apply the appropriate language handler\n      langHandlerForExtension(opt_langExtension, source)(job);\n\n      // Integrate the decorations and tags back into the source code,\n      // modifying the sourceNode in place.\n      recombineTagsAndDecorations(job);\n    } catch (e) {\n      if (win['console']) {\n        console['log'](e && e['stack'] || e);\n      }\n    }\n  }\n\n  /**\n   * Pretty print a chunk of code.\n   * @param sourceCodeHtml {string} The HTML to pretty print.\n   * @param opt_langExtension {string} The language name to use.\n   *     Typically, a filename extension like 'cpp' or 'java'.\n   * @param opt_numberLines {number|boolean} True to number lines,\n   *     or the 1-indexed number of the first line in sourceCodeHtml.\n   */\n  function $prettyPrintOne(sourceCodeHtml, opt_langExtension, opt_numberLines) {\n    var container = document.createElement('div');\n    // This could cause images to load and onload listeners to fire.\n    // E.g. <img onerror=\"alert(1337)\" src=\"nosuchimage.png\">.\n    // We assume that the inner HTML is from a trusted source.\n    // The pre-tag is required for IE8 which strips newlines from innerHTML\n    // when it is injected into a <pre> tag.\n    // http://stackoverflow.com/questions/451486/pre-tag-loses-line-breaks-when-setting-innerhtml-in-ie\n    // http://stackoverflow.com/questions/195363/inserting-a-newline-into-a-pre-tag-ie-javascript\n    container.innerHTML = '<pre>' + sourceCodeHtml + '</pre>';\n    container = container.firstChild;\n    if (opt_numberLines) {\n      numberLines(container, opt_numberLines, true);\n    }\n\n    var job = {\n      langExtension: opt_langExtension,\n      numberLines: opt_numberLines,\n      sourceNode: container,\n      pre: 1\n    };\n    applyDecorator(job);\n    return container.innerHTML;\n  }\n\n   /**\n    * Find all the {@code <pre>} and {@code <code>} tags in the DOM with\n    * {@code class=prettyprint} and prettify them.\n    *\n    * @param {Function} opt_whenDone called when prettifying is done.\n    * @param {HTMLElement|HTMLDocument} opt_root an element or document\n    *   containing all the elements to pretty print.\n    *   Defaults to {@code document.body}.\n    */\n  function $prettyPrint(opt_whenDone, opt_root) {\n    var root = opt_root || document.body;\n    var doc = root.ownerDocument || document;\n    function byTagName(tn) { return root.getElementsByTagName(tn); }\n    // fetch a list of nodes to rewrite\n    var codeSegments = [byTagName('pre'), byTagName('code'), byTagName('xmp')];\n    var elements = [];\n    for (var i = 0; i < codeSegments.length; ++i) {\n      for (var j = 0, n = codeSegments[i].length; j < n; ++j) {\n        elements.push(codeSegments[i][j]);\n      }\n    }\n    codeSegments = null;\n\n    var clock = Date;\n    if (!clock['now']) {\n      clock = { 'now': function () { return +(new Date); } };\n    }\n\n    // The loop is broken into a series of continuations to make sure that we\n    // don't make the browser unresponsive when rewriting a large page.\n    var k = 0;\n    var prettyPrintingJob;\n\n    var langExtensionRe = /\\blang(?:uage)?-([\\w.]+)(?!\\S)/;\n    var prettyPrintRe = /\\bprettyprint\\b/;\n    var prettyPrintedRe = /\\bprettyprinted\\b/;\n    var preformattedTagNameRe = /pre|xmp/i;\n    var codeRe = /^code$/i;\n    var preCodeXmpRe = /^(?:pre|code|xmp)$/i;\n    var EMPTY = {};\n\n    function doWork() {\n      var endTime = (win['PR_SHOULD_USE_CONTINUATION'] ?\n                     clock['now']() + 250 /* ms */ :\n                     Infinity);\n      for (; k < elements.length && clock['now']() < endTime; k++) {\n        var cs = elements[k];\n\n        // Look for a preceding comment like\n        // <?prettify lang=\"...\" linenums=\"...\"?>\n        var attrs = EMPTY;\n        {\n          for (var preceder = cs; (preceder = preceder.previousSibling);) {\n            var nt = preceder.nodeType;\n            // <?foo?> is parsed by HTML 5 to a comment node (8)\n            // like <!--?foo?-->, but in XML is a processing instruction\n            var value = (nt === 7 || nt === 8) && preceder.nodeValue;\n            if (value\n                ? !/^\\??prettify\\b/.test(value)\n                : (nt !== 3 || /\\S/.test(preceder.nodeValue))) {\n              // Skip over white-space text nodes but not others.\n              break;\n            }\n            if (value) {\n              attrs = {};\n              value.replace(\n                  /\\b(\\w+)=([\\w:.%+-]+)/g,\n                function (_, name, value) { attrs[name] = value; });\n              break;\n            }\n          }\n        }\n\n        var className = cs.className;\n        if ((attrs !== EMPTY || prettyPrintRe.test(className))\n            // Don't redo this if we've already done it.\n            // This allows recalling pretty print to just prettyprint elements\n            // that have been added to the page since last call.\n            && !prettyPrintedRe.test(className)) {\n\n          // make sure this is not nested in an already prettified element\n          var nested = false;\n          for (var p = cs.parentNode; p; p = p.parentNode) {\n            var tn = p.tagName;\n            if (preCodeXmpRe.test(tn)\n                && p.className && prettyPrintRe.test(p.className)) {\n              nested = true;\n              break;\n            }\n          }\n          if (!nested) {\n            // Mark done.  If we fail to prettyprint for whatever reason,\n            // we shouldn't try again.\n            cs.className += ' prettyprinted';\n\n            // If the classes includes a language extensions, use it.\n            // Language extensions can be specified like\n            //     <pre class=\"prettyprint lang-cpp\">\n            // the language extension \"cpp\" is used to find a language handler\n            // as passed to PR.registerLangHandler.\n            // HTML5 recommends that a language be specified using \"language-\"\n            // as the prefix instead.  Google Code Prettify supports both.\n            // http://dev.w3.org/html5/spec-author-view/the-code-element.html\n            var langExtension = attrs['lang'];\n            if (!langExtension) {\n              langExtension = className.match(langExtensionRe);\n              // Support <pre class=\"prettyprint\"><code class=\"language-c\">\n              var wrapper;\n              if (!langExtension && (wrapper = childContentWrapper(cs))\n                  && codeRe.test(wrapper.tagName)) {\n                langExtension = wrapper.className.match(langExtensionRe);\n              }\n\n              if (langExtension) { langExtension = langExtension[1]; }\n            }\n\n            var preformatted;\n            if (preformattedTagNameRe.test(cs.tagName)) {\n              preformatted = 1;\n            } else {\n              var currentStyle = cs['currentStyle'];\n              var defaultView = doc.defaultView;\n              var whitespace = (\n                  currentStyle\n                  ? currentStyle['whiteSpace']\n                  : (defaultView\n                     && defaultView.getComputedStyle)\n                  ? defaultView.getComputedStyle(cs, null)\n                  .getPropertyValue('white-space')\n                  : 0);\n              preformatted = whitespace\n                  && 'pre' === whitespace.substring(0, 3);\n            }\n\n            // Look for a class like linenums or linenums:<n> where <n> is the\n            // 1-indexed number of the first line.\n            var lineNums = attrs['linenums'];\n            if (!(lineNums = lineNums === 'true' || +lineNums)) {\n              lineNums = className.match(/\\blinenums\\b(?::(\\d+))?/);\n              lineNums =\n                lineNums\n                ? lineNums[1] && lineNums[1].length\n                  ? +lineNums[1] : true\n                : false;\n            }\n            if (lineNums) { numberLines(cs, lineNums, preformatted); }\n\n            // do the pretty printing\n            prettyPrintingJob = {\n              langExtension: langExtension,\n              sourceNode: cs,\n              numberLines: lineNums,\n              pre: preformatted\n            };\n            applyDecorator(prettyPrintingJob);\n          }\n        }\n      }\n      if (k < elements.length) {\n        // finish up in a continuation\n        setTimeout(doWork, 250);\n      } else if ('function' === typeof opt_whenDone) {\n        opt_whenDone();\n      }\n    }\n\n    doWork();\n  }\n\n  /**\n   * Contains functions for creating and registering new language handlers.\n   * @type {Object}\n   */\n  var PR = win['PR'] = {\n        'createSimpleLexer': createSimpleLexer,\n        'registerLangHandler': registerLangHandler,\n        'sourceDecorator': sourceDecorator,\n        'PR_ATTRIB_NAME': PR_ATTRIB_NAME,\n        'PR_ATTRIB_VALUE': PR_ATTRIB_VALUE,\n        'PR_COMMENT': PR_COMMENT,\n        'PR_DECLARATION': PR_DECLARATION,\n        'PR_KEYWORD': PR_KEYWORD,\n        'PR_LITERAL': PR_LITERAL,\n        'PR_NOCODE': PR_NOCODE,\n        'PR_PLAIN': PR_PLAIN,\n        'PR_PUNCTUATION': PR_PUNCTUATION,\n        'PR_SOURCE': PR_SOURCE,\n        'PR_STRING': PR_STRING,\n        'PR_TAG': PR_TAG,\n        'PR_TYPE': PR_TYPE,\n        'prettyPrintOne':\n           IN_GLOBAL_SCOPE\n             ? (win['prettyPrintOne'] = $prettyPrintOne)\n             : (prettyPrintOne = $prettyPrintOne),\n        'prettyPrint': prettyPrint =\n           IN_GLOBAL_SCOPE\n             ? (win['prettyPrint'] = $prettyPrint)\n             : (prettyPrint = $prettyPrint)\n      };\n\n  // Make PR available via the Asynchronous Module Definition (AMD) API.\n  // Per https://github.com/amdjs/amdjs-api/wiki/AMD:\n  // The Asynchronous Module Definition (AMD) API specifies a\n  // mechanism for defining modules such that the module and its\n  // dependencies can be asynchronously loaded.\n  // ...\n  // To allow a clear indicator that a global define function (as\n  // needed for script src browser loading) conforms to the AMD API,\n  // any global define function SHOULD have a property called \"amd\"\n  // whose value is an object. This helps avoid conflict with any\n  // other existing JavaScript code that could have defined a define()\n  // function that does not conform to the AMD API.\n  if (typeof define === \"function\" && define['amd']) {\n    define(\"google-code-prettify\", [], function () {\n      return PR; \n    });\n  }\n})();\n\ndefine(\"prettify\", function(){});\n\n",
        -    "define('itemView',[\n  'App',\n  // Templates\n  'text!tpl/item.html',\n  'text!tpl/class.html',\n  'text!tpl/itemEnd.html',\n  // Tools\n  'prettify'\n], function(App, itemTpl, classTpl, endTpl) {\n  'use strict';\n\n  var appVersion = App.project.version || 'master';\n\n  var itemView = Backbone.View.extend({\n    el: '#item',\n    init: function() {\n      this.$html = $('html');\n      this.$body = $('body');\n      this.$scrollBody = $('html, body'); // hack for Chrome/Firefox scroll\n\n      this.tpl = _.template(itemTpl);\n      this.classTpl = _.template(classTpl);\n      this.endTpl = _.template(endTpl);\n\n      return this;\n    },\n    getSyntax: function(isMethod, cleanItem) {\n      var isConstructor = cleanItem.is_constructor;\n      var syntax = '';\n      if (isConstructor) {\n        syntax += 'new ';\n      } else if (cleanItem.static && cleanItem.class) {\n        syntax += cleanItem.class + '.';\n      }\n      syntax += cleanItem.name;\n\n      if (isMethod || isConstructor) {\n        syntax += '(';\n        if (cleanItem.params) {\n          for (var i = 0; i < cleanItem.params.length; i++) {\n            var p = cleanItem.params[i];\n            if (p.optional) {\n              syntax += '[';\n            }\n            syntax += p.name;\n            if (p.optdefault) {\n              syntax += '=' + p.optdefault;\n            }\n            if (p.optional) {\n              syntax += ']';\n            }\n            if (i !== cleanItem.params.length - 1) {\n              syntax += ', ';\n            }\n          }\n        }\n        syntax += ')';\n      }\n\n      return syntax;\n    },\n    // Return a list of valid syntaxes across all overloaded versions of\n    // this item.\n    //\n    // For reference, we ultimately want to replicate something like this:\n    //\n    // https://processing.org/reference/color_.html\n    getSyntaxes: function(isMethod, cleanItem) {\n      var overloads = cleanItem.overloads || [cleanItem];\n      return overloads.map(this.getSyntax.bind(this, isMethod));\n    },\n    render: function(item) {\n      if (item) {\n        var itemHtml = '';\n        var cleanItem = this.clean(item);\n        var isClass = item.hasOwnProperty('itemtype') ? 0 : 1;\n        var collectionName = isClass\n            ? 'Constructor'\n            : this.capitalizeFirst(cleanItem.itemtype),\n          isConstructor = cleanItem.is_constructor;\n        cleanItem.isMethod = collectionName === 'Method';\n\n        var syntaxes = this.getSyntaxes(cleanItem.isMethod, cleanItem);\n\n        // Set the item header (title)\n\n        // Set item contents\n        if (isClass) {\n          var constructor = this.tpl({\n            item: cleanItem,\n            isClass: true,\n            isConstructor: isConstructor,\n            syntaxes: syntaxes\n          });\n          cleanItem.constructor = constructor;\n\n          var contents = _.find(App.classes, function(c) {\n            return c.name === cleanItem.name;\n          });\n          cleanItem.things = contents.items;\n\n          itemHtml = this.classTpl(cleanItem);\n        } else {\n          cleanItem.constRefs =\n            item.module === 'Constants' && App.data.consts[item.name];\n\n          itemHtml = this.tpl({\n            item: cleanItem,\n            isClass: false,\n            isConstructor: false,\n            syntaxes: syntaxes\n          });\n        }\n\n        itemHtml += this.endTpl({ item: cleanItem, appVersion: appVersion });\n\n        // Insert the view in the dom\n        this.$el.html(itemHtml);\n\n        renderCode(cleanItem.name);\n\n        // Set the document title based on the item name.\n        // If it is a method, add parentheses to the name\n        if (item.itemtype === 'method') {\n          App.pageView.appendToDocumentTitle(item.name + '()');\n        } else {\n          App.pageView.appendToDocumentTitle(item.name);\n        }\n\n        // Hook up alt-text for examples\n        setTimeout(function() {\n          var alts = $('.example-content')[0];\n          if (alts) {\n            alts = $(alts)\n              .data('alt')\n              .split('\\n');\n\n            var canvases = $('.cnv_div');\n            for (var j = 0; j < alts.length; j++) {\n              if (j < canvases.length) {\n                $(canvases[j]).append(\n                  '<span class=\"sr-only\">' + alts[j] + '</span>'\n                );\n              }\n            }\n          }\n        }, 1000);\n        Prism.highlightAll();\n      }\n\n      var renderEvent = new Event('reference-rendered');\n      window.dispatchEvent(renderEvent);\n\n      return this;\n    },\n    /**\n     * Clean item properties: url encode properties containing paths.\n     * @param {object} item The item object.\n     * @returns {object} Returns the same item object with urlencoded paths.\n     */\n    clean: function(item) {\n      var cleanItem = item;\n\n      if (cleanItem.hasOwnProperty('file')) {\n        cleanItem.urlencodedfile = encodeURIComponent(item.file);\n      }\n      return cleanItem;\n    },\n    /**\n     * Show a single item.\n     * @param {object} item Item object.\n     * @returns {object} This view.\n     */\n    show: function(item) {\n      if (item) {\n        this.render(item);\n      }\n\n      App.pageView.hideContentViews();\n\n      this.$el.show();\n\n      this.scrollTop();\n      $('#item').focus();\n      return this;\n    },\n    /**\n     * Show a message if no item is found.\n     * @returns {object} This view.\n     */\n    nothingFound: function() {\n      this.$el.html(\n        '<p><br><br>Ouch. I am unable to find any item that match the current query.</p>'\n      );\n      App.pageView.hideContentViews();\n      this.$el.show();\n\n      return this;\n    },\n    /**\n     * Scroll to the top of the window with an animation.\n     */\n    scrollTop: function() {\n      // Hack for Chrome/Firefox scroll animation\n      // Chrome scrolls 'body', Firefox scrolls 'html'\n      var scroll = this.$body.scrollTop() > 0 || this.$html.scrollTop() > 0;\n      if (scroll) {\n        this.$scrollBody.animate({ scrollTop: 0 }, 600);\n      }\n    },\n    /**\n     * Helper method to capitalize the first letter of a string\n     * @param {string} str\n     * @returns {string} Returns the string.\n     */\n    capitalizeFirst: function(str) {\n      return str.substr(0, 1).toUpperCase() + str.substr(1);\n    }\n  });\n\n  return itemView;\n});\n\n",
        -    "\ndefine('text!tpl/menu.html',[],function () { return '<div>\\n  <br>\\n  <span id=\"reference-description1\">Can\\'t find what you\\'re looking for? You may want to check out</span>\\n  <a href=\"#/libraries/p5.sound\">p5.sound</a>.<br><a href=\\'https://p5js.org/offline-reference/p5-reference.zip\\' target=_blank><span id=\"reference-description3\">You can also download an offline version of the reference.</span></a>\\n</div>\\n\\n<div id=\\'collection-list-categories\\'>\\n<h2 class=\"sr-only\" id=\"categories\">Categories</h2>\\n<% var i=0; %>\\n<% var max=Math.floor(groups.length/4); %>\\n<% var rem=groups.length%4; %>\\n\\n<% _.each(groups, function(group){ %>\\n  <% var m = rem > 0 ? 1 : 0 %>\\n  <% if (i === 0) { %>\\n    <ul aria-labelledby=\"categories\">\\n    <% } %>\\n    <li><a href=\"#group-<%=group%>\"><%=group%></a></li>\\n    <% if (i === (max+m-1)) { %>\\n    </ul>\\n  \\t<% rem-- %>\\n  \\t<% i=0 %>\\n  <% } else { %>\\n  \\t<% i++ %>\\n  <% } %>\\n<% }); %>\\n</div>\\n';});\n\n",
        -    "define('menuView',[\n  'App',\n  'text!tpl/menu.html'\n], function(App, menuTpl) {\n\n  var menuView = Backbone.View.extend({\n    el: '#collection-list-nav',\n    /**\n     * Init.\n     * @returns {object} This view.\n     */\n    init: function() {\n      this.menuTpl = _.template(menuTpl);\n      return this;\n    },\n    /**\n     * Render.\n     * @returns {object} This view.\n     */\n    render: function() {\n\n      var groups = [];\n      _.each(App.modules, function (item, i) {\n        if (!item.is_submodule) {\n          if (!item.file || item.file.indexOf('addons') === -1) { //addons don't get displayed on main page\n            groups.push(item.name);\n          }\n        }\n        //}\n      });\n\n      // Sort groups by name A-Z\n      groups.sort();\n\n      var menuHtml = this.menuTpl({\n        'groups': groups\n      });\n\n      // Render the view\n      this.$el.html(menuHtml);\n    },\n\n    hide: function() {\n      this.$el.hide();\n    },\n\n    show: function() {\n      this.$el.show();\n    },\n\n    /**\n     * Update the menu.\n     * @param {string} el The name of the current route.\n     */\n    update: function(menuItem) {\n      //console.log(menuItem);\n      // this.$menuItems.removeClass('active');\n      // this.$menuItems.find('a[href=#'+menuItem+']').parent().addClass('active');\n\n    }\n  });\n\n  return menuView;\n\n});\n\n",
        -    "\ndefine('text!tpl/library.html',[],function () { return '<h3><%= module.name %> library</h3>\\n\\n<p><%= module.description %></p>\\n\\n<div id=\"library-page\" class=\"reference-group clearfix\">  \\n\\n<% var t = 0; col = 0; %>\\n\\n<% _.each(groups, function(group){ %>\\n  <% if (t == 0) { %> \\n    <div class=\"column_<%=col%>\">\\n  <% } %>\\n  <% if (group.name !== module.name && group.name !== \\'p5\\') { %>\\n    <% if (group.hash) { %> <a href=\"<%=group.hash%>\" <% if (group.module !== module.name) { %>class=\"core\"<% } %>><% } %>  \\n    <h4 class=\"group-name <% if (t == 0) { %> first<%}%>\"><%=group.name%></h4>\\n    <% if (group.hash) { %> </a><br> <% } %>\\n  <% } %>\\n  <% _.each(group.items.filter(function(item) {return item.access !== \\'private\\'}), function(item) { %>\\n    <a href=\"<%=item.hash%>\" <% if (item.module !== module.name) { %>class=\"core\"<% } %>><%=item.name%><% if (item.itemtype === \\'method\\') { %>()<%}%></a><br>\\n    <% t++; %>\\n  <% }); %>\\n  <% if (t >= Math.floor(totalItems/4)) { col++; t = 0; %>\\n    </div>\\n  <% } %>\\n<% }); %>\\n</div>\\n';});\n\n",
        -    "define(\n  'libraryView',[\n    'App',\n    // Templates\n    'text!tpl/library.html'\n  ],\n  function(App, libraryTpl) {\n    var libraryView = Backbone.View.extend({\n      el: '#list',\n      events: {},\n      /**\n       * Init.\n       */\n      init: function() {\n        this.libraryTpl = _.template(libraryTpl);\n\n        return this;\n      },\n      /**\n       * Render the list.\n       */\n      render: function(m, listCollection) {\n        if (m && listCollection) {\n          var self = this;\n\n          // Render items and group them by module\n          // module === group\n          this.groups = {};\n          _.each(m.items, function(item, i) {\n            var module = item.module || '_';\n            var group;\n            // Override default group with a selected category\n            // TODO: Overwriting with the first category might not be the best choice\n            // We might also want to have links for categories\n            if (item.category && item.category[0]) {\n              group = item.category[0];\n              // Populate item.hash\n              App.router.getHash(item);\n\n              // Create a group list without link hash\n              if (!self.groups[group]) {\n                self.groups[group] = {\n                  name: group.replace('_', '&nbsp;'),\n                  module: module,\n                  hash: undefined,\n                  items: []\n                };\n              }\n            } else {\n              group = item.class || '_';\n              var hash = App.router.getHash(item);\n\n              var ind = hash.lastIndexOf('/');\n              hash = hash.substring(0, ind);\n\n              // Create a group list\n              if (!self.groups[group]) {\n                self.groups[group] = {\n                  name: group.replace('_', '&nbsp;'),\n                  module: module,\n                  hash: hash,\n                  items: []\n                };\n              }\n            }\n\n            self.groups[group].items.push(item);\n          });\n\n          // Sort groups by name A-Z\n          self.groups = _.sortBy(self.groups, this.sortByName);\n\n          // Put the <li> items html into the list <ul>\n          var libraryHtml = self.libraryTpl({\n            title: self.capitalizeFirst(listCollection),\n            module: m.module,\n            totalItems: m.items.length,\n            groups: self.groups\n          });\n\n          // Render the view\n          this.$el.html(libraryHtml);\n        }\n\n        return this;\n      },\n      /**\n       * Show a list of items.\n       * @param {array} items Array of item objects.\n       * @returns {object} This view.\n       */\n      show: function(listGroup) {\n        if (App[listGroup]) {\n          this.render(App[listGroup], listGroup);\n        }\n        App.pageView.hideContentViews();\n\n        this.$el.show();\n\n        return this;\n      },\n      /**\n       * Helper method to capitalize the first letter of a string\n       * @param {string} str\n       * @returns {string} Returns the string.\n       */\n      capitalizeFirst: function(str) {\n        return str.substr(0, 1).toUpperCase() + str.substr(1);\n      },\n      /**\n       * Sort function (for the Array.prototype.sort() native method): from A to Z.\n       * @param {string} a\n       * @param {string} b\n       * @returns {Array} Returns an array with elements sorted from A to Z.\n       */\n      sortAZ: function(a, b) {\n        return a.innerHTML.toLowerCase() > b.innerHTML.toLowerCase() ? 1 : -1;\n      },\n\n      sortByName: function(a, b) {\n        if (a.name === 'p5') return -1;\n        else return 0;\n      }\n    });\n\n    return libraryView;\n  }\n);\n\n",
        -    "define('pageView',[\n  'App',\n\n  // Views\n  'searchView',\n  'listView',\n  'itemView',\n  'menuView',\n  'libraryView'\n], function(App, searchView, listView, itemView, menuView, libraryView) {\n\n  // Store the original title parts so we can substitute different endings.\n  var _originalDocumentTitle = window.document.title;\n\n  var pageView = Backbone.View.extend({\n    el: 'body',\n    /**\n     * Init.\n     */\n    init: function() {\n      App.$container = $('#container');\n      App.contentViews = [];\n\n      return this;\n    },\n    /**\n     * Render.\n     */\n    render: function() {\n\n      // Menu view\n      if (!App.menuView) {\n        App.menuView = new menuView();\n        App.menuView.init().render();\n      }\n\n      // Item view\n      if (!App.itemView) {\n        App.itemView = new itemView();\n        App.itemView.init().render();\n        // Add the item view to the views array\n        App.contentViews.push(App.itemView);\n      }\n\n      // List view\n      if (!App.listView) {\n        App.listView = new listView();\n        App.listView.init().render();\n        // Add the list view to the views array\n        App.contentViews.push(App.listView);\n      }\n\n      // Library view\n      if (!App.libraryView) {\n        App.libraryView = new libraryView();\n        App.libraryView.init().render();\n        // Add the list view to the views array\n        App.contentViews.push(App.libraryView);\n      }\n\n      // Search\n      if (!App.searchView) {\n        App.searchView = new searchView();\n        App.searchView.init().render();\n      }\n      return this;\n    },\n    /**\n     * Hide item and list views.\n     * @returns {object} This view.\n     */\n    hideContentViews: function() {\n      _.each(App.contentViews, function(view, i) {\n        view.$el.hide();\n      });\n\n      return this;\n    },\n    /**\n     * Append the supplied name to the first part of original document title.\n     * If no name is supplied, the title will reset to the original one.\n     */\n    appendToDocumentTitle: function(name){\n      if(name){\n        let firstTitlePart = _originalDocumentTitle.split(\" | \")[0];\n        window.document.title = [firstTitlePart, name].join(\" | \");\n      } else {\n        window.document.title = _originalDocumentTitle;\n      }\n    }    \n  });\n\n  return pageView;\n\n});\n\n",
        -    "define('router',[\n  'App'\n], function(App) {\n\n  'use strict'; //\n\n  var Router = Backbone.Router.extend({\n\n    routes: {\n      '': 'list',\n      'p5': 'list',\n      'p5/': 'list',\n      'classes': 'list',\n      'search': 'search',\n      'libraries/:lib': 'library',\n      ':searchClass(/:searchItem)': 'get'\n    },\n    /**\n     * Whether the json API data was loaded.\n     */\n    _initialized: false,\n    /**\n     * Initialize the app: load json API data and create searchable arrays.\n     */\n    init: function(callback) {\n      var self = this;\n      require(['pageView'], function(pageView) {\n\n        // If already initialized, move away from here!\n        if (self._initialized) {\n          if (callback)\n            callback();\n          return;\n        }\n\n        // Update initialization state: must be done now to avoid recursive mess\n        self._initialized = true;\n\n        // Render views\n        if (!App.pageView) {\n          App.pageView = new pageView();\n          App.pageView.init().render();\n        }\n\n        // If a callback is set (a route has already been called), run it\n        // otherwise, show the default list\n        if (callback)\n          callback();\n        else\n          self.list();\n      });\n    },\n    /**\n     * Start route. Simply check if initialized.\n     */\n    start: function() {\n      this.init();\n    },\n    /**\n     * Show item details by searching a class or a class item (method, property or event).\n     * @param {string} searchClass The class name (mandatory).\n     * @param {string} searchItem The class item name: can be a method, property or event name.\n     */\n    get: function(searchClass, searchItem) {\n\n      // if looking for a library page, redirect\n      if (searchClass === 'p5.sound' && !searchItem) {\n        window.location.hash = '/libraries/'+searchClass;\n        return;\n      }\n\n      var self = this;\n      this.init(function() {\n        var item = self.getItem(searchClass, searchItem);\n\n        App.menuView.hide();\n\n        if (item) {\n          App.itemView.show(item);\n        } else {\n          //App.itemView.nothingFound();\n\n          self.list();\n        }\n\n        styleCodeLinks();\n      });\n    },\n    /**\n     * Returns one item object by searching a class or a class item (method, property or event).\n     * @param {string} searchClass The class name (mandatory).\n     * @param {string} searchItem The class item name: can be a method, property or event name.\n     * @returns {object} The item found or undefined if nothing was found.\n     */\n    getItem: function(searchClass, searchItem) {\n      var classes = App.classes,\n              items = App.allItems,\n              classesCount = classes.length,\n              itemsCount = items.length,\n              className = searchClass ? searchClass.toLowerCase() : undefined,\n              itemName = searchItem ? searchItem : undefined,\n              found;\n\n      // Only search for a class, if itemName is undefined\n      if (className && !itemName) {\n        for (var i = 0; i < classesCount; i++) {\n          if (classes[i].name.toLowerCase() === className) {\n            found = classes[i];\n            _.each(found.items, function(i, idx) {\n              i.hash = App.router.getHash(i);\n            });\n            break;\n          }\n        }\n        // Search for a class item\n      } else if (className && itemName) {\n        // Search case sensitively\n        for (var i = 0; i < itemsCount; i++) {\n          if (items[i].class.toLowerCase() === className &&\n            items[i].name === itemName) {\n            found = items[i];\n            break;\n          }\n        }\n\n        // If no match was found, fallback to search case insensitively\n        if(!found){\n          for (var i = 0; i < itemsCount; i++) {\n            if(items[i].class.toLowerCase() === className &&\n              items[i].name.toLowerCase() === itemName.toLowerCase()){\n              found = items[i];\n              break;\n            }\n          }\n        }\n      }\n\n      return found;\n    },\n    /**\n     * List items.\n     * @param {string} collection The name of the collection to list.\n     */\n    list: function(collection) {\n\n      collection = 'allItems';\n\n      // Make sure collection is valid\n      if (App.collections.indexOf(collection) < 0) {\n        return;\n      }\n\n      this.init(function() {\n        App.menuView.show(collection);\n        App.menuView.update(collection);\n        App.listView.show(collection);\n        styleCodeLinks();\n      });\n    },\n    /**\n     * Display information for a library.\n     * @param {string} collection The name of the collection to list.\n     */\n    library: function(collection) {\n      this.init(function() {\n        App.menuView.hide();\n        App.libraryView.show(collection.substring(3)); //remove p5.\n        styleCodeLinks();\n      });\n    },\n    /**\n     * Close all content views.\n     */\n    search: function() {\n      this.init(function() {\n        App.menuView.hide();\n        App.pageView.hideContentViews();\n      });\n    },\n\n    /**\n     * Create an hash/url for the item.\n     * @param {Object} item A class, method, property or event object.\n     * @returns {String} The hash string, including the '#'.\n     */\n     getHash: function(item) {\n\n       if (!item.hash) {\n\n         // FIX TO INVISIBLE OBJECTS: DH (see also listView.js)\n\n         if (item.class) {\n           var clsFunc = '#/' + item.class + '.' + item.name;\n           var idx = clsFunc.lastIndexOf('.');\n           item.hash = clsFunc.substring(0,idx) + '/' + clsFunc.substring(idx+1);\n         } else {\n          item.hash = '#/' + item.name;\n         }\n       }\n\n       return item.hash;\n    }\n  });\n\n  \n  function styleCodeLinks() {\n    var links = document.getElementsByTagName(\"a\");\n    for (var iLink = 0; iLink < links.length; iLink++) {\n      var link = links[iLink];\n      if (link.hash.startsWith('#/p5')) {\n        link.classList.add('code');\n      }\n    }\n  }\n\n\n  // Get the router\n  App.router = new Router();\n\n  // Start history\n  Backbone.history.start();\n\n  return App.router;\n\n});\n\n",
        -    "/**\n * Define global App.\n */\nvar App = window.App || {};\ndefine('App', [],function() {\n  return App;\n});\n\n/**\n * Load json API data and start the router.\n * @param {module} App\n * @param {module} router\n */\nrequire([\n  'App',\n  './documented-method'], function(App, DocumentedMethod) {\n\n  // Set collections\n  App.collections = ['allItems', 'classes', 'events', 'methods', 'properties', 'p5.sound'];\n\n  // Get json API data\n  $.getJSON('data.min.json', function(data) {\n    App.data = data;\n    App.classes = [];\n    App.methods = [];\n    App.properties = [];\n    App.events = [];\n    App.allItems = [];\n    App.sound = { items: [] };\n    App.dom = { items: [] };\n    App.modules = [];\n    App.project = data.project;\n\n\n    var modules = data.modules;\n\n    // Get class items (methods, properties, events)\n    _.each(modules, function(m, idx, array) {\n      App.modules.push(m);\n      if (m.name == \"p5.sound\") {\n        App.sound.module = m;\n      }\n    });\n\n\n    var items = data.classitems;\n    var classes = data.classes;\n\n    // Get classes\n    _.each(classes, function(c, idx, array) {\n      if (!c.private) {\n        App.classes.push(c);\n      }\n    });\n\n\n    // Get class items (methods, properties, events)\n    _.each(items, function(el, idx, array) {\n      if (el.itemtype) {\n        if (el.itemtype === \"method\") {\n          el = new DocumentedMethod(el);\n          App.methods.push(el);\n          App.allItems.push(el);\n        } else if (el.itemtype === \"property\") {\n          App.properties.push(el);\n          App.allItems.push(el);\n        } else if (el.itemtype === \"event\") {\n          App.events.push(el);\n          App.allItems.push(el);\n        }\n\n        // libraries\n        if (el.module === \"p5.sound\") {\n          App.sound.items.push(el);\n        }\n      }\n    });\n\n    _.each(App.classes, function(c, idx) {\n      c.items = _.filter(App.allItems, function(it){ return it.class === c.name; });\n    });\n\n    require(['router']);\n  });\n});\n\ndefine(\"main\", function(){});\n\n",
        -    "}());"
        -  ]
        -}
        
        From 6832d0f609b53a9b5e9703465df548238937bc3f Mon Sep 17 00:00:00 2001
        From: sukrucildirr <sukrucildirr@gmail.com>
        Date: Wed, 4 Jun 2025 18:40:25 +0000
        Subject: [PATCH 177/282] Restore generated file to match upstream main
        
        ---
         .../assets/js/reference.js.map                | 54 +++++++++++++++++++
         1 file changed, 54 insertions(+)
         create mode 100644 docs/yuidoc-p5-theme/assets/js/reference.js.map
        
        diff --git a/docs/yuidoc-p5-theme/assets/js/reference.js.map b/docs/yuidoc-p5-theme/assets/js/reference.js.map
        new file mode 100644
        index 0000000000..abfb0b3794
        --- /dev/null
        +++ b/docs/yuidoc-p5-theme/assets/js/reference.js.map
        @@ -0,0 +1,54 @@
        +{
        +  "version": 3,
        +  "sources": [
        +    "../../../config-wrap-start-default.js",
        +    "documented-method.js",
        +    "vendor/require/text.js",
        +    "tpl/search.html!text",
        +    "tpl/search_suggestion.html!text",
        +    "vendor/typeahead-amd/typeahead.bundle.js",
        +    "views/searchView.js",
        +    "tpl/list.html!text",
        +    "views/listView.js",
        +    "tpl/item.html!text",
        +    "tpl/class.html!text",
        +    "tpl/itemEnd.html!text",
        +    "vendor/prettify/prettify.js",
        +    "views/itemView.js",
        +    "tpl/menu.html!text",
        +    "views/menuView.js",
        +    "tpl/library.html!text",
        +    "views/libraryView.js",
        +    "views/pageView.js",
        +    "router.js",
        +    "main.js",
        +    "../../../config-wrap-end-default.js"
        +  ],
        +  "names": [],
        +  "mappings": "AAAA;AACA,ACDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC7DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACnYA;AACA;AACA;AACA,ACHA;AACA;AACA;AACA,ACHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC9rDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC3HA;AACA;AACA;AACA,ACHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC3IA;AACA;AACA;AACA,ACHA;AACA;AACA;AACA,ACHA;AACA;AACA;AACA,ACHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC1nDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC/NA;AACA;AACA;AACA,ACHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AClEA;AACA;AACA;AACA,ACHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACjIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AChGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AClOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACxFA",
        +  "file": "reference.js",
        +  "sourcesContent": [
        +    "(function () {\n",
        +    "// https://github.com/umdjs/umd/blob/master/templates/returnExports.js\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    define('documented-method',[], factory);\n  } else if (typeof module === 'object' && module.exports) {\n    module.exports = factory();\n  } else {\n    root.DocumentedMethod = factory();\n  }\n}(this, function () {\n  function extend(target, src) {\n    Object.keys(src).forEach(function(prop) {\n      target[prop] = src[prop];\n    });\n    return target;\n  }\n\n  function DocumentedMethod(classitem) {\n    extend(this, classitem);\n\n    if (this.overloads) {\n      // Make each overload inherit properties from their parent\n      // classitem.\n      this.overloads = this.overloads.map(function(overload) {\n        return extend(Object.create(this), overload);\n      }, this);\n\n      if (this.params) {\n        throw new Error('params for overloaded methods should be undefined');\n      }\n\n      this.params = this._getMergedParams();\n    }\n  }\n\n  DocumentedMethod.prototype = {\n    // Merge parameters across all overloaded versions of this item.\n    _getMergedParams: function() {\n      var paramNames = {};\n      var params = [];\n\n      this.overloads.forEach(function(overload) {\n        if (!overload.params) {\n          return;\n        }\n        overload.params.forEach(function(param) {\n          if (param.name in paramNames) {\n            return;\n          }\n          paramNames[param.name] = param;\n          params.push(param);\n        });\n      });\n\n      return params;\n    }\n  };\n\n  return DocumentedMethod;\n}));\n\n",
        +    "/**\n * @license RequireJS text 2.0.10 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.\n * Available via the MIT or new BSD license.\n * see: http://github.com/requirejs/text for details\n */\n/*jslint regexp: true */\n/*global require, XMLHttpRequest, ActiveXObject,\n  define, window, process, Packages,\n  java, location, Components, FileUtils */\n\ndefine('text',['module'], function (module) {\n    'use strict';\n\n    var text, fs, Cc, Ci, xpcIsWindows,\n        progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'],\n        xmlRegExp = /^\\s*<\\?xml(\\s)+version=[\\'\\\"](\\d)*.(\\d)*[\\'\\\"](\\s)*\\?>/im,\n        bodyRegExp = /<body[^>]*>\\s*([\\s\\S]+)\\s*<\\/body>/im,\n        hasLocation = typeof location !== 'undefined' && location.href,\n        defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\\:/, ''),\n        defaultHostName = hasLocation && location.hostname,\n        defaultPort = hasLocation && (location.port || undefined),\n        buildMap = {},\n        masterConfig = (module.config && module.config()) || {};\n\n    text = {\n        version: '2.0.10',\n\n        strip: function (content) {\n            //Strips <?xml ...?> declarations so that external SVG and XML\n            //documents can be added to a document without worry. Also, if the string\n            //is an HTML document, only the part inside the body tag is returned.\n            if (content) {\n                content = content.replace(xmlRegExp, \"\");\n                var matches = content.match(bodyRegExp);\n                if (matches) {\n                    content = matches[1];\n                }\n            } else {\n                content = \"\";\n            }\n            return content;\n        },\n\n        jsEscape: function (content) {\n            return content.replace(/(['\\\\])/g, '\\\\$1')\n                .replace(/[\\f]/g, \"\\\\f\")\n                .replace(/[\\b]/g, \"\\\\b\")\n                .replace(/[\\n]/g, \"\\\\n\")\n                .replace(/[\\t]/g, \"\\\\t\")\n                .replace(/[\\r]/g, \"\\\\r\")\n                .replace(/[\\u2028]/g, \"\\\\u2028\")\n                .replace(/[\\u2029]/g, \"\\\\u2029\");\n        },\n\n        createXhr: masterConfig.createXhr || function () {\n            //Would love to dump the ActiveX crap in here. Need IE 6 to die first.\n            var xhr, i, progId;\n            if (typeof XMLHttpRequest !== \"undefined\") {\n                return new XMLHttpRequest();\n            } else if (typeof ActiveXObject !== \"undefined\") {\n                for (i = 0; i < 3; i += 1) {\n                    progId = progIds[i];\n                    try {\n                        xhr = new ActiveXObject(progId);\n                    } catch (e) {}\n\n                    if (xhr) {\n                        progIds = [progId];  // so faster next time\n                        break;\n                    }\n                }\n            }\n\n            return xhr;\n        },\n\n        /**\n         * Parses a resource name into its component parts. Resource names\n         * look like: module/name.ext!strip, where the !strip part is\n         * optional.\n         * @param {String} name the resource name\n         * @returns {Object} with properties \"moduleName\", \"ext\" and \"strip\"\n         * where strip is a boolean.\n         */\n        parseName: function (name) {\n            var modName, ext, temp,\n                strip = false,\n                index = name.indexOf(\".\"),\n                isRelative = name.indexOf('./') === 0 ||\n                             name.indexOf('../') === 0;\n\n            if (index !== -1 && (!isRelative || index > 1)) {\n                modName = name.substring(0, index);\n                ext = name.substring(index + 1, name.length);\n            } else {\n                modName = name;\n            }\n\n            temp = ext || modName;\n            index = temp.indexOf(\"!\");\n            if (index !== -1) {\n                //Pull off the strip arg.\n                strip = temp.substring(index + 1) === \"strip\";\n                temp = temp.substring(0, index);\n                if (ext) {\n                    ext = temp;\n                } else {\n                    modName = temp;\n                }\n            }\n\n            return {\n                moduleName: modName,\n                ext: ext,\n                strip: strip\n            };\n        },\n\n        xdRegExp: /^((\\w+)\\:)?\\/\\/([^\\/\\\\]+)/,\n\n        /**\n         * Is an URL on another domain. Only works for browser use, returns\n         * false in non-browser environments. Only used to know if an\n         * optimized .js version of a text resource should be loaded\n         * instead.\n         * @param {String} url\n         * @returns Boolean\n         */\n        useXhr: function (url, protocol, hostname, port) {\n            var uProtocol, uHostName, uPort,\n                match = text.xdRegExp.exec(url);\n            if (!match) {\n                return true;\n            }\n            uProtocol = match[2];\n            uHostName = match[3];\n\n            uHostName = uHostName.split(':');\n            uPort = uHostName[1];\n            uHostName = uHostName[0];\n\n            return (!uProtocol || uProtocol === protocol) &&\n                   (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) &&\n                   ((!uPort && !uHostName) || uPort === port);\n        },\n\n        finishLoad: function (name, strip, content, onLoad) {\n            content = strip ? text.strip(content) : content;\n            if (masterConfig.isBuild) {\n                buildMap[name] = content;\n            }\n            onLoad(content);\n        },\n\n        load: function (name, req, onLoad, config) {\n            //Name has format: some.module.filext!strip\n            //The strip part is optional.\n            //if strip is present, then that means only get the string contents\n            //inside a body tag in an HTML string. For XML/SVG content it means\n            //removing the <?xml ...?> declarations so the content can be inserted\n            //into the current doc without problems.\n\n            // Do not bother with the work if a build and text will\n            // not be inlined.\n            if (config.isBuild && !config.inlineText) {\n                onLoad();\n                return;\n            }\n\n            masterConfig.isBuild = config.isBuild;\n\n            var parsed = text.parseName(name),\n                nonStripName = parsed.moduleName +\n                    (parsed.ext ? '.' + parsed.ext : ''),\n                url = req.toUrl(nonStripName),\n                useXhr = (masterConfig.useXhr) ||\n                         text.useXhr;\n\n            // Do not load if it is an empty: url\n            if (url.indexOf('empty:') === 0) {\n                onLoad();\n                return;\n            }\n\n            //Load the text. Use XHR if possible and in a browser.\n            if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) {\n                text.get(url, function (content) {\n                    text.finishLoad(name, parsed.strip, content, onLoad);\n                }, function (err) {\n                    if (onLoad.error) {\n                        onLoad.error(err);\n                    }\n                });\n            } else {\n                //Need to fetch the resource across domains. Assume\n                //the resource has been optimized into a JS module. Fetch\n                //by the module name + extension, but do not include the\n                //!strip part to avoid file system issues.\n                req([nonStripName], function (content) {\n                    text.finishLoad(parsed.moduleName + '.' + parsed.ext,\n                                    parsed.strip, content, onLoad);\n                });\n            }\n        },\n\n        write: function (pluginName, moduleName, write, config) {\n            if (buildMap.hasOwnProperty(moduleName)) {\n                var content = text.jsEscape(buildMap[moduleName]);\n                write.asModule(pluginName + \"!\" + moduleName,\n                               \"define(function () { return '\" +\n                                   content +\n                               \"';});\\n\");\n            }\n        },\n\n        writeFile: function (pluginName, moduleName, req, write, config) {\n            var parsed = text.parseName(moduleName),\n                extPart = parsed.ext ? '.' + parsed.ext : '',\n                nonStripName = parsed.moduleName + extPart,\n                //Use a '.js' file name so that it indicates it is a\n                //script that can be loaded across domains.\n                fileName = req.toUrl(parsed.moduleName + extPart) + '.js';\n\n            //Leverage own load() method to load plugin value, but only\n            //write out values that do not have the strip argument,\n            //to avoid any potential issues with ! in file names.\n            text.load(nonStripName, req, function (value) {\n                //Use own write() method to construct full module value.\n                //But need to create shell that translates writeFile's\n                //write() to the right interface.\n                var textWrite = function (contents) {\n                    return write(fileName, contents);\n                };\n                textWrite.asModule = function (moduleName, contents) {\n                    return write.asModule(moduleName, fileName, contents);\n                };\n\n                text.write(pluginName, nonStripName, textWrite, config);\n            }, config);\n        }\n    };\n\n    if (masterConfig.env === 'node' || (!masterConfig.env &&\n            typeof process !== \"undefined\" &&\n            process.versions &&\n            !!process.versions.node &&\n            !process.versions['node-webkit'])) {\n        //Using special require.nodeRequire, something added by r.js.\n        fs = require.nodeRequire('fs');\n\n        text.get = function (url, callback, errback) {\n            try {\n                var file = fs.readFileSync(url, 'utf8');\n                //Remove BOM (Byte Mark Order) from utf8 files if it is there.\n                if (file.indexOf('\\uFEFF') === 0) {\n                    file = file.substring(1);\n                }\n                callback(file);\n            } catch (e) {\n                errback(e);\n            }\n        };\n    } else if (masterConfig.env === 'xhr' || (!masterConfig.env &&\n            text.createXhr())) {\n        text.get = function (url, callback, errback, headers) {\n            var xhr = text.createXhr(), header;\n            xhr.open('GET', url, true);\n\n            //Allow plugins direct access to xhr headers\n            if (headers) {\n                for (header in headers) {\n                    if (headers.hasOwnProperty(header)) {\n                        xhr.setRequestHeader(header.toLowerCase(), headers[header]);\n                    }\n                }\n            }\n\n            //Allow overrides specified in config\n            if (masterConfig.onXhr) {\n                masterConfig.onXhr(xhr, url);\n            }\n\n            xhr.onreadystatechange = function (evt) {\n                var status, err;\n                //Do not explicitly handle errors, those should be\n                //visible via console output in the browser.\n                if (xhr.readyState === 4) {\n                    status = xhr.status;\n                    if (status > 399 && status < 600) {\n                        //An http 4xx or 5xx error. Signal an error.\n                        err = new Error(url + ' HTTP status: ' + status);\n                        err.xhr = xhr;\n                        errback(err);\n                    } else {\n                        callback(xhr.responseText);\n                    }\n\n                    if (masterConfig.onXhrComplete) {\n                        masterConfig.onXhrComplete(xhr, url);\n                    }\n                }\n            };\n            xhr.send(null);\n        };\n    } else if (masterConfig.env === 'rhino' || (!masterConfig.env &&\n            typeof Packages !== 'undefined' && typeof java !== 'undefined')) {\n        //Why Java, why is this so awkward?\n        text.get = function (url, callback) {\n            var stringBuffer, line,\n                encoding = \"utf-8\",\n                file = new java.io.File(url),\n                lineSeparator = java.lang.System.getProperty(\"line.separator\"),\n                input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),\n                content = '';\n            try {\n                stringBuffer = new java.lang.StringBuffer();\n                line = input.readLine();\n\n                // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324\n                // http://www.unicode.org/faq/utf_bom.html\n\n                // Note that when we use utf-8, the BOM should appear as \"EF BB BF\", but it doesn't due to this bug in the JDK:\n                // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058\n                if (line && line.length() && line.charAt(0) === 0xfeff) {\n                    // Eat the BOM, since we've already found the encoding on this file,\n                    // and we plan to concatenating this buffer with others; the BOM should\n                    // only appear at the top of a file.\n                    line = line.substring(1);\n                }\n\n                if (line !== null) {\n                    stringBuffer.append(line);\n                }\n\n                while ((line = input.readLine()) !== null) {\n                    stringBuffer.append(lineSeparator);\n                    stringBuffer.append(line);\n                }\n                //Make sure we return a JavaScript string and not a Java string.\n                content = String(stringBuffer.toString()); //String\n            } finally {\n                input.close();\n            }\n            callback(content);\n        };\n    } else if (masterConfig.env === 'xpconnect' || (!masterConfig.env &&\n            typeof Components !== 'undefined' && Components.classes &&\n            Components.interfaces)) {\n        //Avert your gaze!\n        Cc = Components.classes,\n        Ci = Components.interfaces;\n        Components.utils['import']('resource://gre/modules/FileUtils.jsm');\n        xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc);\n\n        text.get = function (url, callback) {\n            var inStream, convertStream, fileObj,\n                readData = {};\n\n            if (xpcIsWindows) {\n                url = url.replace(/\\//g, '\\\\');\n            }\n\n            fileObj = new FileUtils.File(url);\n\n            //XPCOM, you so crazy\n            try {\n                inStream = Cc['@mozilla.org/network/file-input-stream;1']\n                           .createInstance(Ci.nsIFileInputStream);\n                inStream.init(fileObj, 1, 0, false);\n\n                convertStream = Cc['@mozilla.org/intl/converter-input-stream;1']\n                                .createInstance(Ci.nsIConverterInputStream);\n                convertStream.init(inStream, \"utf-8\", inStream.available(),\n                Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);\n\n                convertStream.readString(inStream.available(), readData);\n                convertStream.close();\n                inStream.close();\n                callback(readData.value);\n            } catch (e) {\n                throw new Error((fileObj && fileObj.path || '') + ': ' + e);\n            }\n        };\n    }\n    return text;\n});\n\n",
        +    "\ndefine('text!tpl/search.html',[],function () { return '<h2 class=\"sr-only\">search</h2>\\n<form>\\n  <input id=\"search_reference_field\" type=\"text\" class=\"<%=className%>\" value=\"\" placeholder=\"<%=placeholder%>\" aria-label=\"search reference\">\\n  <label class=\"sr-only\" for=\"search_reference_field\">Search reference</label>\\n</form>\\n\\n';});\n\n",
        +    "\ndefine('text!tpl/search_suggestion.html',[],function () { return '<p id=\"index-<%=idx%>\" class=\"search-suggestion\">\\n\\n  <strong><%=name%></strong>\\n\\n  <span class=\"small\">\\n    <% if (final) { %>\\n    constant\\n    <% } else if (itemtype) { %>\\n    <%=itemtype%> \\n    <% } %>\\n\\n    <% if (className) { %>\\n    in <strong><%=className%></strong>\\n    <% } %>\\n\\n    <% if (typeof is_constructor !== \\'undefined\\' && is_constructor) { %>\\n    <strong><span class=\"glyphicon glyphicon-star\"></span> constructor</strong>\\n    <% } %>\\n  </span>\\n\\n</p>';});\n\n",
        +    "/*!\n * typeahead.js 0.10.2\n * https://github.com/twitter/typeahead.js\n * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT\n */\ndefine('typeahead',[], function() {\n\n//(function($) {\n\n\n    var _ = {\n        isMsie: function() {\n            return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\\d+(.\\d+)?)/i)[2] : false;\n        },\n        isBlankString: function(str) {\n            return !str || /^\\s*$/.test(str);\n        },\n        escapeRegExChars: function(str) {\n            return str.replace(/[\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|]/g, \"\\\\$&\");\n        },\n        isString: function(obj) {\n            return typeof obj === \"string\";\n        },\n        isNumber: function(obj) {\n            return typeof obj === \"number\";\n        },\n        isArray: $.isArray,\n        isFunction: $.isFunction,\n        isObject: $.isPlainObject,\n        isUndefined: function(obj) {\n            return typeof obj === \"undefined\";\n        },\n        bind: $.proxy,\n        each: function(collection, cb) {\n            $.each(collection, reverseArgs);\n            function reverseArgs(index, value) {\n                return cb(value, index);\n            }\n        },\n        map: $.map,\n        filter: $.grep,\n        every: function(obj, test) {\n            var result = true;\n            if (!obj) {\n                return result;\n            }\n            $.each(obj, function(key, val) {\n                if (!(result = test.call(null, val, key, obj))) {\n                    return false;\n                }\n            });\n            return !!result;\n        },\n        some: function(obj, test) {\n            var result = false;\n            if (!obj) {\n                return result;\n            }\n            $.each(obj, function(key, val) {\n                if (result = test.call(null, val, key, obj)) {\n                    return false;\n                }\n            });\n            return !!result;\n        },\n        mixin: $.extend,\n        getUniqueId: function() {\n            var counter = 0;\n            return function() {\n                return counter++;\n            };\n        }(),\n        templatify: function templatify(obj) {\n            return $.isFunction(obj) ? obj : template;\n            function template() {\n                return String(obj);\n            }\n        },\n        defer: function(fn) {\n            setTimeout(fn, 0);\n        },\n        debounce: function(func, wait, immediate) {\n            var timeout, result;\n            return function() {\n                var context = this, args = arguments, later, callNow;\n                later = function() {\n                    timeout = null;\n                    if (!immediate) {\n                        result = func.apply(context, args);\n                    }\n                };\n                callNow = immediate && !timeout;\n                clearTimeout(timeout);\n                timeout = setTimeout(later, wait);\n                if (callNow) {\n                    result = func.apply(context, args);\n                }\n                return result;\n            };\n        },\n        throttle: function(func, wait) {\n            var context, args, timeout, result, previous, later;\n            previous = 0;\n            later = function() {\n                previous = new Date();\n                timeout = null;\n                result = func.apply(context, args);\n            };\n            return function() {\n                var now = new Date(), remaining = wait - (now - previous);\n                context = this;\n                args = arguments;\n                if (remaining <= 0) {\n                    clearTimeout(timeout);\n                    timeout = null;\n                    previous = now;\n                    result = func.apply(context, args);\n                } else if (!timeout) {\n                    timeout = setTimeout(later, remaining);\n                }\n                return result;\n            };\n        },\n        noop: function() {}\n    };\n    var VERSION = \"0.10.2\";\n    var tokenizers = function(root) {\n        return {\n            nonword: nonword,\n            whitespace: whitespace,\n            obj: {\n                nonword: getObjTokenizer(nonword),\n                whitespace: getObjTokenizer(whitespace)\n            }\n        };\n        function whitespace(s) {\n            return s.split(/\\s+/);\n        }\n        function nonword(s) {\n            return s.split(/\\W+/);\n        }\n        function getObjTokenizer(tokenizer) {\n            return function setKey(key) {\n                return function tokenize(o) {\n                    return tokenizer(o[key]);\n                };\n            };\n        }\n    }();\n    var LruCache = function() {\n        function LruCache(maxSize) {\n            this.maxSize = maxSize || 100;\n            this.size = 0;\n            this.hash = {};\n            this.list = new List();\n        }\n        _.mixin(LruCache.prototype, {\n            set: function set(key, val) {\n                var tailItem = this.list.tail, node;\n                if (this.size >= this.maxSize) {\n                    this.list.remove(tailItem);\n                    delete this.hash[tailItem.key];\n                }\n                if (node = this.hash[key]) {\n                    node.val = val;\n                    this.list.moveToFront(node);\n                } else {\n                    node = new Node(key, val);\n                    this.list.add(node);\n                    this.hash[key] = node;\n                    this.size++;\n                }\n            },\n            get: function get(key) {\n                var node = this.hash[key];\n                if (node) {\n                    this.list.moveToFront(node);\n                    return node.val;\n                }\n            }\n        });\n        function List() {\n            this.head = this.tail = null;\n        }\n        _.mixin(List.prototype, {\n            add: function add(node) {\n                if (this.head) {\n                    node.next = this.head;\n                    this.head.prev = node;\n                }\n                this.head = node;\n                this.tail = this.tail || node;\n            },\n            remove: function remove(node) {\n                node.prev ? node.prev.next = node.next : this.head = node.next;\n                node.next ? node.next.prev = node.prev : this.tail = node.prev;\n            },\n            moveToFront: function(node) {\n                this.remove(node);\n                this.add(node);\n            }\n        });\n        function Node(key, val) {\n            this.key = key;\n            this.val = val;\n            this.prev = this.next = null;\n        }\n        return LruCache;\n    }();\n    var PersistentStorage = function() {\n        var ls, methods;\n        try {\n            ls = window.localStorage;\n            ls.setItem(\"~~~\", \"!\");\n            ls.removeItem(\"~~~\");\n        } catch (err) {\n            ls = null;\n        }\n        function PersistentStorage(namespace) {\n            this.prefix = [ \"__\", namespace, \"__\" ].join(\"\");\n            this.ttlKey = \"__ttl__\";\n            this.keyMatcher = new RegExp(\"^\" + this.prefix);\n        }\n        if (ls && window.JSON) {\n            methods = {\n                _prefix: function(key) {\n                    return this.prefix + key;\n                },\n                _ttlKey: function(key) {\n                    return this._prefix(key) + this.ttlKey;\n                },\n                get: function(key) {\n                    if (this.isExpired(key)) {\n                        this.remove(key);\n                    }\n                    return decode(ls.getItem(this._prefix(key)));\n                },\n                set: function(key, val, ttl) {\n                    if (_.isNumber(ttl)) {\n                        ls.setItem(this._ttlKey(key), encode(now() + ttl));\n                    } else {\n                        ls.removeItem(this._ttlKey(key));\n                    }\n                    return ls.setItem(this._prefix(key), encode(val));\n                },\n                remove: function(key) {\n                    ls.removeItem(this._ttlKey(key));\n                    ls.removeItem(this._prefix(key));\n                    return this;\n                },\n                clear: function() {\n                    var i, key, keys = [], len = ls.length;\n                    for (i = 0; i < len; i++) {\n                        if ((key = ls.key(i)).match(this.keyMatcher)) {\n                            keys.push(key.replace(this.keyMatcher, \"\"));\n                        }\n                    }\n                    for (i = keys.length; i--; ) {\n                        this.remove(keys[i]);\n                    }\n                    return this;\n                },\n                isExpired: function(key) {\n                    var ttl = decode(ls.getItem(this._ttlKey(key)));\n                    return _.isNumber(ttl) && now() > ttl ? true : false;\n                }\n            };\n        } else {\n            methods = {\n                get: _.noop,\n                set: _.noop,\n                remove: _.noop,\n                clear: _.noop,\n                isExpired: _.noop\n            };\n        }\n        _.mixin(PersistentStorage.prototype, methods);\n        return PersistentStorage;\n        function now() {\n            return new Date().getTime();\n        }\n        function encode(val) {\n            return JSON.stringify(_.isUndefined(val) ? null : val);\n        }\n        function decode(val) {\n            return JSON.parse(val);\n        }\n    }();\n    var Transport = function() {\n        var pendingRequestsCount = 0, pendingRequests = {}, maxPendingRequests = 6, requestCache = new LruCache(10);\n        function Transport(o) {\n            o = o || {};\n            this._send = o.transport ? callbackToDeferred(o.transport) : $.ajax;\n            this._get = o.rateLimiter ? o.rateLimiter(this._get) : this._get;\n        }\n        Transport.setMaxPendingRequests = function setMaxPendingRequests(num) {\n            maxPendingRequests = num;\n        };\n        Transport.resetCache = function clearCache() {\n            requestCache = new LruCache(10);\n        };\n        _.mixin(Transport.prototype, {\n            _get: function(url, o, cb) {\n                var that = this, jqXhr;\n                if (jqXhr = pendingRequests[url]) {\n                    jqXhr.done(done).fail(fail);\n                } else if (pendingRequestsCount < maxPendingRequests) {\n                    pendingRequestsCount++;\n                    pendingRequests[url] = this._send(url, o).done(done).fail(fail).always(always);\n                } else {\n                    this.onDeckRequestArgs = [].slice.call(arguments, 0);\n                }\n                function done(resp) {\n                    cb && cb(null, resp);\n                    requestCache.set(url, resp);\n                }\n                function fail() {\n                    cb && cb(true);\n                }\n                function always() {\n                    pendingRequestsCount--;\n                    delete pendingRequests[url];\n                    if (that.onDeckRequestArgs) {\n                        that._get.apply(that, that.onDeckRequestArgs);\n                        that.onDeckRequestArgs = null;\n                    }\n                }\n            },\n            get: function(url, o, cb) {\n                var resp;\n                if (_.isFunction(o)) {\n                    cb = o;\n                    o = {};\n                }\n                if (resp = requestCache.get(url)) {\n                    _.defer(function() {\n                        cb && cb(null, resp);\n                    });\n                } else {\n                    this._get(url, o, cb);\n                }\n                return !!resp;\n            }\n        });\n        return Transport;\n        function callbackToDeferred(fn) {\n            return function customSendWrapper(url, o) {\n                var deferred = $.Deferred();\n                fn(url, o, onSuccess, onError);\n                return deferred;\n                function onSuccess(resp) {\n                    _.defer(function() {\n                        deferred.resolve(resp);\n                    });\n                }\n                function onError(err) {\n                    _.defer(function() {\n                        deferred.reject(err);\n                    });\n                }\n            };\n        }\n    }();\n    var SearchIndex = function() {\n        function SearchIndex(o) {\n            o = o || {};\n            if (!o.datumTokenizer || !o.queryTokenizer) {\n                $.error(\"datumTokenizer and queryTokenizer are both required\");\n            }\n            this.datumTokenizer = o.datumTokenizer;\n            this.queryTokenizer = o.queryTokenizer;\n            this.reset();\n        }\n        _.mixin(SearchIndex.prototype, {\n            bootstrap: function bootstrap(o) {\n                this.datums = o.datums;\n                this.trie = o.trie;\n            },\n            add: function(data) {\n                var that = this;\n                data = _.isArray(data) ? data : [ data ];\n                _.each(data, function(datum) {\n                    var id, tokens;\n                    id = that.datums.push(datum) - 1;\n                    tokens = normalizeTokens(that.datumTokenizer(datum));\n                    _.each(tokens, function(token) {\n                        var node, chars, ch;\n                        node = that.trie;\n                        chars = token.split(\"\");\n                        while (ch = chars.shift()) {\n                            node = node.children[ch] || (node.children[ch] = newNode());\n                            node.ids.push(id);\n                        }\n                    });\n                });\n            },\n            get: function get(query) {\n                var that = this, tokens, matches;\n                tokens = normalizeTokens(this.queryTokenizer(query));\n                _.each(tokens, function(token) {\n                    var node, chars, ch, ids;\n                    if (matches && matches.length === 0) {\n                        return false;\n                    }\n                    node = that.trie;\n                    chars = token.split(\"\");\n                    while (node && (ch = chars.shift())) {\n                        node = node.children[ch];\n                    }\n                    if (node && chars.length === 0) {\n                        ids = node.ids.slice(0);\n                        matches = matches ? getIntersection(matches, ids) : ids;\n                    } else {\n                        matches = [];\n                        return false;\n                    }\n                });\n                return matches ? _.map(unique(matches), function(id) {\n                    return that.datums[id];\n                }) : [];\n            },\n            reset: function reset() {\n                this.datums = [];\n                this.trie = newNode();\n            },\n            serialize: function serialize() {\n                return {\n                    datums: this.datums,\n                    trie: this.trie\n                };\n            }\n        });\n        return SearchIndex;\n        function normalizeTokens(tokens) {\n            tokens = _.filter(tokens, function(token) {\n                return !!token;\n            });\n            tokens = _.map(tokens, function(token) {\n                return token.toLowerCase();\n            });\n            return tokens;\n        }\n        function newNode() {\n            return {\n                ids: [],\n                children: {}\n            };\n        }\n        function unique(array) {\n            var seen = {}, uniques = [];\n            for (var i = 0; i < array.length; i++) {\n                if (!seen[array[i]]) {\n                    seen[array[i]] = true;\n                    uniques.push(array[i]);\n                }\n            }\n            return uniques;\n        }\n        function getIntersection(arrayA, arrayB) {\n            var ai = 0, bi = 0, intersection = [];\n            arrayA = arrayA.sort(compare);\n            arrayB = arrayB.sort(compare);\n            while (ai < arrayA.length && bi < arrayB.length) {\n                if (arrayA[ai] < arrayB[bi]) {\n                    ai++;\n                } else if (arrayA[ai] > arrayB[bi]) {\n                    bi++;\n                } else {\n                    intersection.push(arrayA[ai]);\n                    ai++;\n                    bi++;\n                }\n            }\n            return intersection;\n            function compare(a, b) {\n                return a - b;\n            }\n        }\n    }();\n    var oParser = function() {\n        return {\n            local: getLocal,\n            prefetch: getPrefetch,\n            remote: getRemote\n        };\n        function getLocal(o) {\n            return o.local || null;\n        }\n        function getPrefetch(o) {\n            var prefetch, defaults;\n            defaults = {\n                url: null,\n                thumbprint: \"\",\n                ttl: 24 * 60 * 60 * 1e3,\n                filter: null,\n                ajax: {}\n            };\n            if (prefetch = o.prefetch || null) {\n                prefetch = _.isString(prefetch) ? {\n                    url: prefetch\n                } : prefetch;\n                prefetch = _.mixin(defaults, prefetch);\n                prefetch.thumbprint = VERSION + prefetch.thumbprint;\n                prefetch.ajax.type = prefetch.ajax.type || \"GET\";\n                prefetch.ajax.dataType = prefetch.ajax.dataType || \"json\";\n                !prefetch.url && $.error(\"prefetch requires url to be set\");\n            }\n            return prefetch;\n        }\n        function getRemote(o) {\n            var remote, defaults;\n            defaults = {\n                url: null,\n                wildcard: \"%QUERY\",\n                replace: null,\n                rateLimitBy: \"debounce\",\n                rateLimitWait: 300,\n                send: null,\n                filter: null,\n                ajax: {}\n            };\n            if (remote = o.remote || null) {\n                remote = _.isString(remote) ? {\n                    url: remote\n                } : remote;\n                remote = _.mixin(defaults, remote);\n                remote.rateLimiter = /^throttle$/i.test(remote.rateLimitBy) ? byThrottle(remote.rateLimitWait) : byDebounce(remote.rateLimitWait);\n                remote.ajax.type = remote.ajax.type || \"GET\";\n                remote.ajax.dataType = remote.ajax.dataType || \"json\";\n                delete remote.rateLimitBy;\n                delete remote.rateLimitWait;\n                !remote.url && $.error(\"remote requires url to be set\");\n            }\n            return remote;\n            function byDebounce(wait) {\n                return function(fn) {\n                    return _.debounce(fn, wait);\n                };\n            }\n            function byThrottle(wait) {\n                return function(fn) {\n                    return _.throttle(fn, wait);\n                };\n            }\n        }\n    }();\n    (function(root) {\n        var old, keys;\n        old = root.Bloodhound;\n        keys = {\n            data: \"data\",\n            protocol: \"protocol\",\n            thumbprint: \"thumbprint\"\n        };\n        root.Bloodhound = Bloodhound;\n        function Bloodhound(o) {\n            if (!o || !o.local && !o.prefetch && !o.remote) {\n                $.error(\"one of local, prefetch, or remote is required\");\n            }\n            this.limit = o.limit || 5;\n            this.sorter = getSorter(o.sorter);\n            this.dupDetector = o.dupDetector || ignoreDuplicates;\n            this.local = oParser.local(o);\n            this.prefetch = oParser.prefetch(o);\n            this.remote = oParser.remote(o);\n            this.cacheKey = this.prefetch ? this.prefetch.cacheKey || this.prefetch.url : null;\n            this.index = new SearchIndex({\n                datumTokenizer: o.datumTokenizer,\n                queryTokenizer: o.queryTokenizer\n            });\n            this.storage = this.cacheKey ? new PersistentStorage(this.cacheKey) : null;\n        }\n        Bloodhound.noConflict = function noConflict() {\n            root.Bloodhound = old;\n            return Bloodhound;\n        };\n        Bloodhound.tokenizers = tokenizers;\n        _.mixin(Bloodhound.prototype, {\n            _loadPrefetch: function loadPrefetch(o) {\n                var that = this, serialized, deferred;\n                if (serialized = this._readFromStorage(o.thumbprint)) {\n                    this.index.bootstrap(serialized);\n                    deferred = $.Deferred().resolve();\n                } else {\n                    deferred = $.ajax(o.url, o.ajax).done(handlePrefetchResponse);\n                }\n                return deferred;\n                function handlePrefetchResponse(resp) {\n                    that.clear();\n                    that.add(o.filter ? o.filter(resp) : resp);\n                    that._saveToStorage(that.index.serialize(), o.thumbprint, o.ttl);\n                }\n            },\n            _getFromRemote: function getFromRemote(query, cb) {\n                var that = this, url, uriEncodedQuery;\n                query = query || \"\";\n                uriEncodedQuery = encodeURIComponent(query);\n                url = this.remote.replace ? this.remote.replace(this.remote.url, query) : this.remote.url.replace(this.remote.wildcard, uriEncodedQuery);\n                return this.transport.get(url, this.remote.ajax, handleRemoteResponse);\n                function handleRemoteResponse(err, resp) {\n                    err ? cb([]) : cb(that.remote.filter ? that.remote.filter(resp) : resp);\n                }\n            },\n            _saveToStorage: function saveToStorage(data, thumbprint, ttl) {\n                if (this.storage) {\n                    this.storage.set(keys.data, data, ttl);\n                    this.storage.set(keys.protocol, location.protocol, ttl);\n                    this.storage.set(keys.thumbprint, thumbprint, ttl);\n                }\n            },\n            _readFromStorage: function readFromStorage(thumbprint) {\n                var stored = {}, isExpired;\n                if (this.storage) {\n                    stored.data = this.storage.get(keys.data);\n                    stored.protocol = this.storage.get(keys.protocol);\n                    stored.thumbprint = this.storage.get(keys.thumbprint);\n                }\n                isExpired = stored.thumbprint !== thumbprint || stored.protocol !== location.protocol;\n                return stored.data && !isExpired ? stored.data : null;\n            },\n            _initialize: function initialize() {\n                var that = this, local = this.local, deferred;\n                deferred = this.prefetch ? this._loadPrefetch(this.prefetch) : $.Deferred().resolve();\n                local && deferred.done(addLocalToIndex);\n                this.transport = this.remote ? new Transport(this.remote) : null;\n                return this.initPromise = deferred.promise();\n                function addLocalToIndex() {\n                    that.add(_.isFunction(local) ? local() : local);\n                }\n            },\n            initialize: function initialize(force) {\n                return !this.initPromise || force ? this._initialize() : this.initPromise;\n            },\n            add: function add(data) {\n                this.index.add(data);\n            },\n            get: function get(query, cb) {\n                var that = this, matches = [], cacheHit = false;\n                matches = this.index.get(query);\n                matches = this.sorter(matches).slice(0, this.limit);\n                if (matches.length < this.limit && this.transport) {\n                    cacheHit = this._getFromRemote(query, returnRemoteMatches);\n                }\n                if (!cacheHit) {\n                    (matches.length > 0 || !this.transport) && cb && cb(matches);\n                }\n                function returnRemoteMatches(remoteMatches) {\n                    var matchesWithBackfill = matches.slice(0);\n                    _.each(remoteMatches, function(remoteMatch) {\n                        var isDuplicate;\n                        isDuplicate = _.some(matchesWithBackfill, function(match) {\n                            return that.dupDetector(remoteMatch, match);\n                        });\n                        !isDuplicate && matchesWithBackfill.push(remoteMatch);\n                        return matchesWithBackfill.length < that.limit;\n                    });\n                    cb && cb(that.sorter(matchesWithBackfill));\n                }\n            },\n            clear: function clear() {\n                this.index.reset();\n            },\n            clearPrefetchCache: function clearPrefetchCache() {\n                this.storage && this.storage.clear();\n            },\n            clearRemoteCache: function clearRemoteCache() {\n                this.transport && Transport.resetCache();\n            },\n            ttAdapter: function ttAdapter() {\n                return _.bind(this.get, this);\n            }\n        });\n        return Bloodhound;\n        function getSorter(sortFn) {\n            return _.isFunction(sortFn) ? sort : noSort;\n            function sort(array) {\n                return array.sort(sortFn);\n            }\n            function noSort(array) {\n                return array;\n            }\n        }\n        function ignoreDuplicates() {\n            return false;\n        }\n    })(this);\n    var html = {\n        wrapper: '<span class=\"twitter-typeahead\"></span>',\n        dropdown: '<span class=\"tt-dropdown-menu\"></span>',\n        dataset: '<div class=\"tt-dataset-%CLASS%\"></div>',\n        suggestions: '<span class=\"tt-suggestions\"></span>',\n        suggestion: '<div class=\"tt-suggestion\"></div>'\n    };\n    var css = {\n        wrapper: {\n            position: \"relative\",\n            display: \"inline-block\"\n        },\n        hint: {\n            position: \"absolute\",\n            top: \"0\",\n            left: \"0\",\n            borderColor: \"transparent\",\n            boxShadow: \"none\"\n        },\n        input: {\n            position: \"relative\",\n            verticalAlign: \"top\",\n            backgroundColor: \"transparent\"\n        },\n        inputWithNoHint: {\n            position: \"relative\",\n            verticalAlign: \"top\"\n        },\n        dropdown: {\n            position: \"absolute\",\n            top: \"100%\",\n            left: \"0\",\n            zIndex: \"100\",\n            display: \"none\"\n        },\n        suggestions: {\n            display: \"block\"\n        },\n        suggestion: {\n            whiteSpace: \"nowrap\",\n            cursor: \"pointer\"\n        },\n        suggestionChild: {\n            whiteSpace: \"normal\"\n        },\n        ltr: {\n            left: \"0\",\n            right: \"auto\"\n        },\n        rtl: {\n            left: \"auto\",\n            right: \" 0\"\n        }\n    };\n    if (_.isMsie()) {\n        _.mixin(css.input, {\n            backgroundImage: \"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)\"\n        });\n    }\n    if (_.isMsie() && _.isMsie() <= 7) {\n        _.mixin(css.input, {\n            marginTop: \"-1px\"\n        });\n    }\n    var EventBus = function() {\n        var namespace = \"typeahead:\";\n        function EventBus(o) {\n            if (!o || !o.el) {\n                $.error(\"EventBus initialized without el\");\n            }\n            this.$el = $(o.el);\n        }\n        _.mixin(EventBus.prototype, {\n            trigger: function(type) {\n                var args = [].slice.call(arguments, 1);\n                this.$el.trigger(namespace + type, args);\n            }\n        });\n        return EventBus;\n    }();\n    var EventEmitter = function() {\n        var splitter = /\\s+/, nextTick = getNextTick();\n        return {\n            onSync: onSync,\n            onAsync: onAsync,\n            off: off,\n            trigger: trigger\n        };\n        function on(method, types, cb, context) {\n            var type;\n            if (!cb) {\n                return this;\n            }\n            types = types.split(splitter);\n            cb = context ? bindContext(cb, context) : cb;\n            this._callbacks = this._callbacks || {};\n            while (type = types.shift()) {\n                this._callbacks[type] = this._callbacks[type] || {\n                    sync: [],\n                    async: []\n                };\n                this._callbacks[type][method].push(cb);\n            }\n            return this;\n        }\n        function onAsync(types, cb, context) {\n            return on.call(this, \"async\", types, cb, context);\n        }\n        function onSync(types, cb, context) {\n            return on.call(this, \"sync\", types, cb, context);\n        }\n        function off(types) {\n            var type;\n            if (!this._callbacks) {\n                return this;\n            }\n            types = types.split(splitter);\n            while (type = types.shift()) {\n                delete this._callbacks[type];\n            }\n            return this;\n        }\n        function trigger(types) {\n            var type, callbacks, args, syncFlush, asyncFlush;\n            if (!this._callbacks) {\n                return this;\n            }\n            types = types.split(splitter);\n            args = [].slice.call(arguments, 1);\n            while ((type = types.shift()) && (callbacks = this._callbacks[type])) {\n                syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args));\n                asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args));\n                syncFlush() && nextTick(asyncFlush);\n            }\n            return this;\n        }\n        function getFlush(callbacks, context, args) {\n            return flush;\n            function flush() {\n                var cancelled;\n                for (var i = 0; !cancelled && i < callbacks.length; i += 1) {\n                    cancelled = callbacks[i].apply(context, args) === false;\n                }\n                return !cancelled;\n            }\n        }\n        function getNextTick() {\n            var nextTickFn;\n            if (window.setImmediate) {\n                nextTickFn = function nextTickSetImmediate(fn) {\n                    setImmediate(function() {\n                        fn();\n                    });\n                };\n            } else {\n                nextTickFn = function nextTickSetTimeout(fn) {\n                    setTimeout(function() {\n                        fn();\n                    }, 0);\n                };\n            }\n            return nextTickFn;\n        }\n        function bindContext(fn, context) {\n            return fn.bind ? fn.bind(context) : function() {\n                fn.apply(context, [].slice.call(arguments, 0));\n            };\n        }\n    }();\n    var highlight = function(doc) {\n        var defaults = {\n            node: null,\n            pattern: null,\n            tagName: \"strong\",\n            className: null,\n            wordsOnly: false,\n            caseSensitive: false\n        };\n        return function hightlight(o) {\n            var regex;\n            o = _.mixin({}, defaults, o);\n            if (!o.node || !o.pattern) {\n                return;\n            }\n            o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ];\n            regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly);\n            traverse(o.node, hightlightTextNode);\n            function hightlightTextNode(textNode) {\n                var match, patternNode;\n                if (match = regex.exec(textNode.data)) {\n                    wrapperNode = doc.createElement(o.tagName);\n                    o.className && (wrapperNode.className = o.className);\n                    patternNode = textNode.splitText(match.index);\n                    patternNode.splitText(match[0].length);\n                    wrapperNode.appendChild(patternNode.cloneNode(true));\n                    textNode.parentNode.replaceChild(wrapperNode, patternNode);\n                }\n                return !!match;\n            }\n            function traverse(el, hightlightTextNode) {\n                var childNode, TEXT_NODE_TYPE = 3;\n                for (var i = 0; i < el.childNodes.length; i++) {\n                    childNode = el.childNodes[i];\n                    if (childNode.nodeType === TEXT_NODE_TYPE) {\n                        i += hightlightTextNode(childNode) ? 1 : 0;\n                    } else {\n                        traverse(childNode, hightlightTextNode);\n                    }\n                }\n            }\n        };\n        function getRegex(patterns, caseSensitive, wordsOnly) {\n            var escapedPatterns = [], regexStr;\n            for (var i = 0; i < patterns.length; i++) {\n                escapedPatterns.push(_.escapeRegExChars(patterns[i]));\n            }\n            regexStr = wordsOnly ? \"\\\\b(\" + escapedPatterns.join(\"|\") + \")\\\\b\" : \"(\" + escapedPatterns.join(\"|\") + \")\";\n            return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, \"i\");\n        }\n    }(window.document);\n    var Input = function() {\n        var specialKeyCodeMap;\n        specialKeyCodeMap = {\n            9: \"tab\",\n            27: \"esc\",\n            37: \"left\",\n            39: \"right\",\n            13: \"enter\",\n            38: \"up\",\n            40: \"down\"\n        };\n        function Input(o) {\n            var that = this, onBlur, onFocus, onKeydown, onInput;\n            o = o || {};\n            if (!o.input) {\n                $.error(\"input is missing\");\n            }\n            onBlur = _.bind(this._onBlur, this);\n            onFocus = _.bind(this._onFocus, this);\n            onKeydown = _.bind(this._onKeydown, this);\n            onInput = _.bind(this._onInput, this);\n            this.$hint = $(o.hint);\n            this.$input = $(o.input).on(\"blur.tt\", onBlur).on(\"focus.tt\", onFocus).on(\"keydown.tt\", onKeydown);\n            if (this.$hint.length === 0) {\n                this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop;\n            }\n            if (!_.isMsie()) {\n                this.$input.on(\"input.tt\", onInput);\n            } else {\n                this.$input.on(\"keydown.tt keypress.tt cut.tt paste.tt\", function($e) {\n                    if (specialKeyCodeMap[$e.which || $e.keyCode]) {\n                        return;\n                    }\n                    _.defer(_.bind(that._onInput, that, $e));\n                });\n            }\n            this.query = this.$input.val();\n            this.$overflowHelper = buildOverflowHelper(this.$input);\n        }\n        Input.normalizeQuery = function(str) {\n            return (str || \"\").replace(/^\\s*/g, \"\").replace(/\\s{2,}/g, \" \");\n        };\n        _.mixin(Input.prototype, EventEmitter, {\n            _onBlur: function onBlur() {\n                this.resetInputValue();\n                this.trigger(\"blurred\");\n            },\n            _onFocus: function onFocus() {\n                this.trigger(\"focused\");\n            },\n            _onKeydown: function onKeydown($e) {\n                var keyName = specialKeyCodeMap[$e.which || $e.keyCode];\n                this._managePreventDefault(keyName, $e);\n                if (keyName && this._shouldTrigger(keyName, $e)) {\n                    this.trigger(keyName + \"Keyed\", $e);\n                }\n            },\n            _onInput: function onInput() {\n                this._checkInputValue();\n            },\n            _managePreventDefault: function managePreventDefault(keyName, $e) {\n                var preventDefault, hintValue, inputValue;\n                switch (keyName) {\n                  case \"tab\":\n                    hintValue = this.getHint();\n                    inputValue = this.getInputValue();\n                    preventDefault = hintValue && hintValue !== inputValue && !withModifier($e);\n                    break;\n\n                  case \"up\":\n                  case \"down\":\n                    preventDefault = !withModifier($e);\n                    break;\n\n                  default:\n                    preventDefault = false;\n                }\n                preventDefault && $e.preventDefault();\n            },\n            _shouldTrigger: function shouldTrigger(keyName, $e) {\n                var trigger;\n                switch (keyName) {\n                  case \"tab\":\n                    trigger = !withModifier($e);\n                    break;\n\n                  default:\n                    trigger = true;\n                }\n                return trigger;\n            },\n            _checkInputValue: function checkInputValue() {\n                var inputValue, areEquivalent, hasDifferentWhitespace;\n                inputValue = this.getInputValue();\n                areEquivalent = areQueriesEquivalent(inputValue, this.query);\n                hasDifferentWhitespace = areEquivalent ? this.query.length !== inputValue.length : false;\n                if (!areEquivalent) {\n                    this.trigger(\"queryChanged\", this.query = inputValue);\n                } else if (hasDifferentWhitespace) {\n                    this.trigger(\"whitespaceChanged\", this.query);\n                }\n            },\n            focus: function focus() {\n                this.$input.focus();\n            },\n            blur: function blur() {\n                this.$input.blur();\n            },\n            getQuery: function getQuery() {\n                return this.query;\n            },\n            setQuery: function setQuery(query) {\n                this.query = query;\n            },\n            getInputValue: function getInputValue() {\n                return this.$input.val();\n            },\n            setInputValue: function setInputValue(value, silent) {\n                this.$input.val(value);\n                silent ? this.clearHint() : this._checkInputValue();\n            },\n            resetInputValue: function resetInputValue() {\n                this.setInputValue(this.query, true);\n            },\n            getHint: function getHint() {\n                return this.$hint.val();\n            },\n            setHint: function setHint(value) {\n                this.$hint.val(value);\n            },\n            clearHint: function clearHint() {\n                this.setHint(\"\");\n            },\n            clearHintIfInvalid: function clearHintIfInvalid() {\n                var val, hint, valIsPrefixOfHint, isValid;\n                val = this.getInputValue();\n                hint = this.getHint();\n                valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0;\n                isValid = val !== \"\" && valIsPrefixOfHint && !this.hasOverflow();\n                !isValid && this.clearHint();\n            },\n            getLanguageDirection: function getLanguageDirection() {\n                return (this.$input.css(\"direction\") || \"ltr\").toLowerCase();\n            },\n            hasOverflow: function hasOverflow() {\n                var constraint = this.$input.width() - 2;\n                this.$overflowHelper.text(this.getInputValue());\n                return this.$overflowHelper.width() >= constraint;\n            },\n            isCursorAtEnd: function() {\n                var valueLength, selectionStart, range;\n                valueLength = this.$input.val().length;\n                selectionStart = this.$input[0].selectionStart;\n                if (_.isNumber(selectionStart)) {\n                    return selectionStart === valueLength;\n                } else if (document.selection) {\n                    range = document.selection.createRange();\n                    range.moveStart(\"character\", -valueLength);\n                    return valueLength === range.text.length;\n                }\n                return true;\n            },\n            destroy: function destroy() {\n                this.$hint.off(\".tt\");\n                this.$input.off(\".tt\");\n                this.$hint = this.$input = this.$overflowHelper = null;\n            }\n        });\n        return Input;\n        function buildOverflowHelper($input) {\n            return $('<pre aria-hidden=\"true\"></pre>').css({\n                position: \"absolute\",\n                visibility: \"hidden\",\n                whiteSpace: \"pre\",\n                fontFamily: $input.css(\"font-family\"),\n                fontSize: $input.css(\"font-size\"),\n                fontStyle: $input.css(\"font-style\"),\n                fontVariant: $input.css(\"font-variant\"),\n                fontWeight: $input.css(\"font-weight\"),\n                wordSpacing: $input.css(\"word-spacing\"),\n                letterSpacing: $input.css(\"letter-spacing\"),\n                textIndent: $input.css(\"text-indent\"),\n                textRendering: $input.css(\"text-rendering\"),\n                textTransform: $input.css(\"text-transform\")\n            }).insertAfter($input);\n        }\n        function areQueriesEquivalent(a, b) {\n            return Input.normalizeQuery(a) === Input.normalizeQuery(b);\n        }\n        function withModifier($e) {\n            return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey;\n        }\n    }();\n    var Dataset = function() {\n        var datasetKey = \"ttDataset\", valueKey = \"ttValue\", datumKey = \"ttDatum\";\n        function Dataset(o) {\n            o = o || {};\n            o.templates = o.templates || {};\n            if (!o.source) {\n                $.error(\"missing source\");\n            }\n            if (o.name && !isValidName(o.name)) {\n                $.error(\"invalid dataset name: \" + o.name);\n            }\n            this.query = null;\n            this.highlight = !!o.highlight;\n            this.name = o.name || _.getUniqueId();\n            this.source = o.source;\n            this.displayFn = getDisplayFn(o.display || o.displayKey);\n            this.templates = getTemplates(o.templates, this.displayFn);\n            this.$el = $(html.dataset.replace(\"%CLASS%\", this.name));\n        }\n        Dataset.extractDatasetName = function extractDatasetName(el) {\n            return $(el).data(datasetKey);\n        };\n        Dataset.extractValue = function extractDatum(el) {\n            return $(el).data(valueKey);\n        };\n        Dataset.extractDatum = function extractDatum(el) {\n            return $(el).data(datumKey);\n        };\n        _.mixin(Dataset.prototype, EventEmitter, {\n            _render: function render(query, suggestions) {\n                if (!this.$el) {\n                    return;\n                }\n                var that = this, hasSuggestions;\n                this.$el.empty();\n                hasSuggestions = suggestions && suggestions.length;\n                if (!hasSuggestions && this.templates.empty) {\n                    this.$el.html(getEmptyHtml()).prepend(that.templates.header ? getHeaderHtml() : null).append(that.templates.footer ? getFooterHtml() : null);\n                } else if (hasSuggestions) {\n                    this.$el.html(getSuggestionsHtml()).prepend(that.templates.header ? getHeaderHtml() : null).append(that.templates.footer ? getFooterHtml() : null);\n                }\n                this.trigger(\"rendered\");\n                function getEmptyHtml() {\n                    return that.templates.empty({\n                        query: query,\n                        isEmpty: true\n                    });\n                }\n                function getSuggestionsHtml() {\n                    var $suggestions, nodes;\n                    $suggestions = $(html.suggestions).css(css.suggestions);\n                    nodes = _.map(suggestions, getSuggestionNode);\n                    $suggestions.append.apply($suggestions, nodes);\n                    that.highlight && highlight({\n                        node: $suggestions[0],\n                        pattern: query\n                    });\n                    return $suggestions;\n                    function getSuggestionNode(suggestion) {\n                        var $el;\n                        $el = $(html.suggestion).append(that.templates.suggestion(suggestion)).data(datasetKey, that.name).data(valueKey, that.displayFn(suggestion)).data(datumKey, suggestion);\n                        $el.children().each(function() {\n                            $(this).css(css.suggestionChild);\n                        });\n                        return $el;\n                    }\n                }\n                function getHeaderHtml() {\n                    return that.templates.header({\n                        query: query,\n                        isEmpty: !hasSuggestions\n                    });\n                }\n                function getFooterHtml() {\n                    return that.templates.footer({\n                        query: query,\n                        isEmpty: !hasSuggestions\n                    });\n                }\n            },\n            getRoot: function getRoot() {\n                return this.$el;\n            },\n            update: function update(query) {\n                var that = this;\n                this.query = query;\n                this.canceled = false;\n                this.source(query, render);\n                function render(suggestions) {\n                    if (!that.canceled && query === that.query) {\n                        that._render(query, suggestions);\n                    }\n                }\n            },\n            cancel: function cancel() {\n                this.canceled = true;\n            },\n            clear: function clear() {\n                this.cancel();\n                this.$el.empty();\n                this.trigger(\"rendered\");\n            },\n            isEmpty: function isEmpty() {\n                return this.$el.is(\":empty\");\n            },\n            destroy: function destroy() {\n                this.$el = null;\n            }\n        });\n        return Dataset;\n        function getDisplayFn(display) {\n            display = display || \"value\";\n            return _.isFunction(display) ? display : displayFn;\n            function displayFn(obj) {\n                return obj[display];\n            }\n        }\n        function getTemplates(templates, displayFn) {\n            return {\n                empty: templates.empty && _.templatify(templates.empty),\n                header: templates.header && _.templatify(templates.header),\n                footer: templates.footer && _.templatify(templates.footer),\n                suggestion: templates.suggestion || suggestionTemplate\n            };\n            function suggestionTemplate(context) {\n                return \"<p>\" + displayFn(context) + \"</p>\";\n            }\n        }\n        function isValidName(str) {\n            return /^[_a-zA-Z0-9-]+$/.test(str);\n        }\n    }();\n    var Dropdown = function() {\n        function Dropdown(o) {\n            var that = this, onSuggestionClick, onSuggestionMouseEnter, onSuggestionMouseLeave;\n            o = o || {};\n            if (!o.menu) {\n                $.error(\"menu is required\");\n            }\n            this.isOpen = false;\n            this.isEmpty = true;\n            this.datasets = _.map(o.datasets, initializeDataset);\n            onSuggestionClick = _.bind(this._onSuggestionClick, this);\n            onSuggestionMouseEnter = _.bind(this._onSuggestionMouseEnter, this);\n            onSuggestionMouseLeave = _.bind(this._onSuggestionMouseLeave, this);\n            this.$menu = $(o.menu).on(\"click.tt\", \".tt-suggestion\", onSuggestionClick).on(\"mouseenter.tt\", \".tt-suggestion\", onSuggestionMouseEnter).on(\"mouseleave.tt\", \".tt-suggestion\", onSuggestionMouseLeave);\n            _.each(this.datasets, function(dataset) {\n                that.$menu.append(dataset.getRoot());\n                dataset.onSync(\"rendered\", that._onRendered, that);\n            });\n        }\n        _.mixin(Dropdown.prototype, EventEmitter, {\n            _onSuggestionClick: function onSuggestionClick($e) {\n                this.trigger(\"suggestionClicked\", $($e.currentTarget));\n            },\n            _onSuggestionMouseEnter: function onSuggestionMouseEnter($e) {\n                this._removeCursor();\n                this._setCursor($($e.currentTarget), true);\n            },\n            _onSuggestionMouseLeave: function onSuggestionMouseLeave() {\n                this._removeCursor();\n            },\n            _onRendered: function onRendered() {\n                this.isEmpty = _.every(this.datasets, isDatasetEmpty);\n                this.isEmpty ? this._hide() : this.isOpen && this._show();\n                this.trigger(\"datasetRendered\");\n                function isDatasetEmpty(dataset) {\n                    return dataset.isEmpty();\n                }\n            },\n            _hide: function() {\n                this.$menu.hide();\n            },\n            _show: function() {\n                this.$menu.css(\"display\", \"block\");\n            },\n            _getSuggestions: function getSuggestions() {\n                return this.$menu.find(\".tt-suggestion\");\n            },\n            _getCursor: function getCursor() {\n                return this.$menu.find(\".tt-cursor\").first();\n            },\n            _setCursor: function setCursor($el, silent) {\n                $el.first().addClass(\"tt-cursor\");\n                !silent && this.trigger(\"cursorMoved\");\n            },\n            _removeCursor: function removeCursor() {\n                this._getCursor().removeClass(\"tt-cursor\");\n            },\n            _moveCursor: function moveCursor(increment) {\n                var $suggestions, $oldCursor, newCursorIndex, $newCursor;\n                if (!this.isOpen) {\n                    return;\n                }\n                $oldCursor = this._getCursor();\n                $suggestions = this._getSuggestions();\n                this._removeCursor();\n                newCursorIndex = $suggestions.index($oldCursor) + increment;\n                newCursorIndex = (newCursorIndex + 1) % ($suggestions.length + 1) - 1;\n                if (newCursorIndex === -1) {\n                    this.trigger(\"cursorRemoved\");\n                    return;\n                } else if (newCursorIndex < -1) {\n                    newCursorIndex = $suggestions.length - 1;\n                }\n                this._setCursor($newCursor = $suggestions.eq(newCursorIndex));\n                this._ensureVisible($newCursor);\n            },\n            _ensureVisible: function ensureVisible($el) {\n                var elTop, elBottom, menuScrollTop, menuHeight;\n                elTop = $el.position().top;\n                elBottom = elTop + $el.outerHeight(true);\n                menuScrollTop = this.$menu.scrollTop();\n                menuHeight = this.$menu.height() + parseInt(this.$menu.css(\"paddingTop\"), 10) + parseInt(this.$menu.css(\"paddingBottom\"), 10);\n                if (elTop < 0) {\n                    this.$menu.scrollTop(menuScrollTop + elTop);\n                } else if (menuHeight < elBottom) {\n                    this.$menu.scrollTop(menuScrollTop + (elBottom - menuHeight));\n                }\n            },\n            close: function close() {\n                if (this.isOpen) {\n                    this.isOpen = false;\n                    this._removeCursor();\n                    this._hide();\n                    this.trigger(\"closed\");\n                }\n            },\n            open: function open() {\n                if (!this.isOpen) {\n                    this.isOpen = true;\n                    !this.isEmpty && this._show();\n                    this.trigger(\"opened\");\n                }\n            },\n            setLanguageDirection: function setLanguageDirection(dir) {\n                this.$menu.css(dir === \"ltr\" ? css.ltr : css.rtl);\n            },\n            moveCursorUp: function moveCursorUp() {\n                this._moveCursor(-1);\n            },\n            moveCursorDown: function moveCursorDown() {\n                this._moveCursor(+1);\n            },\n            getDatumForSuggestion: function getDatumForSuggestion($el) {\n                var datum = null;\n                if ($el.length) {\n                    datum = {\n                        raw: Dataset.extractDatum($el),\n                        value: Dataset.extractValue($el),\n                        datasetName: Dataset.extractDatasetName($el)\n                    };\n                }\n                return datum;\n            },\n            getDatumForCursor: function getDatumForCursor() {\n                return this.getDatumForSuggestion(this._getCursor().first());\n            },\n            getDatumForTopSuggestion: function getDatumForTopSuggestion() {\n                return this.getDatumForSuggestion(this._getSuggestions().first());\n            },\n            update: function update(query) {\n                _.each(this.datasets, updateDataset);\n                function updateDataset(dataset) {\n                    dataset.update(query);\n                }\n            },\n            empty: function empty() {\n                _.each(this.datasets, clearDataset);\n                this.isEmpty = true;\n                function clearDataset(dataset) {\n                    dataset.clear();\n                }\n            },\n            isVisible: function isVisible() {\n                return this.isOpen && !this.isEmpty;\n            },\n            destroy: function destroy() {\n                this.$menu.off(\".tt\");\n                this.$menu = null;\n                _.each(this.datasets, destroyDataset);\n                function destroyDataset(dataset) {\n                    dataset.destroy();\n                }\n            }\n        });\n        return Dropdown;\n        function initializeDataset(oDataset) {\n            return new Dataset(oDataset);\n        }\n    }();\n    var Typeahead = function() {\n        var attrsKey = \"ttAttrs\";\n        function Typeahead(o) {\n            var $menu, $input, $hint;\n            o = o || {};\n            if (!o.input) {\n                $.error(\"missing input\");\n            }\n            this.isActivated = false;\n            this.autoselect = !!o.autoselect;\n            this.minLength = _.isNumber(o.minLength) ? o.minLength : 1;\n            this.$node = buildDomStructure(o.input, o.withHint);\n            $menu = this.$node.find(\".tt-dropdown-menu\");\n            $input = this.$node.find(\".tt-input\");\n            $hint = this.$node.find(\".tt-hint\");\n            $input.on(\"blur.tt\", function($e) {\n                var active, isActive, hasActive;\n                active = document.activeElement;\n                isActive = $menu.is(active);\n                hasActive = $menu.has(active).length > 0;\n                if (_.isMsie() && (isActive || hasActive)) {\n                    $e.preventDefault();\n                    $e.stopImmediatePropagation();\n                    _.defer(function() {\n                        $input.focus();\n                    });\n                }\n            });\n            $menu.on(\"mousedown.tt\", function($e) {\n                $e.preventDefault();\n            });\n            this.eventBus = o.eventBus || new EventBus({\n                el: $input\n            });\n            this.dropdown = new Dropdown({\n                menu: $menu,\n                datasets: o.datasets\n            }).onSync(\"suggestionClicked\", this._onSuggestionClicked, this).onSync(\"cursorMoved\", this._onCursorMoved, this).onSync(\"cursorRemoved\", this._onCursorRemoved, this).onSync(\"opened\", this._onOpened, this).onSync(\"closed\", this._onClosed, this).onAsync(\"datasetRendered\", this._onDatasetRendered, this);\n            this.input = new Input({\n                input: $input,\n                hint: $hint\n            }).onSync(\"focused\", this._onFocused, this).onSync(\"blurred\", this._onBlurred, this).onSync(\"enterKeyed\", this._onEnterKeyed, this).onSync(\"tabKeyed\", this._onTabKeyed, this).onSync(\"escKeyed\", this._onEscKeyed, this).onSync(\"upKeyed\", this._onUpKeyed, this).onSync(\"downKeyed\", this._onDownKeyed, this).onSync(\"leftKeyed\", this._onLeftKeyed, this).onSync(\"rightKeyed\", this._onRightKeyed, this).onSync(\"queryChanged\", this._onQueryChanged, this).onSync(\"whitespaceChanged\", this._onWhitespaceChanged, this);\n            this._setLanguageDirection();\n        }\n        _.mixin(Typeahead.prototype, {\n            _onSuggestionClicked: function onSuggestionClicked(type, $el) {\n                var datum;\n                if (datum = this.dropdown.getDatumForSuggestion($el)) {\n                    this._select(datum);\n                }\n            },\n            _onCursorMoved: function onCursorMoved() {\n                var datum = this.dropdown.getDatumForCursor();\n                this.input.setInputValue(datum.value, true);\n                this.eventBus.trigger(\"cursorchanged\", datum.raw, datum.datasetName);\n            },\n            _onCursorRemoved: function onCursorRemoved() {\n                this.input.resetInputValue();\n                this._updateHint();\n            },\n            _onDatasetRendered: function onDatasetRendered() {\n                this._updateHint();\n            },\n            _onOpened: function onOpened() {\n                this._updateHint();\n                this.eventBus.trigger(\"opened\");\n            },\n            _onClosed: function onClosed() {\n                this.input.clearHint();\n                this.eventBus.trigger(\"closed\");\n            },\n            _onFocused: function onFocused() {\n                this.isActivated = true;\n                this.dropdown.open();\n            },\n            _onBlurred: function onBlurred() {\n                this.isActivated = false;\n                this.dropdown.empty();\n                this.dropdown.close();\n                this.setVal(\"\", true); //LM\n            },\n            _onEnterKeyed: function onEnterKeyed(type, $e) {\n                var cursorDatum, topSuggestionDatum;\n                cursorDatum = this.dropdown.getDatumForCursor();\n                topSuggestionDatum = this.dropdown.getDatumForTopSuggestion();\n                if (cursorDatum) {\n                    this._select(cursorDatum);\n                    $e.preventDefault();\n                } else if (this.autoselect && topSuggestionDatum) {\n                    this._select(topSuggestionDatum);\n                    $e.preventDefault();\n                }\n            },\n            _onTabKeyed: function onTabKeyed(type, $e) {\n                var datum;\n                if (datum = this.dropdown.getDatumForCursor()) {\n                    this._select(datum);\n                    $e.preventDefault();\n                } else {\n                    this._autocomplete(true);\n                }\n            },\n            _onEscKeyed: function onEscKeyed() {\n                this.dropdown.close();\n                this.input.resetInputValue();\n            },\n            _onUpKeyed: function onUpKeyed() {\n                var query = this.input.getQuery();\n                this.dropdown.isEmpty && query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.moveCursorUp();\n                this.dropdown.open();\n            },\n            _onDownKeyed: function onDownKeyed() {\n                var query = this.input.getQuery();\n                this.dropdown.isEmpty && query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.moveCursorDown();\n                this.dropdown.open();\n            },\n            _onLeftKeyed: function onLeftKeyed() {\n                this.dir === \"rtl\" && this._autocomplete();\n            },\n            _onRightKeyed: function onRightKeyed() {\n                this.dir === \"ltr\" && this._autocomplete();\n            },\n            _onQueryChanged: function onQueryChanged(e, query) {\n                this.input.clearHintIfInvalid();\n                query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.empty();\n                this.dropdown.open();\n                this._setLanguageDirection();\n            },\n            _onWhitespaceChanged: function onWhitespaceChanged() {\n                this._updateHint();\n                this.dropdown.open();\n            },\n            _setLanguageDirection: function setLanguageDirection() {\n                var dir;\n                if (this.dir !== (dir = this.input.getLanguageDirection())) {\n                    this.dir = dir;\n                    this.$node.css(\"direction\", dir);\n                    this.dropdown.setLanguageDirection(dir);\n                }\n            },\n            _updateHint: function updateHint() {\n                var datum, val, query, escapedQuery, frontMatchRegEx, match;\n                datum = this.dropdown.getDatumForTopSuggestion();\n                if (datum && this.dropdown.isVisible() && !this.input.hasOverflow()) {\n                    val = this.input.getInputValue();\n                    query = Input.normalizeQuery(val);\n                    escapedQuery = _.escapeRegExChars(query);\n                    frontMatchRegEx = new RegExp(\"^(?:\" + escapedQuery + \")(.+$)\", \"i\");\n                    match = frontMatchRegEx.exec(datum.value);\n                    match ? this.input.setHint(val + match[1]) : this.input.clearHint();\n                } else {\n                    this.input.clearHint();\n                }\n            },\n            _autocomplete: function autocomplete(laxCursor) {\n                var hint, query, isCursorAtEnd, datum;\n                hint = this.input.getHint();\n                query = this.input.getQuery();\n                isCursorAtEnd = laxCursor || this.input.isCursorAtEnd();\n                if (hint && query !== hint && isCursorAtEnd) {\n                    datum = this.dropdown.getDatumForTopSuggestion();\n                    datum && this.input.setInputValue(datum.value);\n                    this.eventBus.trigger(\"autocompleted\", datum.raw, datum.datasetName);\n                }\n            },\n            _select: function select(datum) {\n                this.input.setQuery(datum.value);\n                this.input.setInputValue(datum.value, true);\n                this._setLanguageDirection();\n                this.eventBus.trigger(\"selected\", datum.raw, datum.datasetName);\n                this.dropdown.close();\n                _.defer(_.bind(this.dropdown.empty, this.dropdown));\n            },\n            open: function open() {\n                this.dropdown.open();\n            },\n            close: function close() {\n                this.dropdown.close();\n            },\n            setVal: function setVal(val) {\n                if (this.isActivated) {\n                    this.input.setInputValue(val);\n                } else {\n                    this.input.setQuery(val);\n                    this.input.setInputValue(val, true);\n                }\n                this._setLanguageDirection();\n            },\n            getVal: function getVal() {\n                return this.input.getQuery();\n            },\n            destroy: function destroy() {\n                this.input.destroy();\n                this.dropdown.destroy();\n                destroyDomStructure(this.$node);\n                this.$node = null;\n            }\n        });\n        return Typeahead;\n        function buildDomStructure(input, withHint) {\n            var $input, $wrapper, $dropdown, $hint;\n            $input = $(input);\n            $wrapper = $(html.wrapper).css(css.wrapper);\n            $dropdown = $(html.dropdown).css(css.dropdown);\n            $hint = $input.clone().css(css.hint).css(getBackgroundStyles($input));\n            $hint.val(\"\").removeData().addClass(\"tt-hint\").removeAttr(\"id name placeholder\").prop(\"disabled\", true).attr({\n                autocomplete: \"off\",\n                spellcheck: \"false\"\n            });\n            $input.data(attrsKey, {\n                dir: $input.attr(\"dir\"),\n                autocomplete: $input.attr(\"autocomplete\"),\n                spellcheck: $input.attr(\"spellcheck\"),\n                style: $input.attr(\"style\")\n            });\n            $input.addClass(\"tt-input\").attr({\n                autocomplete: \"off\",\n                spellcheck: false\n            }).css(withHint ? css.input : css.inputWithNoHint);\n            try {\n                !$input.attr(\"dir\") && $input.attr(\"dir\", \"auto\");\n            } catch (e) {}\n            return $input.wrap($wrapper).parent().prepend(withHint ? $hint : null).append($dropdown);\n        }\n        function getBackgroundStyles($el) {\n            return {\n                backgroundAttachment: $el.css(\"background-attachment\"),\n                backgroundClip: $el.css(\"background-clip\"),\n                backgroundColor: $el.css(\"background-color\"),\n                backgroundImage: $el.css(\"background-image\"),\n                backgroundOrigin: $el.css(\"background-origin\"),\n                backgroundPosition: $el.css(\"background-position\"),\n                backgroundRepeat: $el.css(\"background-repeat\"),\n                backgroundSize: $el.css(\"background-size\")\n            };\n        }\n        function destroyDomStructure($node) {\n            var $input = $node.find(\".tt-input\");\n            _.each($input.data(attrsKey), function(val, key) {\n                _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val);\n            });\n            $input.detach().removeData(attrsKey).removeClass(\"tt-input\").insertAfter($node);\n            $node.remove();\n        }\n    }();\n    (function() {\n        var old, typeaheadKey, methods;\n        old = $.fn.typeahead;\n        typeaheadKey = \"ttTypeahead\";\n        methods = {\n            initialize: function initialize(o, datasets) {\n                datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1);\n                o = o || {};\n                return this.each(attach);\n                function attach() {\n                    var $input = $(this), eventBus, typeahead;\n                    _.each(datasets, function(d) {\n                        d.highlight = !!o.highlight;\n                    });\n                    typeahead = new Typeahead({\n                        input: $input,\n                        eventBus: eventBus = new EventBus({\n                            el: $input\n                        }),\n                        withHint: _.isUndefined(o.hint) ? true : !!o.hint,\n                        minLength: o.minLength,\n                        autoselect: o.autoselect,\n                        datasets: datasets\n                    });\n                    $input.data(typeaheadKey, typeahead);\n                }\n            },\n            open: function open() {\n                return this.each(openTypeahead);\n                function openTypeahead() {\n                    var $input = $(this), typeahead;\n                    if (typeahead = $input.data(typeaheadKey)) {\n                        typeahead.open();\n                    }\n                }\n            },\n            close: function close() {\n                return this.each(closeTypeahead);\n                function closeTypeahead() {\n                    var $input = $(this), typeahead;\n                    if (typeahead = $input.data(typeaheadKey)) {\n                        typeahead.close();\n                    }\n                }\n            },\n            val: function val(newVal) {\n                return !arguments.length ? getVal(this.first()) : this.each(setVal);\n                function setVal() {\n                    var $input = $(this), typeahead;\n                    if (typeahead = $input.data(typeaheadKey)) {\n                        typeahead.setVal(newVal);\n                    }\n                }\n                function getVal($input) {\n                    var typeahead, query;\n                    if (typeahead = $input.data(typeaheadKey)) {\n                        query = typeahead.getVal();\n                    }\n                    return query;\n                }\n            },\n            destroy: function destroy() {\n                return this.each(unattach);\n                function unattach() {\n                    var $input = $(this), typeahead;\n                    if (typeahead = $input.data(typeaheadKey)) {\n                        typeahead.destroy();\n                        $input.removeData(typeaheadKey);\n                    }\n                }\n            }\n        };\n        $.fn.typeahead = function(method) {\n            if (methods[method]) {\n                return methods[method].apply(this, [].slice.call(arguments, 1));\n            } else {\n                return methods.initialize.apply(this, arguments);\n            }\n        };\n        $.fn.typeahead.noConflict = function noConflict() {\n            $.fn.typeahead = old;\n            return this;\n        };\n    })();\n    \n    \n    \n//})(window.jQuery);\n\n\n});\n",
        +    "define('searchView',[\n  'App',\n  // Templates\n  'text!tpl/search.html',\n  'text!tpl/search_suggestion.html',\n  // Tools\n  'typeahead'\n], function(App, searchTpl, suggestionTpl) {\n\n  var searchView = Backbone.View.extend({\n    el: '#search',\n    /**\n     * Init.\n     */\n    init: function() {\n      var tpl = _.template(searchTpl);\n      var className = 'form-control input-lg';\n      var placeholder = 'Search reference';\n      this.searchHtml = tpl({\n        'placeholder': placeholder,\n        'className': className\n      });\n      this.items = App.classes.concat(App.allItems);\n\n      return this;\n    },\n    /**\n     * Render input field with Typehead activated.\n     */\n    render: function() {\n      // Append the view to the dom\n      this.$el.append(this.searchHtml);\n\n      // Render Typeahead\n      var $searchInput = this.$el.find('input[type=text]');\n      this.typeaheadRender($searchInput);\n      this.typeaheadEvents($searchInput);\n\n      return this;\n    },\n    /**\n     * Apply Twitter Typeahead to the search input field.\n     * @param {jquery} $input\n     */\n    typeaheadRender: function($input) {\n      var self = this;\n      $input.typeahead(null, {\n        'displayKey': 'name',\n        'minLength': 2,\n        //'highlight': true,\n        'source': self.substringMatcher(this.items),\n        'templates': {\n          'empty': '<p class=\"empty-message\">Unable to find any item that match the current query</p>',\n          'suggestion': _.template(suggestionTpl)\n        }\n      });\n    },\n    /**\n     * Setup typeahead custom events (item selected).\n     */\n    typeaheadEvents: function($input) {\n      var self = this;\n      $input.on('typeahead:selected', function(e, item, datasetName) {\n        var selectedItem = self.items[item.idx];\n        select(selectedItem);\n      });\n      $input.on('keydown', function(e) {\n        if (e.which === 13) { // enter\n          var txt = $input.val();\n          var f = _.find(self.items, function(it) { return it.name == txt; });\n          if (f) {\n            select(f);\n          }\n        } else if (e.which === 27) {\n          $input.blur();\n        }\n      });\n\n      function select(selectedItem) {\n        var hash = App.router.getHash(selectedItem);//\n        App.router.navigate(hash, {'trigger': true});\n        $('#item').focus();\n      }\n    },\n    /**\n     * substringMatcher function for Typehead (search for strings in an array).\n     * @param {array} array\n     * @returns {Function}\n     */\n    substringMatcher: function(array) {\n      return function findMatches(query, callback) {\n        var matches = [], substrRegex, arrayLength = array.length;\n\n        // regex used to determine if a string contains the substring `query`\n        substrRegex = new RegExp(query, 'i');\n\n        // iterate through the pool of strings and for any string that\n        // contains the substring `query`, add it to the `matches` array\n        for (var i=0; i < arrayLength; i++) {\n          var item = array[i];\n          if (substrRegex.test(item.name)) {\n            // typeahead expects suggestions to be a js object\n            matches.push({\n              'itemtype': item.itemtype,\n              'name': item.name,\n              'className': item.class,\n              'is_constructor': !!item.is_constructor,\n              'final': item.final,\n              'idx': i\n            });\n          }\n        }\n\n        callback(matches);\n      };\n    }\n\n  });\n\n  return searchView;\n\n});\n\n",
        +    "\ndefine('text!tpl/list.html',[],function () { return '<% _.each(groups, function(group){ %>\\n  <div class=\"reference-group clearfix main-ref-page\">  \\n    <h2 class=\"group-name\" id=\"group-<%=group.name%>\" tab-index=\"-1\"><%=group.name%></h2>\\n    <div class=\"reference-subgroups clearfix main-ref-page\">  \\n    <% _.each(group.subgroups, function(subgroup, ind) { %>\\n      <div class=\"reference-subgroup\">\\n        <% if (subgroup.name !== \\'0\\') { %>\\n          <h3 id=\"<%=group.name%><%=ind%>\" class=\"subgroup-name subgroup-<%=subgroup.name%>\"><%=subgroup.name%></h3>\\n        <% } %>\\n        <ul aria-labelledby=\"<%=group.name%> <%=ind%>\">\\n        <% _.each(subgroup.items, function(item) { %>\\n        <li><a href=\"<%=item.hash%>\"><%=item.name%><% if (item.itemtype === \\'method\\') { %>()<%}%></a></li>\\n        <% }); %>\\n        </ul>\\n      </div>\\n    <% }); %>\\n    </div>\\n  </div>\\n<% }); %>\\n';});\n\n",
        +    "define('listView',[\n  'App',\n  // Templates\n  'text!tpl/list.html'\n], function (App, listTpl) {\n  var striptags = function(html) {\n    var div = document.createElement('div');\n    div.innerHTML = html;\n    return div.textContent;\n  };\n\n  var listView = Backbone.View.extend({\n    el: '#list',\n    events: {},\n    /**\n     * Init.\n     */\n    init: function () {\n      this.listTpl = _.template(listTpl);\n\n      return this;\n    },\n    /**\n     * Render the list.\n     */\n    render: function (items, listCollection) {\n      if (items && listCollection) {\n        var self = this;\n\n        // Render items and group them by module\n        // module === group\n        this.groups = {};\n        _.each(items, function (item, i) {\n\n          if (!item.private && item.file.indexOf('addons') === -1) { //addons don't get displayed on main page\n\n            var group = item.module || '_';\n            var subgroup = item.submodule || '_';\n            if (group === subgroup) {\n              subgroup = '0';\n            }\n            var hash = App.router.getHash(item);\n\n            // fixes broken links for #/p5/> and #/p5/>=\n            item.hash = item.hash.replace('>', '&gt;');\n\n            // Create a group list\n            if (!self.groups[group]) {\n              self.groups[group] = {\n                name: group.replace('_', '&nbsp;'),\n                subgroups: {}\n              };\n            }\n\n            // Create a subgroup list\n            if (!self.groups[group].subgroups[subgroup]) {\n              self.groups[group].subgroups[subgroup] = {\n                name: subgroup.replace('_', '&nbsp;'),\n                items: []\n              };\n            }\n\n            // hide the un-interesting constants\n            if (group === 'Constants' && !item.example)\n              return;\n\n            if (item.class === 'p5') {\n\n              self.groups[group].subgroups[subgroup].items.push(item);\n\n            } else {\n\n              var found = _.find(self.groups[group].subgroups[subgroup].items,\n                function(i){ return i.name == item.class; });\n\n              if (!found) {\n\n                // FIX TO INVISIBLE OBJECTS: DH (see also router.js)\n                var ind = hash.lastIndexOf('/');\n                hash = item.hash.substring(0, ind).replace('p5/','p5.');\n                self.groups[group].subgroups[subgroup].items.push({\n                  name: item.class,\n                  hash: hash\n                });\n              }\n\n            }\n          }\n        });\n\n        // Put the <li> items html into the list <ul>\n        var listHtml = self.listTpl({\n          'striptags': striptags,\n          'title': self.capitalizeFirst(listCollection),\n          'groups': self.groups,\n          'listCollection': listCollection\n        });\n\n        // Render the view\n        this.$el.html(listHtml);\n      }\n\n      var renderEvent = new Event('reference-rendered');\n      window.dispatchEvent(renderEvent);\n\n      return this;\n    },\n    /**\n     * Show a list of items.\n     * @param {array} items Array of item objects.\n     * @returns {object} This view.\n     */\n    show: function (listGroup) {\n      if (App[listGroup]) {\n        this.render(App[listGroup], listGroup);\n      }\n      App.pageView.hideContentViews();\n\n      this.$el.show();\n\n      return this;\n    },\n    /**\n     * Helper method to capitalize the first letter of a string\n     * @param {string} str\n     * @returns {string} Returns the string.\n     */\n    capitalizeFirst: function (str) {\n      return str.substr(0, 1).toUpperCase() + str.substr(1);\n    }\n\n\n\n  });\n\n  return listView;\n\n});\n\n",
        +    "\ndefine('text!tpl/item.html',[],function () { return '<h2><%=item.name%><% if (item.isMethod) { %>()<% } %></h2>\\n\\n<% if (item.example) { %>\\n<div class=\"example\">\\n  <h3 id=\"reference-example\">Examples</h3>\\n\\n  <div class=\"example-content\" data-alt=\"<%= item.alt %>\">\\n    <% _.each(item.example, function(example, i){ %>\\n      <%= example %>\\n    <% }); %>\\n  </div>\\n</div>\\n<% } %>\\n\\n<div class=\"description\">\\n    \\n  <h3 id=\"reference-description\">Description</h3>\\n\\n  <% if (item.deprecated) { %>\\n    <p>\\n      Deprecated: <%=item.name%><% if (item.isMethod) { %>()<% } %> is deprecated and will be removed in a future version of p5. <% if (item.deprecationMessage) { %><%=item.deprecationMessage%><% } %>\\n    </p>\\n  <% } %>\\n      \\n\\n  <span class=\\'description-text\\'><%= item.description %></span>\\n\\n  <% if (item.extends) { %>\\n    <p><span id=\"reference-extends\">Extends</span> <a href=\"/reference/#/<%=item.extends%>\" title=\"<%=item.extends%> reference\"><%=item.extends%></a></p>\\n  <% } %>\\n\\n  <% if (item.module === \\'p5.sound\\') { %>\\n    <p>This function requires you include the p5.sound library.  Add the following into the head of your index.html file:\\n      <pre><code class=\"language-javascript\">&lt;script src=\"path/to/p5.sound.js\"&gt;&lt;/script&gt;</code></pre>\\n    </p>\\n  <% } %>\\n\\n  <% if (item.constRefs) { %>\\n    <p>Used by:\\n  <%\\n      var refs = item.constRefs;\\n      for (var i = 0; i < refs.length; i ++) {\\n        var ref = refs[i];\\n        var name = ref;\\n        if (name.substr(0, 3) === \\'p5.\\') {\\n          name = name.substr(3);\\n        }\\n  if (i !== 0) {\\n          if (i == refs.length - 1) {\\n            %> and <%\\n          } else {\\n            %>, <%\\n          }\\n        }\\n        %><a href=\"./#/<%= ref.replace(\\'.\\', \\'/\\') %>\"><%= name %>()</a><%\\n      }\\n  %>\\n    </p>\\n  <% } %>\\n</div>\\n\\n<% if (isConstructor || !isClass) { %>\\n\\n<div>\\n  <h3 id=\"reference-syntax\">Syntax</h3>\\n  <p>\\n    <% syntaxes.forEach(function(syntax) { %>\\n    <pre><code class=\"language-javascript\"><%= syntax %></code></pre>\\n    <% }) %>\\n  </p>\\n</div>\\n\\n\\n<% if (item.params) { %>\\n  <div class=\"params\">\\n    <h3 id=\"reference-parameters\">Parameters</h3>\\n    <ul aria-labelledby=\\'reference-parameters\\'>\\n    <% for (var i=0; i<item.params.length; i++) { %>\\n      <% var p = item.params[i] %>\\n      <li>\\n        <div class=\\'paramname\\'><%=p.name%></div>\\n        <% if (p.type) { %>\\n          <div class=\\'paramtype\\'>\\n          <% var type = p.type.replace(/(p5\\\\.[A-Z][A-Za-z]*)/, \\'<a href=\"#/$1\">$1</a>\\'); %>\\n          <span class=\"param-type label label-info\"><%=type%></span>: <%=p.description%>\\n          <% if (p.optional) { %> (Optional)<% } %>\\n          </div>\\n        <% } %>\\n      </li>\\n    <% } %>\\n    </ul>\\n  </div>\\n<% } %>\\n\\n<% if (item.return && item.return.type) { %>\\n  <div>\\n    <h3 id=\"reference-returns\">Returns</h3>\\n    <p class=\\'returns\\'><span class=\"param-type label label-info\"><%=item.return.type%></span>: <%= item.return.description %></p>\\n  </div>\\n<% } %>\\n\\n<% } %>\\n';});\n\n",
        +    "\ndefine('text!tpl/class.html',[],function () { return '\\n<% if (typeof constructor !== \\'undefined\\') { %>\\n<div class=\"constructor\">\\n  <%=constructor%>\\n</div>\\n<% } %>\\n\\n<% let fields = _.filter(things, function(item) { return item.itemtype === \\'property\\' && item.access !== \\'private\\' }); %>\\n<% if (fields.length > 0) { %>\\n  <h3 id=\\'reference-fields\\'>Fields</h3>\\n  <ul aria-labelledby=\\'reference-fields\\'>\\n  <% _.each(fields, function(item) { %>\\n    <li>\\n      <div class=\\'paramname\\'><a href=\"<%=item.hash%>\" <% if (item.module !== module) { %>class=\"addon\"<% } %>><%=item.name%></a></div>\\n      <div class=\\'paramtype\\'><%= item.description %></div>\\n    </li>\\n  <% }); %>\\n  </ul>\\n<% } %>\\n\\n<% let methods = _.filter(things, function(item) { return item.itemtype === \\'method\\' && item.access !== \\'private\\' }); %>\\n<% if (methods.length > 0) { %>\\n  <h3 id=\\'reference-methods\\'>Methods</h3>\\n  <ul aria-labelledby=\\'reference-methods\\'>\\n    <% _.each(methods, function(item) { %>\\n      <li>\\n        <div class=\\'paramname\\'><a href=\"<%=item.hash%>\" <% if (item.module !== module) { %>class=\"addon\"<% } %>><%=item.name%><% if (item.itemtype === \\'method\\') { %>()<%}%></a></div>\\n        <div class=\\'paramtype\\'><%= item.description %></div>\\n      </li>\\n    <% }); %>\\n  </ul>\\n<% } %>\\n';});\n\n",
        +    "\ndefine('text!tpl/itemEnd.html',[],function () { return '\\n<br><br>\\n\\n<div>\\n<% if (item.file && item.line) { %>\\n<span id=\"reference-error1\">Notice any errors or typos?</span> <a href=\"https://github.com/processing/p5.js/issues\"><span id=\"reference-contribute2\">Please let us know.</span></a> <span id=\"reference-error3\">Please feel free to edit</span> <a href=\"https://github.com/processing/p5.js/blob/<%= appVersion %>/<%= item.file %>#L<%= item.line %>\" target=\"_blank\" ><%= item.file %></a> <span id=\"reference-error5\">and issue a pull request!</span>\\n<% } %>\\n</div>\\n\\n<a style=\"border-bottom:none !important;\" href=\"http://creativecommons.org/licenses/by-nc-sa/4.0/\" target=_blank><img src=\"https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png\" style=\"width:88px\" alt=\"creative commons logo\"/></a>\\n<br><br>\\n';});\n\n",
        +    "// Copyright (C) 2006 Google Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n\n/**\n * @fileoverview\n * some functions for browser-side pretty printing of code contained in html.\n *\n * <p>\n * For a fairly comprehensive set of languages see the\n * <a href=\"http://google-code-prettify.googlecode.com/svn/trunk/README.html#langs\">README</a>\n * file that came with this source.  At a minimum, the lexer should work on a\n * number of languages including C and friends, Java, Python, Bash, SQL, HTML,\n * XML, CSS, Javascript, and Makefiles.  It works passably on Ruby, PHP and Awk\n * and a subset of Perl, but, because of commenting conventions, doesn't work on\n * Smalltalk, Lisp-like, or CAML-like languages without an explicit lang class.\n * <p>\n * Usage: <ol>\n * <li> include this source file in an html page via\n *   {@code <script src=\"/path/to/prettify.js\"></script>}\n * <li> define style rules.  See the example page for examples.\n * <li> mark the {@code <pre>} and {@code <code>} tags in your source with\n *    {@code class=prettyprint.}\n *    You can also use the (html deprecated) {@code <xmp>} tag, but the pretty\n *    printer needs to do more substantial DOM manipulations to support that, so\n *    some css styles may not be preserved.\n * </ol>\n * That's it.  I wanted to keep the API as simple as possible, so there's no\n * need to specify which language the code is in, but if you wish, you can add\n * another class to the {@code <pre>} or {@code <code>} element to specify the\n * language, as in {@code <pre class=\"prettyprint lang-java\">}.  Any class that\n * starts with \"lang-\" followed by a file extension, specifies the file type.\n * See the \"lang-*.js\" files in this directory for code that implements\n * per-language file handlers.\n * <p>\n * Change log:<br>\n * cbeust, 2006/08/22\n * <blockquote>\n *   Java annotations (start with \"@\") are now captured as literals (\"lit\")\n * </blockquote>\n * @requires console\n */\n\n// JSLint declarations\n/*global console, document, navigator, setTimeout, window, define */\n\n/** @define {boolean} */\nvar IN_GLOBAL_SCOPE = true;\n\n/**\n * Split {@code prettyPrint} into multiple timeouts so as not to interfere with\n * UI events.\n * If set to {@code false}, {@code prettyPrint()} is synchronous.\n */\nwindow['PR_SHOULD_USE_CONTINUATION'] = true;\n\n/**\n * Pretty print a chunk of code.\n * @param {string} sourceCodeHtml The HTML to pretty print.\n * @param {string} opt_langExtension The language name to use.\n *     Typically, a filename extension like 'cpp' or 'java'.\n * @param {number|boolean} opt_numberLines True to number lines,\n *     or the 1-indexed number of the first line in sourceCodeHtml.\n * @return {string} code as html, but prettier\n */\nvar prettyPrintOne;\n/**\n * Find all the {@code <pre>} and {@code <code>} tags in the DOM with\n * {@code class=prettyprint} and prettify them.\n *\n * @param {Function} opt_whenDone called when prettifying is done.\n * @param {HTMLElement|HTMLDocument} opt_root an element or document\n *   containing all the elements to pretty print.\n *   Defaults to {@code document.body}.\n */\nvar prettyPrint;\n\n\n(function () {\n  var win = window;\n  // Keyword lists for various languages.\n  // We use things that coerce to strings to make them compact when minified\n  // and to defeat aggressive optimizers that fold large string constants.\n  var FLOW_CONTROL_KEYWORDS = [\"break,continue,do,else,for,if,return,while\"];\n  var C_KEYWORDS = [FLOW_CONTROL_KEYWORDS,\"auto,case,char,const,default,\" + \n      \"double,enum,extern,float,goto,inline,int,long,register,short,signed,\" +\n      \"sizeof,static,struct,switch,typedef,union,unsigned,void,volatile\"];\n  var COMMON_KEYWORDS = [C_KEYWORDS,\"catch,class,delete,false,import,\" +\n      \"new,operator,private,protected,public,this,throw,true,try,typeof\"];\n  var CPP_KEYWORDS = [COMMON_KEYWORDS,\"alignof,align_union,asm,axiom,bool,\" +\n      \"concept,concept_map,const_cast,constexpr,decltype,delegate,\" +\n      \"dynamic_cast,explicit,export,friend,generic,late_check,\" +\n      \"mutable,namespace,nullptr,property,reinterpret_cast,static_assert,\" +\n      \"static_cast,template,typeid,typename,using,virtual,where\"];\n  var JAVA_KEYWORDS = [COMMON_KEYWORDS,\n      \"abstract,assert,boolean,byte,extends,final,finally,implements,import,\" +\n      \"instanceof,interface,null,native,package,strictfp,super,synchronized,\" +\n      \"throws,transient\"];\n  var CSHARP_KEYWORDS = [JAVA_KEYWORDS,\n      \"as,base,by,checked,decimal,delegate,descending,dynamic,event,\" +\n      \"fixed,foreach,from,group,implicit,in,internal,into,is,let,\" +\n      \"lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,\" +\n      \"sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,\" +\n      \"var,virtual,where\"];\n  var COFFEE_KEYWORDS = \"all,and,by,catch,class,else,extends,false,finally,\" +\n      \"for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,\" +\n      \"throw,true,try,unless,until,when,while,yes\";\n  var JSCRIPT_KEYWORDS = [COMMON_KEYWORDS,\n      \"debugger,eval,export,function,get,null,set,undefined,var,with,\" +\n      \"Infinity,NaN\"];\n  var PERL_KEYWORDS = \"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,\" +\n      \"goto,if,import,last,local,my,next,no,our,print,package,redo,require,\" +\n      \"sub,undef,unless,until,use,wantarray,while,BEGIN,END\";\n  var PYTHON_KEYWORDS = [FLOW_CONTROL_KEYWORDS, \"and,as,assert,class,def,del,\" +\n      \"elif,except,exec,finally,from,global,import,in,is,lambda,\" +\n      \"nonlocal,not,or,pass,print,raise,try,with,yield,\" +\n      \"False,True,None\"];\n  var RUBY_KEYWORDS = [FLOW_CONTROL_KEYWORDS, \"alias,and,begin,case,class,\" +\n      \"def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,\" +\n      \"rescue,retry,self,super,then,true,undef,unless,until,when,yield,\" +\n      \"BEGIN,END\"];\n   var RUST_KEYWORDS = [FLOW_CONTROL_KEYWORDS, \"as,assert,const,copy,drop,\" +\n      \"enum,extern,fail,false,fn,impl,let,log,loop,match,mod,move,mut,priv,\" +\n      \"pub,pure,ref,self,static,struct,true,trait,type,unsafe,use\"];\n  var SH_KEYWORDS = [FLOW_CONTROL_KEYWORDS, \"case,done,elif,esac,eval,fi,\" +\n      \"function,in,local,set,then,until\"];\n  var ALL_KEYWORDS = [\n      CPP_KEYWORDS, CSHARP_KEYWORDS, JSCRIPT_KEYWORDS, PERL_KEYWORDS,\n      PYTHON_KEYWORDS, RUBY_KEYWORDS, SH_KEYWORDS];\n  var C_TYPES = /^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\\d*)\\b/;\n\n  // token style names.  correspond to css classes\n  /**\n   * token style for a string literal\n   * @const\n   */\n  var PR_STRING = 'str';\n  /**\n   * token style for a keyword\n   * @const\n   */\n  var PR_KEYWORD = 'kwd';\n  /**\n   * token style for a comment\n   * @const\n   */\n  var PR_COMMENT = 'com';\n  /**\n   * token style for a type\n   * @const\n   */\n  var PR_TYPE = 'typ';\n  /**\n   * token style for a literal value.  e.g. 1, null, true.\n   * @const\n   */\n  var PR_LITERAL = 'lit';\n  /**\n   * token style for a punctuation string.\n   * @const\n   */\n  var PR_PUNCTUATION = 'pun';\n  /**\n   * token style for plain text.\n   * @const\n   */\n  var PR_PLAIN = 'pln';\n\n  /**\n   * token style for an sgml tag.\n   * @const\n   */\n  var PR_TAG = 'tag';\n  /**\n   * token style for a markup declaration such as a DOCTYPE.\n   * @const\n   */\n  var PR_DECLARATION = 'dec';\n  /**\n   * token style for embedded source.\n   * @const\n   */\n  var PR_SOURCE = 'src';\n  /**\n   * token style for an sgml attribute name.\n   * @const\n   */\n  var PR_ATTRIB_NAME = 'atn';\n  /**\n   * token style for an sgml attribute value.\n   * @const\n   */\n  var PR_ATTRIB_VALUE = 'atv';\n\n  /**\n   * A class that indicates a section of markup that is not code, e.g. to allow\n   * embedding of line numbers within code listings.\n   * @const\n   */\n  var PR_NOCODE = 'nocode';\n\n  \n  \n  /**\n   * A set of tokens that can precede a regular expression literal in\n   * javascript\n   * http://web.archive.org/web/20070717142515/http://www.mozilla.org/js/language/js20/rationale/syntax.html\n   * has the full list, but I've removed ones that might be problematic when\n   * seen in languages that don't support regular expression literals.\n   *\n   * <p>Specifically, I've removed any keywords that can't precede a regexp\n   * literal in a syntactically legal javascript program, and I've removed the\n   * \"in\" keyword since it's not a keyword in many languages, and might be used\n   * as a count of inches.\n   *\n   * <p>The link above does not accurately describe EcmaScript rules since\n   * it fails to distinguish between (a=++/b/i) and (a++/b/i) but it works\n   * very well in practice.\n   *\n   * @private\n   * @const\n   */\n  var REGEXP_PRECEDER_PATTERN = '(?:^^\\\\.?|[+-]|[!=]=?=?|\\\\#|%=?|&&?=?|\\\\(|\\\\*=?|[+\\\\-]=|->|\\\\/=?|::?|<<?=?|>>?>?=?|,|;|\\\\?|@|\\\\[|~|{|\\\\^\\\\^?=?|\\\\|\\\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\\\s*';\n  \n  // CAVEAT: this does not properly handle the case where a regular\n  // expression immediately follows another since a regular expression may\n  // have flags for case-sensitivity and the like.  Having regexp tokens\n  // adjacent is not valid in any language I'm aware of, so I'm punting.\n  // TODO: maybe style special characters inside a regexp as punctuation.\n\n  /**\n   * Given a group of {@link RegExp}s, returns a {@code RegExp} that globally\n   * matches the union of the sets of strings matched by the input RegExp.\n   * Since it matches globally, if the input strings have a start-of-input\n   * anchor (/^.../), it is ignored for the purposes of unioning.\n   * @param {Array.<RegExp>} regexs non multiline, non-global regexs.\n   * @return {RegExp} a global regex.\n   */\n  function combinePrefixPatterns(regexs) {\n    var capturedGroupIndex = 0;\n  \n    var needToFoldCase = false;\n    var ignoreCase = false;\n    for (var i = 0, n = regexs.length; i < n; ++i) {\n      var regex = regexs[i];\n      if (regex.ignoreCase) {\n        ignoreCase = true;\n      } else if (/[a-z]/i.test(regex.source.replace(\n                     /\\\\u[0-9a-f]{4}|\\\\x[0-9a-f]{2}|\\\\[^ux]/gi, ''))) {\n        needToFoldCase = true;\n        ignoreCase = false;\n        break;\n      }\n    }\n  \n    var escapeCharToCodeUnit = {\n      'b': 8,\n      't': 9,\n      'n': 0xa,\n      'v': 0xb,\n      'f': 0xc,\n      'r': 0xd\n    };\n  \n    function decodeEscape(charsetPart) {\n      var cc0 = charsetPart.charCodeAt(0);\n      if (cc0 !== 92 /* \\\\ */) {\n        return cc0;\n      }\n      var c1 = charsetPart.charAt(1);\n      cc0 = escapeCharToCodeUnit[c1];\n      if (cc0) {\n        return cc0;\n      } else if ('0' <= c1 && c1 <= '7') {\n        return parseInt(charsetPart.substring(1), 8);\n      } else if (c1 === 'u' || c1 === 'x') {\n        return parseInt(charsetPart.substring(2), 16);\n      } else {\n        return charsetPart.charCodeAt(1);\n      }\n    }\n  \n    function encodeEscape(charCode) {\n      if (charCode < 0x20) {\n        return (charCode < 0x10 ? '\\\\x0' : '\\\\x') + charCode.toString(16);\n      }\n      var ch = String.fromCharCode(charCode);\n      return (ch === '\\\\' || ch === '-' || ch === ']' || ch === '^')\n          ? \"\\\\\" + ch : ch;\n    }\n  \n    function caseFoldCharset(charSet) {\n      var charsetParts = charSet.substring(1, charSet.length - 1).match(\n          new RegExp(\n              '\\\\\\\\u[0-9A-Fa-f]{4}'\n              + '|\\\\\\\\x[0-9A-Fa-f]{2}'\n              + '|\\\\\\\\[0-3][0-7]{0,2}'\n              + '|\\\\\\\\[0-7]{1,2}'\n              + '|\\\\\\\\[\\\\s\\\\S]'\n              + '|-'\n              + '|[^-\\\\\\\\]',\n              'g'));\n      var ranges = [];\n      var inverse = charsetParts[0] === '^';\n  \n      var out = ['['];\n      if (inverse) { out.push('^'); }\n  \n      for (var i = inverse ? 1 : 0, n = charsetParts.length; i < n; ++i) {\n        var p = charsetParts[i];\n        if (/\\\\[bdsw]/i.test(p)) {  // Don't muck with named groups.\n          out.push(p);\n        } else {\n          var start = decodeEscape(p);\n          var end;\n          if (i + 2 < n && '-' === charsetParts[i + 1]) {\n            end = decodeEscape(charsetParts[i + 2]);\n            i += 2;\n          } else {\n            end = start;\n          }\n          ranges.push([start, end]);\n          // If the range might intersect letters, then expand it.\n          // This case handling is too simplistic.\n          // It does not deal with non-latin case folding.\n          // It works for latin source code identifiers though.\n          if (!(end < 65 || start > 122)) {\n            if (!(end < 65 || start > 90)) {\n              ranges.push([Math.max(65, start) | 32, Math.min(end, 90) | 32]);\n            }\n            if (!(end < 97 || start > 122)) {\n              ranges.push([Math.max(97, start) & ~32, Math.min(end, 122) & ~32]);\n            }\n          }\n        }\n      }\n  \n      // [[1, 10], [3, 4], [8, 12], [14, 14], [16, 16], [17, 17]]\n      // -> [[1, 12], [14, 14], [16, 17]]\n      ranges.sort(function (a, b) { return (a[0] - b[0]) || (b[1]  - a[1]); });\n      var consolidatedRanges = [];\n      var lastRange = [];\n      for (var i = 0; i < ranges.length; ++i) {\n        var range = ranges[i];\n        if (range[0] <= lastRange[1] + 1) {\n          lastRange[1] = Math.max(lastRange[1], range[1]);\n        } else {\n          consolidatedRanges.push(lastRange = range);\n        }\n      }\n  \n      for (var i = 0; i < consolidatedRanges.length; ++i) {\n        var range = consolidatedRanges[i];\n        out.push(encodeEscape(range[0]));\n        if (range[1] > range[0]) {\n          if (range[1] + 1 > range[0]) { out.push('-'); }\n          out.push(encodeEscape(range[1]));\n        }\n      }\n      out.push(']');\n      return out.join('');\n    }\n  \n    function allowAnywhereFoldCaseAndRenumberGroups(regex) {\n      // Split into character sets, escape sequences, punctuation strings\n      // like ('(', '(?:', ')', '^'), and runs of characters that do not\n      // include any of the above.\n      var parts = regex.source.match(\n          new RegExp(\n              '(?:'\n              + '\\\\[(?:[^\\\\x5C\\\\x5D]|\\\\\\\\[\\\\s\\\\S])*\\\\]'  // a character set\n              + '|\\\\\\\\u[A-Fa-f0-9]{4}'  // a unicode escape\n              + '|\\\\\\\\x[A-Fa-f0-9]{2}'  // a hex escape\n              + '|\\\\\\\\[0-9]+'  // a back-reference or octal escape\n              + '|\\\\\\\\[^ux0-9]'  // other escape sequence\n              + '|\\\\(\\\\?[:!=]'  // start of a non-capturing group\n              + '|[\\\\(\\\\)\\\\^]'  // start/end of a group, or line start\n              + '|[^\\\\x5B\\\\x5C\\\\(\\\\)\\\\^]+'  // run of other characters\n              + ')',\n              'g'));\n      var n = parts.length;\n  \n      // Maps captured group numbers to the number they will occupy in\n      // the output or to -1 if that has not been determined, or to\n      // undefined if they need not be capturing in the output.\n      var capturedGroups = [];\n  \n      // Walk over and identify back references to build the capturedGroups\n      // mapping.\n      for (var i = 0, groupIndex = 0; i < n; ++i) {\n        var p = parts[i];\n        if (p === '(') {\n          // groups are 1-indexed, so max group index is count of '('\n          ++groupIndex;\n        } else if ('\\\\' === p.charAt(0)) {\n          var decimalValue = +p.substring(1);\n          if (decimalValue) {\n            if (decimalValue <= groupIndex) {\n              capturedGroups[decimalValue] = -1;\n            } else {\n              // Replace with an unambiguous escape sequence so that\n              // an octal escape sequence does not turn into a backreference\n              // to a capturing group from an earlier regex.\n              parts[i] = encodeEscape(decimalValue);\n            }\n          }\n        }\n      }\n  \n      // Renumber groups and reduce capturing groups to non-capturing groups\n      // where possible.\n      for (var i = 1; i < capturedGroups.length; ++i) {\n        if (-1 === capturedGroups[i]) {\n          capturedGroups[i] = ++capturedGroupIndex;\n        }\n      }\n      for (var i = 0, groupIndex = 0; i < n; ++i) {\n        var p = parts[i];\n        if (p === '(') {\n          ++groupIndex;\n          if (!capturedGroups[groupIndex]) {\n            parts[i] = '(?:';\n          }\n        } else if ('\\\\' === p.charAt(0)) {\n          var decimalValue = +p.substring(1);\n          if (decimalValue && decimalValue <= groupIndex) {\n            parts[i] = '\\\\' + capturedGroups[decimalValue];\n          }\n        }\n      }\n  \n      // Remove any prefix anchors so that the output will match anywhere.\n      // ^^ really does mean an anchored match though.\n      for (var i = 0; i < n; ++i) {\n        if ('^' === parts[i] && '^' !== parts[i + 1]) { parts[i] = ''; }\n      }\n  \n      // Expand letters to groups to handle mixing of case-sensitive and\n      // case-insensitive patterns if necessary.\n      if (regex.ignoreCase && needToFoldCase) {\n        for (var i = 0; i < n; ++i) {\n          var p = parts[i];\n          var ch0 = p.charAt(0);\n          if (p.length >= 2 && ch0 === '[') {\n            parts[i] = caseFoldCharset(p);\n          } else if (ch0 !== '\\\\') {\n            // TODO: handle letters in numeric escapes.\n            parts[i] = p.replace(\n                /[a-zA-Z]/g,\n                function (ch) {\n                  var cc = ch.charCodeAt(0);\n                  return '[' + String.fromCharCode(cc & ~32, cc | 32) + ']';\n                });\n          }\n        }\n      }\n  \n      return parts.join('');\n    }\n  \n    var rewritten = [];\n    for (var i = 0, n = regexs.length; i < n; ++i) {\n      var regex = regexs[i];\n      if (regex.global || regex.multiline) { throw new Error('' + regex); }\n      rewritten.push(\n          '(?:' + allowAnywhereFoldCaseAndRenumberGroups(regex) + ')');\n    }\n  \n    return new RegExp(rewritten.join('|'), ignoreCase ? 'gi' : 'g');\n  }\n\n  /**\n   * Split markup into a string of source code and an array mapping ranges in\n   * that string to the text nodes in which they appear.\n   *\n   * <p>\n   * The HTML DOM structure:</p>\n   * <pre>\n   * (Element   \"p\"\n   *   (Element \"b\"\n   *     (Text  \"print \"))       ; #1\n   *   (Text    \"'Hello '\")      ; #2\n   *   (Element \"br\")            ; #3\n   *   (Text    \"  + 'World';\")) ; #4\n   * </pre>\n   * <p>\n   * corresponds to the HTML\n   * {@code <p><b>print </b>'Hello '<br>  + 'World';</p>}.</p>\n   *\n   * <p>\n   * It will produce the output:</p>\n   * <pre>\n   * {\n   *   sourceCode: \"print 'Hello '\\n  + 'World';\",\n   *   //                     1          2\n   *   //           012345678901234 5678901234567\n   *   spans: [0, #1, 6, #2, 14, #3, 15, #4]\n   * }\n   * </pre>\n   * <p>\n   * where #1 is a reference to the {@code \"print \"} text node above, and so\n   * on for the other text nodes.\n   * </p>\n   *\n   * <p>\n   * The {@code} spans array is an array of pairs.  Even elements are the start\n   * indices of substrings, and odd elements are the text nodes (or BR elements)\n   * that contain the text for those substrings.\n   * Substrings continue until the next index or the end of the source.\n   * </p>\n   *\n   * @param {Node} node an HTML DOM subtree containing source-code.\n   * @param {boolean} isPreformatted true if white-space in text nodes should\n   *    be considered significant.\n   * @return {Object} source code and the text nodes in which they occur.\n   */\n  function extractSourceSpans(node, isPreformatted) {\n    var nocode = /(?:^|\\s)nocode(?:\\s|$)/;\n  \n    var chunks = [];\n    var length = 0;\n    var spans = [];\n    var k = 0;\n  \n    function walk(node) {\n      var type = node.nodeType;\n      if (type == 1) {  // Element\n        if (nocode.test(node.className)) { return; }\n        for (var child = node.firstChild; child; child = child.nextSibling) {\n          walk(child);\n        }\n        var nodeName = node.nodeName.toLowerCase();\n        if ('br' === nodeName || 'li' === nodeName) {\n          chunks[k] = '\\n';\n          spans[k << 1] = length++;\n          spans[(k++ << 1) | 1] = node;\n        }\n      } else if (type == 3 || type == 4) {  // Text\n        var text = node.nodeValue;\n        if (text.length) {\n          if (!isPreformatted) {\n            text = text.replace(/[ \\t\\r\\n]+/g, ' ');\n          } else {\n            text = text.replace(/\\r\\n?/g, '\\n');  // Normalize newlines.\n          }\n          // TODO: handle tabs here?\n          chunks[k] = text;\n          spans[k << 1] = length;\n          length += text.length;\n          spans[(k++ << 1) | 1] = node;\n        }\n      }\n    }\n  \n    walk(node);\n  \n    return {\n      sourceCode: chunks.join('').replace(/\\n$/, ''),\n      spans: spans\n    };\n  }\n\n  /**\n   * Apply the given language handler to sourceCode and add the resulting\n   * decorations to out.\n   * @param {number} basePos the index of sourceCode within the chunk of source\n   *    whose decorations are already present on out.\n   */\n  function appendDecorations(basePos, sourceCode, langHandler, out) {\n    if (!sourceCode) { return; }\n    var job = {\n      sourceCode: sourceCode,\n      basePos: basePos\n    };\n    langHandler(job);\n    out.push.apply(out, job.decorations);\n  }\n\n  var notWs = /\\S/;\n\n  /**\n   * Given an element, if it contains only one child element and any text nodes\n   * it contains contain only space characters, return the sole child element.\n   * Otherwise returns undefined.\n   * <p>\n   * This is meant to return the CODE element in {@code <pre><code ...>} when\n   * there is a single child element that contains all the non-space textual\n   * content, but not to return anything where there are multiple child elements\n   * as in {@code <pre><code>...</code><code>...</code></pre>} or when there\n   * is textual content.\n   */\n  function childContentWrapper(element) {\n    var wrapper = undefined;\n    for (var c = element.firstChild; c; c = c.nextSibling) {\n      var type = c.nodeType;\n      wrapper = (type === 1)  // Element Node\n          ? (wrapper ? element : c)\n          : (type === 3)  // Text Node\n          ? (notWs.test(c.nodeValue) ? element : wrapper)\n          : wrapper;\n    }\n    return wrapper === element ? undefined : wrapper;\n  }\n\n  /** Given triples of [style, pattern, context] returns a lexing function,\n    * The lexing function interprets the patterns to find token boundaries and\n    * returns a decoration list of the form\n    * [index_0, style_0, index_1, style_1, ..., index_n, style_n]\n    * where index_n is an index into the sourceCode, and style_n is a style\n    * constant like PR_PLAIN.  index_n-1 <= index_n, and style_n-1 applies to\n    * all characters in sourceCode[index_n-1:index_n].\n    *\n    * The stylePatterns is a list whose elements have the form\n    * [style : string, pattern : RegExp, DEPRECATED, shortcut : string].\n    *\n    * Style is a style constant like PR_PLAIN, or can be a string of the\n    * form 'lang-FOO', where FOO is a language extension describing the\n    * language of the portion of the token in $1 after pattern executes.\n    * E.g., if style is 'lang-lisp', and group 1 contains the text\n    * '(hello (world))', then that portion of the token will be passed to the\n    * registered lisp handler for formatting.\n    * The text before and after group 1 will be restyled using this decorator\n    * so decorators should take care that this doesn't result in infinite\n    * recursion.  For example, the HTML lexer rule for SCRIPT elements looks\n    * something like ['lang-js', /<[s]cript>(.+?)<\\/script>/].  This may match\n    * '<script>foo()<\\/script>', which would cause the current decorator to\n    * be called with '<script>' which would not match the same rule since\n    * group 1 must not be empty, so it would be instead styled as PR_TAG by\n    * the generic tag rule.  The handler registered for the 'js' extension would\n    * then be called with 'foo()', and finally, the current decorator would\n    * be called with '<\\/script>' which would not match the original rule and\n    * so the generic tag rule would identify it as a tag.\n    *\n    * Pattern must only match prefixes, and if it matches a prefix, then that\n    * match is considered a token with the same style.\n    *\n    * Context is applied to the last non-whitespace, non-comment token\n    * recognized.\n    *\n    * Shortcut is an optional string of characters, any of which, if the first\n    * character, gurantee that this pattern and only this pattern matches.\n    *\n    * @param {Array} shortcutStylePatterns patterns that always start with\n    *   a known character.  Must have a shortcut string.\n    * @param {Array} fallthroughStylePatterns patterns that will be tried in\n    *   order if the shortcut ones fail.  May have shortcuts.\n    *\n    * @return {function (Object)} a\n    *   function that takes source code and returns a list of decorations.\n    */\n  function createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns) {\n    var shortcuts = {};\n    var tokenizer;\n    (function () {\n      var allPatterns = shortcutStylePatterns.concat(fallthroughStylePatterns);\n      var allRegexs = [];\n      var regexKeys = {};\n      for (var i = 0, n = allPatterns.length; i < n; ++i) {\n        var patternParts = allPatterns[i];\n        var shortcutChars = patternParts[3];\n        if (shortcutChars) {\n          for (var c = shortcutChars.length; --c >= 0;) {\n            shortcuts[shortcutChars.charAt(c)] = patternParts;\n          }\n        }\n        var regex = patternParts[1];\n        var k = '' + regex;\n        if (!regexKeys.hasOwnProperty(k)) {\n          allRegexs.push(regex);\n          regexKeys[k] = null;\n        }\n      }\n      allRegexs.push(/[\\0-\\uffff]/);\n      tokenizer = combinePrefixPatterns(allRegexs);\n    })();\n\n    var nPatterns = fallthroughStylePatterns.length;\n\n    /**\n     * Lexes job.sourceCode and produces an output array job.decorations of\n     * style classes preceded by the position at which they start in\n     * job.sourceCode in order.\n     *\n     * @param {Object} job an object like <pre>{\n     *    sourceCode: {string} sourceText plain text,\n     *    basePos: {int} position of job.sourceCode in the larger chunk of\n     *        sourceCode.\n     * }</pre>\n     */\n    var decorate = function (job) {\n      var sourceCode = job.sourceCode, basePos = job.basePos;\n      /** Even entries are positions in source in ascending order.  Odd enties\n        * are style markers (e.g., PR_COMMENT) that run from that position until\n        * the end.\n        * @type {Array.<number|string>}\n        */\n      var decorations = [basePos, PR_PLAIN];\n      var pos = 0;  // index into sourceCode\n      var tokens = sourceCode.match(tokenizer) || [];\n      var styleCache = {};\n\n      for (var ti = 0, nTokens = tokens.length; ti < nTokens; ++ti) {\n        var token = tokens[ti];\n        var style = styleCache[token];\n        var match = void 0;\n\n        var isEmbedded;\n        if (typeof style === 'string') {\n          isEmbedded = false;\n        } else {\n          var patternParts = shortcuts[token.charAt(0)];\n          if (patternParts) {\n            match = token.match(patternParts[1]);\n            style = patternParts[0];\n          } else {\n            for (var i = 0; i < nPatterns; ++i) {\n              patternParts = fallthroughStylePatterns[i];\n              match = token.match(patternParts[1]);\n              if (match) {\n                style = patternParts[0];\n                break;\n              }\n            }\n\n            if (!match) {  // make sure that we make progress\n              style = PR_PLAIN;\n            }\n          }\n\n          isEmbedded = style.length >= 5 && 'lang-' === style.substring(0, 5);\n          if (isEmbedded && !(match && typeof match[1] === 'string')) {\n            isEmbedded = false;\n            style = PR_SOURCE;\n          }\n\n          if (!isEmbedded) { styleCache[token] = style; }\n        }\n\n        var tokenStart = pos;\n        pos += token.length;\n\n        if (!isEmbedded) {\n          decorations.push(basePos + tokenStart, style);\n        } else {  // Treat group 1 as an embedded block of source code.\n          var embeddedSource = match[1];\n          var embeddedSourceStart = token.indexOf(embeddedSource);\n          var embeddedSourceEnd = embeddedSourceStart + embeddedSource.length;\n          if (match[2]) {\n            // If embeddedSource can be blank, then it would match at the\n            // beginning which would cause us to infinitely recurse on the\n            // entire token, so we catch the right context in match[2].\n            embeddedSourceEnd = token.length - match[2].length;\n            embeddedSourceStart = embeddedSourceEnd - embeddedSource.length;\n          }\n          var lang = style.substring(5);\n          // Decorate the left of the embedded source\n          appendDecorations(\n              basePos + tokenStart,\n              token.substring(0, embeddedSourceStart),\n              decorate, decorations);\n          // Decorate the embedded source\n          appendDecorations(\n              basePos + tokenStart + embeddedSourceStart,\n              embeddedSource,\n              langHandlerForExtension(lang, embeddedSource),\n              decorations);\n          // Decorate the right of the embedded section\n          appendDecorations(\n              basePos + tokenStart + embeddedSourceEnd,\n              token.substring(embeddedSourceEnd),\n              decorate, decorations);\n        }\n      }\n      job.decorations = decorations;\n    };\n    return decorate;\n  }\n\n  /** returns a function that produces a list of decorations from source text.\n    *\n    * This code treats \", ', and ` as string delimiters, and \\ as a string\n    * escape.  It does not recognize perl's qq() style strings.\n    * It has no special handling for double delimiter escapes as in basic, or\n    * the tripled delimiters used in python, but should work on those regardless\n    * although in those cases a single string literal may be broken up into\n    * multiple adjacent string literals.\n    *\n    * It recognizes C, C++, and shell style comments.\n    *\n    * @param {Object} options a set of optional parameters.\n    * @return {function (Object)} a function that examines the source code\n    *     in the input job and builds the decoration list.\n    */\n  function sourceDecorator(options) {\n    var shortcutStylePatterns = [], fallthroughStylePatterns = [];\n    if (options['tripleQuotedStrings']) {\n      // '''multi-line-string''', 'single-line-string', and double-quoted\n      shortcutStylePatterns.push(\n          [PR_STRING,  /^(?:\\'\\'\\'(?:[^\\'\\\\]|\\\\[\\s\\S]|\\'{1,2}(?=[^\\']))*(?:\\'\\'\\'|$)|\\\"\\\"\\\"(?:[^\\\"\\\\]|\\\\[\\s\\S]|\\\"{1,2}(?=[^\\\"]))*(?:\\\"\\\"\\\"|$)|\\'(?:[^\\\\\\']|\\\\[\\s\\S])*(?:\\'|$)|\\\"(?:[^\\\\\\\"]|\\\\[\\s\\S])*(?:\\\"|$))/,\n           null, '\\'\"']);\n    } else if (options['multiLineStrings']) {\n      // 'multi-line-string', \"multi-line-string\"\n      shortcutStylePatterns.push(\n          [PR_STRING,  /^(?:\\'(?:[^\\\\\\']|\\\\[\\s\\S])*(?:\\'|$)|\\\"(?:[^\\\\\\\"]|\\\\[\\s\\S])*(?:\\\"|$)|\\`(?:[^\\\\\\`]|\\\\[\\s\\S])*(?:\\`|$))/,\n           null, '\\'\"`']);\n    } else {\n      // 'single-line-string', \"single-line-string\"\n      shortcutStylePatterns.push(\n          [PR_STRING,\n           /^(?:\\'(?:[^\\\\\\'\\r\\n]|\\\\.)*(?:\\'|$)|\\\"(?:[^\\\\\\\"\\r\\n]|\\\\.)*(?:\\\"|$))/,\n           null, '\"\\'']);\n    }\n    if (options['verbatimStrings']) {\n      // verbatim-string-literal production from the C# grammar.  See issue 93.\n      fallthroughStylePatterns.push(\n          [PR_STRING, /^@\\\"(?:[^\\\"]|\\\"\\\")*(?:\\\"|$)/, null]);\n    }\n    var hc = options['hashComments'];\n    if (hc) {\n      if (options['cStyleComments']) {\n        if (hc > 1) {  // multiline hash comments\n          shortcutStylePatterns.push(\n              [PR_COMMENT, /^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/, null, '#']);\n        } else {\n          // Stop C preprocessor declarations at an unclosed open comment\n          shortcutStylePatterns.push(\n              [PR_COMMENT, /^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\\b|[^\\r\\n]*)/,\n               null, '#']);\n        }\n        // #include <stdio.h>\n        fallthroughStylePatterns.push(\n            [PR_STRING,\n             /^<(?:(?:(?:\\.\\.\\/)*|\\/?)(?:[\\w-]+(?:\\/[\\w-]+)+)?[\\w-]+\\.h(?:h|pp|\\+\\+)?|[a-z]\\w*)>/,\n             null]);\n      } else {\n        shortcutStylePatterns.push([PR_COMMENT, /^#[^\\r\\n]*/, null, '#']);\n      }\n    }\n    if (options['cStyleComments']) {\n      fallthroughStylePatterns.push([PR_COMMENT, /^\\/\\/[^\\r\\n]*/, null]);\n      fallthroughStylePatterns.push(\n          [PR_COMMENT, /^\\/\\*[\\s\\S]*?(?:\\*\\/|$)/, null]);\n    }\n    var regexLiterals = options['regexLiterals'];\n    if (regexLiterals) {\n      /**\n       * @const\n       */\n      var regexExcls = regexLiterals > 1\n        ? ''  // Multiline regex literals\n        : '\\n\\r';\n      /**\n       * @const\n       */\n      var regexAny = regexExcls ? '.' : '[\\\\S\\\\s]';\n      /**\n       * @const\n       */\n      var REGEX_LITERAL = (\n          // A regular expression literal starts with a slash that is\n          // not followed by * or / so that it is not confused with\n          // comments.\n          '/(?=[^/*' + regexExcls + '])'\n          // and then contains any number of raw characters,\n          + '(?:[^/\\\\x5B\\\\x5C' + regexExcls + ']'\n          // escape sequences (\\x5C),\n          +    '|\\\\x5C' + regexAny\n          // or non-nesting character sets (\\x5B\\x5D);\n          +    '|\\\\x5B(?:[^\\\\x5C\\\\x5D' + regexExcls + ']'\n          +             '|\\\\x5C' + regexAny + ')*(?:\\\\x5D|$))+'\n          // finally closed by a /.\n          + '/');\n      fallthroughStylePatterns.push(\n          ['lang-regex',\n           RegExp('^' + REGEXP_PRECEDER_PATTERN + '(' + REGEX_LITERAL + ')')\n           ]);\n    }\n\n    var types = options['types'];\n    if (types) {\n      fallthroughStylePatterns.push([PR_TYPE, types]);\n    }\n\n    var keywords = (\"\" + options['keywords']).replace(/^ | $/g, '');\n    if (keywords.length) {\n      fallthroughStylePatterns.push(\n          [PR_KEYWORD,\n           new RegExp('^(?:' + keywords.replace(/[\\s,]+/g, '|') + ')\\\\b'),\n           null]);\n    }\n\n    shortcutStylePatterns.push([PR_PLAIN,       /^\\s+/, null, ' \\r\\n\\t\\xA0']);\n\n    var punctuation =\n      // The Bash man page says\n\n      // A word is a sequence of characters considered as a single\n      // unit by GRUB. Words are separated by metacharacters,\n      // which are the following plus space, tab, and newline: { }\n      // | & $ ; < >\n      // ...\n      \n      // A word beginning with # causes that word and all remaining\n      // characters on that line to be ignored.\n\n      // which means that only a '#' after /(?:^|[{}|&$;<>\\s])/ starts a\n      // comment but empirically\n      // $ echo {#}\n      // {#}\n      // $ echo \\$#\n      // $#\n      // $ echo }#\n      // }#\n\n      // so /(?:^|[|&;<>\\s])/ is more appropriate.\n\n      // http://gcc.gnu.org/onlinedocs/gcc-2.95.3/cpp_1.html#SEC3\n      // suggests that this definition is compatible with a\n      // default mode that tries to use a single token definition\n      // to recognize both bash/python style comments and C\n      // preprocessor directives.\n\n      // This definition of punctuation does not include # in the list of\n      // follow-on exclusions, so # will not be broken before if preceeded\n      // by a punctuation character.  We could try to exclude # after\n      // [|&;<>] but that doesn't seem to cause many major problems.\n      // If that does turn out to be a problem, we should change the below\n      // when hc is truthy to include # in the run of punctuation characters\n      // only when not followint [|&;<>].\n      '^.[^\\\\s\\\\w.$@\\'\"`/\\\\\\\\]*';\n    if (options['regexLiterals']) {\n      punctuation += '(?!\\s*\\/)';\n    }\n\n    fallthroughStylePatterns.push(\n        // TODO(mikesamuel): recognize non-latin letters and numerals in idents\n        [PR_LITERAL,     /^@[a-z_$][a-z_$@0-9]*/i, null],\n        [PR_TYPE,        /^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\\w+_t\\b)/, null],\n        [PR_PLAIN,       /^[a-z_$][a-z_$@0-9]*/i, null],\n        [PR_LITERAL,\n         new RegExp(\n             '^(?:'\n             // A hex number\n             + '0x[a-f0-9]+'\n             // or an octal or decimal number,\n             + '|(?:\\\\d(?:_\\\\d+)*\\\\d*(?:\\\\.\\\\d*)?|\\\\.\\\\d\\\\+)'\n             // possibly in scientific notation\n             + '(?:e[+\\\\-]?\\\\d+)?'\n             + ')'\n             // with an optional modifier like UL for unsigned long\n             + '[a-z]*', 'i'),\n         null, '0123456789'],\n        // Don't treat escaped quotes in bash as starting strings.\n        // See issue 144.\n        [PR_PLAIN,       /^\\\\[\\s\\S]?/, null],\n        [PR_PUNCTUATION, new RegExp(punctuation), null]);\n\n    return createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns);\n  }\n\n  var decorateSource = sourceDecorator({\n        'keywords': ALL_KEYWORDS,\n        'hashComments': true,\n        'cStyleComments': true,\n        'multiLineStrings': true,\n        'regexLiterals': true\n      });\n\n  /**\n   * Given a DOM subtree, wraps it in a list, and puts each line into its own\n   * list item.\n   *\n   * @param {Node} node modified in place.  Its content is pulled into an\n   *     HTMLOListElement, and each line is moved into a separate list item.\n   *     This requires cloning elements, so the input might not have unique\n   *     IDs after numbering.\n   * @param {boolean} isPreformatted true iff white-space in text nodes should\n   *     be treated as significant.\n   */\n  function numberLines(node, opt_startLineNum, isPreformatted) {\n    var nocode = /(?:^|\\s)nocode(?:\\s|$)/;\n    var lineBreak = /\\r\\n?|\\n/;\n  \n    var document = node.ownerDocument;\n  \n    var li = document.createElement('li');\n    while (node.firstChild) {\n      li.appendChild(node.firstChild);\n    }\n    // An array of lines.  We split below, so this is initialized to one\n    // un-split line.\n    var listItems = [li];\n  \n    function walk(node) {\n      var type = node.nodeType;\n      if (type == 1 && !nocode.test(node.className)) {  // Element\n        if ('br' === node.nodeName) {\n          breakAfter(node);\n          // Discard the <BR> since it is now flush against a </LI>.\n          if (node.parentNode) {\n            node.parentNode.removeChild(node);\n          }\n        } else {\n          for (var child = node.firstChild; child; child = child.nextSibling) {\n            walk(child);\n          }\n        }\n      } else if ((type == 3 || type == 4) && isPreformatted) {  // Text\n        var text = node.nodeValue;\n        var match = text.match(lineBreak);\n        if (match) {\n          var firstLine = text.substring(0, match.index);\n          node.nodeValue = firstLine;\n          var tail = text.substring(match.index + match[0].length);\n          if (tail) {\n            var parent = node.parentNode;\n            parent.insertBefore(\n              document.createTextNode(tail), node.nextSibling);\n          }\n          breakAfter(node);\n          if (!firstLine) {\n            // Don't leave blank text nodes in the DOM.\n            node.parentNode.removeChild(node);\n          }\n        }\n      }\n    }\n  \n    // Split a line after the given node.\n    function breakAfter(lineEndNode) {\n      // If there's nothing to the right, then we can skip ending the line\n      // here, and move root-wards since splitting just before an end-tag\n      // would require us to create a bunch of empty copies.\n      while (!lineEndNode.nextSibling) {\n        lineEndNode = lineEndNode.parentNode;\n        if (!lineEndNode) { return; }\n      }\n  \n      function breakLeftOf(limit, copy) {\n        // Clone shallowly if this node needs to be on both sides of the break.\n        var rightSide = copy ? limit.cloneNode(false) : limit;\n        var parent = limit.parentNode;\n        if (parent) {\n          // We clone the parent chain.\n          // This helps us resurrect important styling elements that cross lines.\n          // E.g. in <i>Foo<br>Bar</i>\n          // should be rewritten to <li><i>Foo</i></li><li><i>Bar</i></li>.\n          var parentClone = breakLeftOf(parent, 1);\n          // Move the clone and everything to the right of the original\n          // onto the cloned parent.\n          var next = limit.nextSibling;\n          parentClone.appendChild(rightSide);\n          for (var sibling = next; sibling; sibling = next) {\n            next = sibling.nextSibling;\n            parentClone.appendChild(sibling);\n          }\n        }\n        return rightSide;\n      }\n  \n      var copiedListItem = breakLeftOf(lineEndNode.nextSibling, 0);\n  \n      // Walk the parent chain until we reach an unattached LI.\n      for (var parent;\n           // Check nodeType since IE invents document fragments.\n           (parent = copiedListItem.parentNode) && parent.nodeType === 1;) {\n        copiedListItem = parent;\n      }\n      // Put it on the list of lines for later processing.\n      listItems.push(copiedListItem);\n    }\n  \n    // Split lines while there are lines left to split.\n    for (var i = 0;  // Number of lines that have been split so far.\n         i < listItems.length;  // length updated by breakAfter calls.\n         ++i) {\n      walk(listItems[i]);\n    }\n  \n    // Make sure numeric indices show correctly.\n    if (opt_startLineNum === (opt_startLineNum|0)) {\n      listItems[0].setAttribute('value', opt_startLineNum);\n    }\n  \n    var ol = document.createElement('ol');\n    ol.className = 'linenums';\n    var offset = Math.max(0, ((opt_startLineNum - 1 /* zero index */)) | 0) || 0;\n    for (var i = 0, n = listItems.length; i < n; ++i) {\n      li = listItems[i];\n      // Stick a class on the LIs so that stylesheets can\n      // color odd/even rows, or any other row pattern that\n      // is co-prime with 10.\n      li.className = 'L' + ((i + offset) % 10);\n      if (!li.firstChild) {\n        li.appendChild(document.createTextNode('\\xA0'));\n      }\n      ol.appendChild(li);\n    }\n  \n    node.appendChild(ol);\n  }\n  /**\n   * Breaks {@code job.sourceCode} around style boundaries in\n   * {@code job.decorations} and modifies {@code job.sourceNode} in place.\n   * @param {Object} job like <pre>{\n   *    sourceCode: {string} source as plain text,\n   *    sourceNode: {HTMLElement} the element containing the source,\n   *    spans: {Array.<number|Node>} alternating span start indices into source\n   *       and the text node or element (e.g. {@code <BR>}) corresponding to that\n   *       span.\n   *    decorations: {Array.<number|string} an array of style classes preceded\n   *       by the position at which they start in job.sourceCode in order\n   * }</pre>\n   * @private\n   */\n  function recombineTagsAndDecorations(job) {\n    var isIE8OrEarlier = /\\bMSIE\\s(\\d+)/.exec(navigator.userAgent);\n    isIE8OrEarlier = isIE8OrEarlier && +isIE8OrEarlier[1] <= 8;\n    var newlineRe = /\\n/g;\n  \n    var source = job.sourceCode;\n    var sourceLength = source.length;\n    // Index into source after the last code-unit recombined.\n    var sourceIndex = 0;\n  \n    var spans = job.spans;\n    var nSpans = spans.length;\n    // Index into spans after the last span which ends at or before sourceIndex.\n    var spanIndex = 0;\n  \n    var decorations = job.decorations;\n    var nDecorations = decorations.length;\n    // Index into decorations after the last decoration which ends at or before\n    // sourceIndex.\n    var decorationIndex = 0;\n  \n    // Remove all zero-length decorations.\n    decorations[nDecorations] = sourceLength;\n    var decPos, i;\n    for (i = decPos = 0; i < nDecorations;) {\n      if (decorations[i] !== decorations[i + 2]) {\n        decorations[decPos++] = decorations[i++];\n        decorations[decPos++] = decorations[i++];\n      } else {\n        i += 2;\n      }\n    }\n    nDecorations = decPos;\n  \n    // Simplify decorations.\n    for (i = decPos = 0; i < nDecorations;) {\n      var startPos = decorations[i];\n      // Conflate all adjacent decorations that use the same style.\n      var startDec = decorations[i + 1];\n      var end = i + 2;\n      while (end + 2 <= nDecorations && decorations[end + 1] === startDec) {\n        end += 2;\n      }\n      decorations[decPos++] = startPos;\n      decorations[decPos++] = startDec;\n      i = end;\n    }\n  \n    nDecorations = decorations.length = decPos;\n  \n    var sourceNode = job.sourceNode;\n    var oldDisplay;\n    if (sourceNode) {\n      oldDisplay = sourceNode.style.display;\n      sourceNode.style.display = 'none';\n    }\n    try {\n      var decoration = null;\n      while (spanIndex < nSpans) {\n        var spanStart = spans[spanIndex];\n        var spanEnd = spans[spanIndex + 2] || sourceLength;\n  \n        var decEnd = decorations[decorationIndex + 2] || sourceLength;\n  \n        var end = Math.min(spanEnd, decEnd);\n  \n        var textNode = spans[spanIndex + 1];\n        var styledText;\n        if (textNode.nodeType !== 1  // Don't muck with <BR>s or <LI>s\n            // Don't introduce spans around empty text nodes.\n            && (styledText = source.substring(sourceIndex, end))) {\n          // This may seem bizarre, and it is.  Emitting LF on IE causes the\n          // code to display with spaces instead of line breaks.\n          // Emitting Windows standard issue linebreaks (CRLF) causes a blank\n          // space to appear at the beginning of every line but the first.\n          // Emitting an old Mac OS 9 line separator makes everything spiffy.\n          if (isIE8OrEarlier) {\n            styledText = styledText.replace(newlineRe, '\\r');\n          }\n          textNode.nodeValue = styledText;\n          var document = textNode.ownerDocument;\n          var span = document.createElement('span');\n          span.className = decorations[decorationIndex + 1];\n          var parentNode = textNode.parentNode;\n          parentNode.replaceChild(span, textNode);\n          span.appendChild(textNode);\n          if (sourceIndex < spanEnd) {  // Split off a text node.\n            spans[spanIndex + 1] = textNode\n                // TODO: Possibly optimize by using '' if there's no flicker.\n                = document.createTextNode(source.substring(end, spanEnd));\n            parentNode.insertBefore(textNode, span.nextSibling);\n          }\n        }\n  \n        sourceIndex = end;\n  \n        if (sourceIndex >= spanEnd) {\n          spanIndex += 2;\n        }\n        if (sourceIndex >= decEnd) {\n          decorationIndex += 2;\n        }\n      }\n    } finally {\n      if (sourceNode) {\n        sourceNode.style.display = oldDisplay;\n      }\n    }\n  }\n\n  /** Maps language-specific file extensions to handlers. */\n  var langHandlerRegistry = {};\n  /** Register a language handler for the given file extensions.\n    * @param {function (Object)} handler a function from source code to a list\n    *      of decorations.  Takes a single argument job which describes the\n    *      state of the computation.   The single parameter has the form\n    *      {@code {\n    *        sourceCode: {string} as plain text.\n    *        decorations: {Array.<number|string>} an array of style classes\n    *                     preceded by the position at which they start in\n    *                     job.sourceCode in order.\n    *                     The language handler should assigned this field.\n    *        basePos: {int} the position of source in the larger source chunk.\n    *                 All positions in the output decorations array are relative\n    *                 to the larger source chunk.\n    *      } }\n    * @param {Array.<string>} fileExtensions\n    */\n  function registerLangHandler(handler, fileExtensions) {\n    for (var i = fileExtensions.length; --i >= 0;) {\n      var ext = fileExtensions[i];\n      if (!langHandlerRegistry.hasOwnProperty(ext)) {\n        langHandlerRegistry[ext] = handler;\n      } else if (win['console']) {\n        console['warn']('cannot override language handler %s', ext);\n      }\n    }\n  }\n  function langHandlerForExtension(extension, source) {\n    if (!(extension && langHandlerRegistry.hasOwnProperty(extension))) {\n      // Treat it as markup if the first non whitespace character is a < and\n      // the last non-whitespace character is a >.\n      extension = /^\\s*</.test(source)\n          ? 'default-markup'\n          : 'default-code';\n    }\n    return langHandlerRegistry[extension];\n  }\n  registerLangHandler(decorateSource, ['default-code']);\n  registerLangHandler(\n      createSimpleLexer(\n          [],\n          [\n           [PR_PLAIN,       /^[^<?]+/],\n           [PR_DECLARATION, /^<!\\w[^>]*(?:>|$)/],\n           [PR_COMMENT,     /^<\\!--[\\s\\S]*?(?:-\\->|$)/],\n           // Unescaped content in an unknown language\n           ['lang-',        /^<\\?([\\s\\S]+?)(?:\\?>|$)/],\n           ['lang-',        /^<%([\\s\\S]+?)(?:%>|$)/],\n           [PR_PUNCTUATION, /^(?:<[%?]|[%?]>)/],\n           ['lang-',        /^<xmp\\b[^>]*>([\\s\\S]+?)<\\/xmp\\b[^>]*>/i],\n           // Unescaped content in javascript.  (Or possibly vbscript).\n           ['lang-js',      /^<script\\b[^>]*>([\\s\\S]*?)(<\\/script\\b[^>]*>)/i],\n           // Contains unescaped stylesheet content\n           ['lang-css',     /^<style\\b[^>]*>([\\s\\S]*?)(<\\/style\\b[^>]*>)/i],\n           ['lang-in.tag',  /^(<\\/?[a-z][^<>]*>)/i]\n          ]),\n      ['default-markup', 'htm', 'html', 'mxml', 'xhtml', 'xml', 'xsl']);\n  registerLangHandler(\n      createSimpleLexer(\n          [\n           [PR_PLAIN,        /^[\\s]+/, null, ' \\t\\r\\n'],\n           [PR_ATTRIB_VALUE, /^(?:\\\"[^\\\"]*\\\"?|\\'[^\\']*\\'?)/, null, '\\\"\\'']\n           ],\n          [\n           [PR_TAG,          /^^<\\/?[a-z](?:[\\w.:-]*\\w)?|\\/?>$/i],\n           [PR_ATTRIB_NAME,  /^(?!style[\\s=]|on)[a-z](?:[\\w:-]*\\w)?/i],\n           ['lang-uq.val',   /^=\\s*([^>\\'\\\"\\s]*(?:[^>\\'\\\"\\s\\/]|\\/(?=\\s)))/],\n           [PR_PUNCTUATION,  /^[=<>\\/]+/],\n           ['lang-js',       /^on\\w+\\s*=\\s*\\\"([^\\\"]+)\\\"/i],\n           ['lang-js',       /^on\\w+\\s*=\\s*\\'([^\\']+)\\'/i],\n           ['lang-js',       /^on\\w+\\s*=\\s*([^\\\"\\'>\\s]+)/i],\n           ['lang-css',      /^style\\s*=\\s*\\\"([^\\\"]+)\\\"/i],\n           ['lang-css',      /^style\\s*=\\s*\\'([^\\']+)\\'/i],\n           ['lang-css',      /^style\\s*=\\s*([^\\\"\\'>\\s]+)/i]\n           ]),\n      ['in.tag']);\n  registerLangHandler(\n      createSimpleLexer([], [[PR_ATTRIB_VALUE, /^[\\s\\S]+/]]), ['uq.val']);\n  registerLangHandler(sourceDecorator({\n          'keywords': CPP_KEYWORDS,\n          'hashComments': true,\n          'cStyleComments': true,\n          'types': C_TYPES\n        }), ['c', 'cc', 'cpp', 'cxx', 'cyc', 'm']);\n  registerLangHandler(sourceDecorator({\n          'keywords': 'null,true,false'\n        }), ['json']);\n  registerLangHandler(sourceDecorator({\n          'keywords': CSHARP_KEYWORDS,\n          'hashComments': true,\n          'cStyleComments': true,\n          'verbatimStrings': true,\n          'types': C_TYPES\n        }), ['cs']);\n  registerLangHandler(sourceDecorator({\n          'keywords': JAVA_KEYWORDS,\n          'cStyleComments': true\n        }), ['java']);\n  registerLangHandler(sourceDecorator({\n          'keywords': SH_KEYWORDS,\n          'hashComments': true,\n          'multiLineStrings': true\n        }), ['bash', 'bsh', 'csh', 'sh']);\n  registerLangHandler(sourceDecorator({\n          'keywords': PYTHON_KEYWORDS,\n          'hashComments': true,\n          'multiLineStrings': true,\n          'tripleQuotedStrings': true\n        }), ['cv', 'py', 'python']);\n  registerLangHandler(sourceDecorator({\n          'keywords': PERL_KEYWORDS,\n          'hashComments': true,\n          'multiLineStrings': true,\n          'regexLiterals': 2  // multiline regex literals\n        }), ['perl', 'pl', 'pm']);\n  registerLangHandler(sourceDecorator({\n          'keywords': RUBY_KEYWORDS,\n          'hashComments': true,\n          'multiLineStrings': true,\n          'regexLiterals': true\n        }), ['rb', 'ruby']);\n  registerLangHandler(sourceDecorator({\n          'keywords': JSCRIPT_KEYWORDS,\n          'cStyleComments': true,\n          'regexLiterals': true\n        }), ['javascript', 'js']);\n  registerLangHandler(sourceDecorator({\n          'keywords': COFFEE_KEYWORDS,\n          'hashComments': 3,  // ### style block comments\n          'cStyleComments': true,\n          'multilineStrings': true,\n          'tripleQuotedStrings': true,\n          'regexLiterals': true\n        }), ['coffee']);\n  registerLangHandler(sourceDecorator({\n          'keywords': RUST_KEYWORDS,\n          'cStyleComments': true,\n          'multilineStrings': true\n        }), ['rc', 'rs', 'rust']);\n  registerLangHandler(\n      createSimpleLexer([], [[PR_STRING, /^[\\s\\S]+/]]), ['regex']);\n\n  function applyDecorator(job) {\n    var opt_langExtension = job.langExtension;\n\n    try {\n      // Extract tags, and convert the source code to plain text.\n      var sourceAndSpans = extractSourceSpans(job.sourceNode, job.pre);\n      /** Plain text. @type {string} */\n      var source = sourceAndSpans.sourceCode;\n      job.sourceCode = source;\n      job.spans = sourceAndSpans.spans;\n      job.basePos = 0;\n\n      // Apply the appropriate language handler\n      langHandlerForExtension(opt_langExtension, source)(job);\n\n      // Integrate the decorations and tags back into the source code,\n      // modifying the sourceNode in place.\n      recombineTagsAndDecorations(job);\n    } catch (e) {\n      if (win['console']) {\n        console['log'](e && e['stack'] || e);\n      }\n    }\n  }\n\n  /**\n   * Pretty print a chunk of code.\n   * @param sourceCodeHtml {string} The HTML to pretty print.\n   * @param opt_langExtension {string} The language name to use.\n   *     Typically, a filename extension like 'cpp' or 'java'.\n   * @param opt_numberLines {number|boolean} True to number lines,\n   *     or the 1-indexed number of the first line in sourceCodeHtml.\n   */\n  function $prettyPrintOne(sourceCodeHtml, opt_langExtension, opt_numberLines) {\n    var container = document.createElement('div');\n    // This could cause images to load and onload listeners to fire.\n    // E.g. <img onerror=\"alert(1337)\" src=\"nosuchimage.png\">.\n    // We assume that the inner HTML is from a trusted source.\n    // The pre-tag is required for IE8 which strips newlines from innerHTML\n    // when it is injected into a <pre> tag.\n    // http://stackoverflow.com/questions/451486/pre-tag-loses-line-breaks-when-setting-innerhtml-in-ie\n    // http://stackoverflow.com/questions/195363/inserting-a-newline-into-a-pre-tag-ie-javascript\n    container.innerHTML = '<pre>' + sourceCodeHtml + '</pre>';\n    container = container.firstChild;\n    if (opt_numberLines) {\n      numberLines(container, opt_numberLines, true);\n    }\n\n    var job = {\n      langExtension: opt_langExtension,\n      numberLines: opt_numberLines,\n      sourceNode: container,\n      pre: 1\n    };\n    applyDecorator(job);\n    return container.innerHTML;\n  }\n\n   /**\n    * Find all the {@code <pre>} and {@code <code>} tags in the DOM with\n    * {@code class=prettyprint} and prettify them.\n    *\n    * @param {Function} opt_whenDone called when prettifying is done.\n    * @param {HTMLElement|HTMLDocument} opt_root an element or document\n    *   containing all the elements to pretty print.\n    *   Defaults to {@code document.body}.\n    */\n  function $prettyPrint(opt_whenDone, opt_root) {\n    var root = opt_root || document.body;\n    var doc = root.ownerDocument || document;\n    function byTagName(tn) { return root.getElementsByTagName(tn); }\n    // fetch a list of nodes to rewrite\n    var codeSegments = [byTagName('pre'), byTagName('code'), byTagName('xmp')];\n    var elements = [];\n    for (var i = 0; i < codeSegments.length; ++i) {\n      for (var j = 0, n = codeSegments[i].length; j < n; ++j) {\n        elements.push(codeSegments[i][j]);\n      }\n    }\n    codeSegments = null;\n\n    var clock = Date;\n    if (!clock['now']) {\n      clock = { 'now': function () { return +(new Date); } };\n    }\n\n    // The loop is broken into a series of continuations to make sure that we\n    // don't make the browser unresponsive when rewriting a large page.\n    var k = 0;\n    var prettyPrintingJob;\n\n    var langExtensionRe = /\\blang(?:uage)?-([\\w.]+)(?!\\S)/;\n    var prettyPrintRe = /\\bprettyprint\\b/;\n    var prettyPrintedRe = /\\bprettyprinted\\b/;\n    var preformattedTagNameRe = /pre|xmp/i;\n    var codeRe = /^code$/i;\n    var preCodeXmpRe = /^(?:pre|code|xmp)$/i;\n    var EMPTY = {};\n\n    function doWork() {\n      var endTime = (win['PR_SHOULD_USE_CONTINUATION'] ?\n                     clock['now']() + 250 /* ms */ :\n                     Infinity);\n      for (; k < elements.length && clock['now']() < endTime; k++) {\n        var cs = elements[k];\n\n        // Look for a preceding comment like\n        // <?prettify lang=\"...\" linenums=\"...\"?>\n        var attrs = EMPTY;\n        {\n          for (var preceder = cs; (preceder = preceder.previousSibling);) {\n            var nt = preceder.nodeType;\n            // <?foo?> is parsed by HTML 5 to a comment node (8)\n            // like <!--?foo?-->, but in XML is a processing instruction\n            var value = (nt === 7 || nt === 8) && preceder.nodeValue;\n            if (value\n                ? !/^\\??prettify\\b/.test(value)\n                : (nt !== 3 || /\\S/.test(preceder.nodeValue))) {\n              // Skip over white-space text nodes but not others.\n              break;\n            }\n            if (value) {\n              attrs = {};\n              value.replace(\n                  /\\b(\\w+)=([\\w:.%+-]+)/g,\n                function (_, name, value) { attrs[name] = value; });\n              break;\n            }\n          }\n        }\n\n        var className = cs.className;\n        if ((attrs !== EMPTY || prettyPrintRe.test(className))\n            // Don't redo this if we've already done it.\n            // This allows recalling pretty print to just prettyprint elements\n            // that have been added to the page since last call.\n            && !prettyPrintedRe.test(className)) {\n\n          // make sure this is not nested in an already prettified element\n          var nested = false;\n          for (var p = cs.parentNode; p; p = p.parentNode) {\n            var tn = p.tagName;\n            if (preCodeXmpRe.test(tn)\n                && p.className && prettyPrintRe.test(p.className)) {\n              nested = true;\n              break;\n            }\n          }\n          if (!nested) {\n            // Mark done.  If we fail to prettyprint for whatever reason,\n            // we shouldn't try again.\n            cs.className += ' prettyprinted';\n\n            // If the classes includes a language extensions, use it.\n            // Language extensions can be specified like\n            //     <pre class=\"prettyprint lang-cpp\">\n            // the language extension \"cpp\" is used to find a language handler\n            // as passed to PR.registerLangHandler.\n            // HTML5 recommends that a language be specified using \"language-\"\n            // as the prefix instead.  Google Code Prettify supports both.\n            // http://dev.w3.org/html5/spec-author-view/the-code-element.html\n            var langExtension = attrs['lang'];\n            if (!langExtension) {\n              langExtension = className.match(langExtensionRe);\n              // Support <pre class=\"prettyprint\"><code class=\"language-c\">\n              var wrapper;\n              if (!langExtension && (wrapper = childContentWrapper(cs))\n                  && codeRe.test(wrapper.tagName)) {\n                langExtension = wrapper.className.match(langExtensionRe);\n              }\n\n              if (langExtension) { langExtension = langExtension[1]; }\n            }\n\n            var preformatted;\n            if (preformattedTagNameRe.test(cs.tagName)) {\n              preformatted = 1;\n            } else {\n              var currentStyle = cs['currentStyle'];\n              var defaultView = doc.defaultView;\n              var whitespace = (\n                  currentStyle\n                  ? currentStyle['whiteSpace']\n                  : (defaultView\n                     && defaultView.getComputedStyle)\n                  ? defaultView.getComputedStyle(cs, null)\n                  .getPropertyValue('white-space')\n                  : 0);\n              preformatted = whitespace\n                  && 'pre' === whitespace.substring(0, 3);\n            }\n\n            // Look for a class like linenums or linenums:<n> where <n> is the\n            // 1-indexed number of the first line.\n            var lineNums = attrs['linenums'];\n            if (!(lineNums = lineNums === 'true' || +lineNums)) {\n              lineNums = className.match(/\\blinenums\\b(?::(\\d+))?/);\n              lineNums =\n                lineNums\n                ? lineNums[1] && lineNums[1].length\n                  ? +lineNums[1] : true\n                : false;\n            }\n            if (lineNums) { numberLines(cs, lineNums, preformatted); }\n\n            // do the pretty printing\n            prettyPrintingJob = {\n              langExtension: langExtension,\n              sourceNode: cs,\n              numberLines: lineNums,\n              pre: preformatted\n            };\n            applyDecorator(prettyPrintingJob);\n          }\n        }\n      }\n      if (k < elements.length) {\n        // finish up in a continuation\n        setTimeout(doWork, 250);\n      } else if ('function' === typeof opt_whenDone) {\n        opt_whenDone();\n      }\n    }\n\n    doWork();\n  }\n\n  /**\n   * Contains functions for creating and registering new language handlers.\n   * @type {Object}\n   */\n  var PR = win['PR'] = {\n        'createSimpleLexer': createSimpleLexer,\n        'registerLangHandler': registerLangHandler,\n        'sourceDecorator': sourceDecorator,\n        'PR_ATTRIB_NAME': PR_ATTRIB_NAME,\n        'PR_ATTRIB_VALUE': PR_ATTRIB_VALUE,\n        'PR_COMMENT': PR_COMMENT,\n        'PR_DECLARATION': PR_DECLARATION,\n        'PR_KEYWORD': PR_KEYWORD,\n        'PR_LITERAL': PR_LITERAL,\n        'PR_NOCODE': PR_NOCODE,\n        'PR_PLAIN': PR_PLAIN,\n        'PR_PUNCTUATION': PR_PUNCTUATION,\n        'PR_SOURCE': PR_SOURCE,\n        'PR_STRING': PR_STRING,\n        'PR_TAG': PR_TAG,\n        'PR_TYPE': PR_TYPE,\n        'prettyPrintOne':\n           IN_GLOBAL_SCOPE\n             ? (win['prettyPrintOne'] = $prettyPrintOne)\n             : (prettyPrintOne = $prettyPrintOne),\n        'prettyPrint': prettyPrint =\n           IN_GLOBAL_SCOPE\n             ? (win['prettyPrint'] = $prettyPrint)\n             : (prettyPrint = $prettyPrint)\n      };\n\n  // Make PR available via the Asynchronous Module Definition (AMD) API.\n  // Per https://github.com/amdjs/amdjs-api/wiki/AMD:\n  // The Asynchronous Module Definition (AMD) API specifies a\n  // mechanism for defining modules such that the module and its\n  // dependencies can be asynchronously loaded.\n  // ...\n  // To allow a clear indicator that a global define function (as\n  // needed for script src browser loading) conforms to the AMD API,\n  // any global define function SHOULD have a property called \"amd\"\n  // whose value is an object. This helps avoid conflict with any\n  // other existing JavaScript code that could have defined a define()\n  // function that does not conform to the AMD API.\n  if (typeof define === \"function\" && define['amd']) {\n    define(\"google-code-prettify\", [], function () {\n      return PR; \n    });\n  }\n})();\n\ndefine(\"prettify\", function(){});\n\n",
        +    "define('itemView',[\n  'App',\n  // Templates\n  'text!tpl/item.html',\n  'text!tpl/class.html',\n  'text!tpl/itemEnd.html',\n  // Tools\n  'prettify'\n], function(App, itemTpl, classTpl, endTpl) {\n  'use strict';\n\n  var appVersion = App.project.version || 'master';\n\n  var itemView = Backbone.View.extend({\n    el: '#item',\n    init: function() {\n      this.$html = $('html');\n      this.$body = $('body');\n      this.$scrollBody = $('html, body'); // hack for Chrome/Firefox scroll\n\n      this.tpl = _.template(itemTpl);\n      this.classTpl = _.template(classTpl);\n      this.endTpl = _.template(endTpl);\n\n      return this;\n    },\n    getSyntax: function(isMethod, cleanItem) {\n      var isConstructor = cleanItem.is_constructor;\n      var syntax = '';\n      if (isConstructor) {\n        syntax += 'new ';\n      } else if (cleanItem.static && cleanItem.class) {\n        syntax += cleanItem.class + '.';\n      }\n      syntax += cleanItem.name;\n\n      if (isMethod || isConstructor) {\n        syntax += '(';\n        if (cleanItem.params) {\n          for (var i = 0; i < cleanItem.params.length; i++) {\n            var p = cleanItem.params[i];\n            if (p.optional) {\n              syntax += '[';\n            }\n            syntax += p.name;\n            if (p.optdefault) {\n              syntax += '=' + p.optdefault;\n            }\n            if (p.optional) {\n              syntax += ']';\n            }\n            if (i !== cleanItem.params.length - 1) {\n              syntax += ', ';\n            }\n          }\n        }\n        syntax += ')';\n      }\n\n      return syntax;\n    },\n    // Return a list of valid syntaxes across all overloaded versions of\n    // this item.\n    //\n    // For reference, we ultimately want to replicate something like this:\n    //\n    // https://processing.org/reference/color_.html\n    getSyntaxes: function(isMethod, cleanItem) {\n      var overloads = cleanItem.overloads || [cleanItem];\n      return overloads.map(this.getSyntax.bind(this, isMethod));\n    },\n    render: function(item) {\n      if (item) {\n        var itemHtml = '';\n        var cleanItem = this.clean(item);\n        var isClass = item.hasOwnProperty('itemtype') ? 0 : 1;\n        var collectionName = isClass\n            ? 'Constructor'\n            : this.capitalizeFirst(cleanItem.itemtype),\n          isConstructor = cleanItem.is_constructor;\n        cleanItem.isMethod = collectionName === 'Method';\n\n        var syntaxes = this.getSyntaxes(cleanItem.isMethod, cleanItem);\n\n        // Set the item header (title)\n\n        // Set item contents\n        if (isClass) {\n          var constructor = this.tpl({\n            item: cleanItem,\n            isClass: true,\n            isConstructor: isConstructor,\n            syntaxes: syntaxes\n          });\n          cleanItem.constructor = constructor;\n\n          var contents = _.find(App.classes, function(c) {\n            return c.name === cleanItem.name;\n          });\n          cleanItem.things = contents.items;\n\n          itemHtml = this.classTpl(cleanItem);\n        } else {\n          cleanItem.constRefs =\n            item.module === 'Constants' && App.data.consts[item.name];\n\n          itemHtml = this.tpl({\n            item: cleanItem,\n            isClass: false,\n            isConstructor: false,\n            syntaxes: syntaxes\n          });\n        }\n\n        itemHtml += this.endTpl({ item: cleanItem, appVersion: appVersion });\n\n        // Insert the view in the dom\n        this.$el.html(itemHtml);\n\n        renderCode(cleanItem.name);\n\n        // Set the document title based on the item name.\n        // If it is a method, add parentheses to the name\n        if (item.itemtype === 'method') {\n          App.pageView.appendToDocumentTitle(item.name + '()');\n        } else {\n          App.pageView.appendToDocumentTitle(item.name);\n        }\n\n        // Hook up alt-text for examples\n        setTimeout(function() {\n          var alts = $('.example-content')[0];\n          if (alts) {\n            alts = $(alts)\n              .data('alt')\n              .split('\\n');\n\n            var canvases = $('.cnv_div');\n            for (var j = 0; j < alts.length; j++) {\n              if (j < canvases.length) {\n                $(canvases[j]).append(\n                  '<span class=\"sr-only\">' + alts[j] + '</span>'\n                );\n              }\n            }\n          }\n        }, 1000);\n        Prism.highlightAll();\n      }\n\n      var renderEvent = new Event('reference-rendered');\n      window.dispatchEvent(renderEvent);\n\n      return this;\n    },\n    /**\n     * Clean item properties: url encode properties containing paths.\n     * @param {object} item The item object.\n     * @returns {object} Returns the same item object with urlencoded paths.\n     */\n    clean: function(item) {\n      var cleanItem = item;\n\n      if (cleanItem.hasOwnProperty('file')) {\n        cleanItem.urlencodedfile = encodeURIComponent(item.file);\n      }\n      return cleanItem;\n    },\n    /**\n     * Show a single item.\n     * @param {object} item Item object.\n     * @returns {object} This view.\n     */\n    show: function(item) {\n      if (item) {\n        this.render(item);\n      }\n\n      App.pageView.hideContentViews();\n\n      this.$el.show();\n\n      this.scrollTop();\n      $('#item').focus();\n      return this;\n    },\n    /**\n     * Show a message if no item is found.\n     * @returns {object} This view.\n     */\n    nothingFound: function() {\n      this.$el.html(\n        '<p><br><br>Ouch. I am unable to find any item that match the current query.</p>'\n      );\n      App.pageView.hideContentViews();\n      this.$el.show();\n\n      return this;\n    },\n    /**\n     * Scroll to the top of the window with an animation.\n     */\n    scrollTop: function() {\n      // Hack for Chrome/Firefox scroll animation\n      // Chrome scrolls 'body', Firefox scrolls 'html'\n      var scroll = this.$body.scrollTop() > 0 || this.$html.scrollTop() > 0;\n      if (scroll) {\n        this.$scrollBody.animate({ scrollTop: 0 }, 600);\n      }\n    },\n    /**\n     * Helper method to capitalize the first letter of a string\n     * @param {string} str\n     * @returns {string} Returns the string.\n     */\n    capitalizeFirst: function(str) {\n      return str.substr(0, 1).toUpperCase() + str.substr(1);\n    }\n  });\n\n  return itemView;\n});\n\n",
        +    "\ndefine('text!tpl/menu.html',[],function () { return '<div>\\n  <br>\\n  <span id=\"reference-description1\">Can\\'t find what you\\'re looking for? You may want to check out</span>\\n  <a href=\"#/libraries/p5.sound\">p5.sound</a>.<br><a href=\\'https://p5js.org/offline-reference/p5-reference.zip\\' target=_blank><span id=\"reference-description3\">You can also download an offline version of the reference.</span></a>\\n</div>\\n\\n<div id=\\'collection-list-categories\\'>\\n<h2 class=\"sr-only\" id=\"categories\">Categories</h2>\\n<% var i=0; %>\\n<% var max=Math.floor(groups.length/4); %>\\n<% var rem=groups.length%4; %>\\n\\n<% _.each(groups, function(group){ %>\\n  <% var m = rem > 0 ? 1 : 0 %>\\n  <% if (i === 0) { %>\\n    <ul aria-labelledby=\"categories\">\\n    <% } %>\\n    <li><a href=\"#group-<%=group%>\"><%=group%></a></li>\\n    <% if (i === (max+m-1)) { %>\\n    </ul>\\n  \\t<% rem-- %>\\n  \\t<% i=0 %>\\n  <% } else { %>\\n  \\t<% i++ %>\\n  <% } %>\\n<% }); %>\\n</div>\\n';});\n\n",
        +    "define('menuView',[\n  'App',\n  'text!tpl/menu.html'\n], function(App, menuTpl) {\n\n  var menuView = Backbone.View.extend({\n    el: '#collection-list-nav',\n    /**\n     * Init.\n     * @returns {object} This view.\n     */\n    init: function() {\n      this.menuTpl = _.template(menuTpl);\n      return this;\n    },\n    /**\n     * Render.\n     * @returns {object} This view.\n     */\n    render: function() {\n\n      var groups = [];\n      _.each(App.modules, function (item, i) {\n        if (!item.is_submodule) {\n          if (!item.file || item.file.indexOf('addons') === -1) { //addons don't get displayed on main page\n            groups.push(item.name);\n          }\n        }\n        //}\n      });\n\n      // Sort groups by name A-Z\n      groups.sort();\n\n      var menuHtml = this.menuTpl({\n        'groups': groups\n      });\n\n      // Render the view\n      this.$el.html(menuHtml);\n    },\n\n    hide: function() {\n      this.$el.hide();\n    },\n\n    show: function() {\n      this.$el.show();\n    },\n\n    /**\n     * Update the menu.\n     * @param {string} el The name of the current route.\n     */\n    update: function(menuItem) {\n      //console.log(menuItem);\n      // this.$menuItems.removeClass('active');\n      // this.$menuItems.find('a[href=#'+menuItem+']').parent().addClass('active');\n\n    }\n  });\n\n  return menuView;\n\n});\n\n",
        +    "\ndefine('text!tpl/library.html',[],function () { return '<h3><%= module.name %> library</h3>\\n\\n<p><%= module.description %></p>\\n\\n<div id=\"library-page\" class=\"reference-group clearfix\">  \\n\\n<% var t = 0; col = 0; %>\\n\\n<% _.each(groups, function(group){ %>\\n  <% if (t == 0) { %> \\n    <div class=\"column_<%=col%>\">\\n  <% } %>\\n  <% if (group.name !== module.name && group.name !== \\'p5\\') { %>\\n    <% if (group.hash) { %> <a href=\"<%=group.hash%>\" <% if (group.module !== module.name) { %>class=\"core\"<% } %>><% } %>  \\n    <h4 class=\"group-name <% if (t == 0) { %> first<%}%>\"><%=group.name%></h4>\\n    <% if (group.hash) { %> </a><br> <% } %>\\n  <% } %>\\n  <% _.each(group.items.filter(function(item) {return item.access !== \\'private\\'}), function(item) { %>\\n    <a href=\"<%=item.hash%>\" <% if (item.module !== module.name) { %>class=\"core\"<% } %>><%=item.name%><% if (item.itemtype === \\'method\\') { %>()<%}%></a><br>\\n    <% t++; %>\\n  <% }); %>\\n  <% if (t >= Math.floor(totalItems/4)) { col++; t = 0; %>\\n    </div>\\n  <% } %>\\n<% }); %>\\n</div>\\n';});\n\n",
        +    "define(\n  'libraryView',[\n    'App',\n    // Templates\n    'text!tpl/library.html'\n  ],\n  function(App, libraryTpl) {\n    var libraryView = Backbone.View.extend({\n      el: '#list',\n      events: {},\n      /**\n       * Init.\n       */\n      init: function() {\n        this.libraryTpl = _.template(libraryTpl);\n\n        return this;\n      },\n      /**\n       * Render the list.\n       */\n      render: function(m, listCollection) {\n        if (m && listCollection) {\n          var self = this;\n\n          // Render items and group them by module\n          // module === group\n          this.groups = {};\n          _.each(m.items, function(item, i) {\n            var module = item.module || '_';\n            var group;\n            // Override default group with a selected category\n            // TODO: Overwriting with the first category might not be the best choice\n            // We might also want to have links for categories\n            if (item.category && item.category[0]) {\n              group = item.category[0];\n              // Populate item.hash\n              App.router.getHash(item);\n\n              // Create a group list without link hash\n              if (!self.groups[group]) {\n                self.groups[group] = {\n                  name: group.replace('_', '&nbsp;'),\n                  module: module,\n                  hash: undefined,\n                  items: []\n                };\n              }\n            } else {\n              group = item.class || '_';\n              var hash = App.router.getHash(item);\n\n              var ind = hash.lastIndexOf('/');\n              hash = hash.substring(0, ind);\n\n              // Create a group list\n              if (!self.groups[group]) {\n                self.groups[group] = {\n                  name: group.replace('_', '&nbsp;'),\n                  module: module,\n                  hash: hash,\n                  items: []\n                };\n              }\n            }\n\n            self.groups[group].items.push(item);\n          });\n\n          // Sort groups by name A-Z\n          self.groups = _.sortBy(self.groups, this.sortByName);\n\n          // Put the <li> items html into the list <ul>\n          var libraryHtml = self.libraryTpl({\n            title: self.capitalizeFirst(listCollection),\n            module: m.module,\n            totalItems: m.items.length,\n            groups: self.groups\n          });\n\n          // Render the view\n          this.$el.html(libraryHtml);\n        }\n\n        return this;\n      },\n      /**\n       * Show a list of items.\n       * @param {array} items Array of item objects.\n       * @returns {object} This view.\n       */\n      show: function(listGroup) {\n        if (App[listGroup]) {\n          this.render(App[listGroup], listGroup);\n        }\n        App.pageView.hideContentViews();\n\n        this.$el.show();\n\n        return this;\n      },\n      /**\n       * Helper method to capitalize the first letter of a string\n       * @param {string} str\n       * @returns {string} Returns the string.\n       */\n      capitalizeFirst: function(str) {\n        return str.substr(0, 1).toUpperCase() + str.substr(1);\n      },\n      /**\n       * Sort function (for the Array.prototype.sort() native method): from A to Z.\n       * @param {string} a\n       * @param {string} b\n       * @returns {Array} Returns an array with elements sorted from A to Z.\n       */\n      sortAZ: function(a, b) {\n        return a.innerHTML.toLowerCase() > b.innerHTML.toLowerCase() ? 1 : -1;\n      },\n\n      sortByName: function(a, b) {\n        if (a.name === 'p5') return -1;\n        else return 0;\n      }\n    });\n\n    return libraryView;\n  }\n);\n\n",
        +    "define('pageView',[\n  'App',\n\n  // Views\n  'searchView',\n  'listView',\n  'itemView',\n  'menuView',\n  'libraryView'\n], function(App, searchView, listView, itemView, menuView, libraryView) {\n\n  // Store the original title parts so we can substitue different endings.\n  var _originalDocumentTitle = window.document.title;\n\n  var pageView = Backbone.View.extend({\n    el: 'body',\n    /**\n     * Init.\n     */\n    init: function() {\n      App.$container = $('#container');\n      App.contentViews = [];\n\n      return this;\n    },\n    /**\n     * Render.\n     */\n    render: function() {\n\n      // Menu view\n      if (!App.menuView) {\n        App.menuView = new menuView();\n        App.menuView.init().render();\n      }\n\n      // Item view\n      if (!App.itemView) {\n        App.itemView = new itemView();\n        App.itemView.init().render();\n        // Add the item view to the views array\n        App.contentViews.push(App.itemView);\n      }\n\n      // List view\n      if (!App.listView) {\n        App.listView = new listView();\n        App.listView.init().render();\n        // Add the list view to the views array\n        App.contentViews.push(App.listView);\n      }\n\n      // Library view\n      if (!App.libraryView) {\n        App.libraryView = new libraryView();\n        App.libraryView.init().render();\n        // Add the list view to the views array\n        App.contentViews.push(App.libraryView);\n      }\n\n      // Search\n      if (!App.searchView) {\n        App.searchView = new searchView();\n        App.searchView.init().render();\n      }\n      return this;\n    },\n    /**\n     * Hide item and list views.\n     * @returns {object} This view.\n     */\n    hideContentViews: function() {\n      _.each(App.contentViews, function(view, i) {\n        view.$el.hide();\n      });\n\n      return this;\n    },\n    /**\n     * Append the supplied name to the first part of original document title.\n     * If no name is supplied, the title will reset to the original one.\n     */\n    appendToDocumentTitle: function(name){\n      if(name){\n        let firstTitlePart = _originalDocumentTitle.split(\" | \")[0];\n        window.document.title = [firstTitlePart, name].join(\" | \");\n      } else {\n        window.document.title = _originalDocumentTitle;\n      }\n    }    \n  });\n\n  return pageView;\n\n});\n\n",
        +    "define('router',[\n  'App'\n], function(App) {\n\n  'use strict'; //\n\n  var Router = Backbone.Router.extend({\n\n    routes: {\n      '': 'list',\n      'p5': 'list',\n      'p5/': 'list',\n      'classes': 'list',\n      'search': 'search',\n      'libraries/:lib': 'library',\n      ':searchClass(/:searchItem)': 'get'\n    },\n    /**\n     * Whether the json API data was loaded.\n     */\n    _initialized: false,\n    /**\n     * Initialize the app: load json API data and create searchable arrays.\n     */\n    init: function(callback) {\n      var self = this;\n      require(['pageView'], function(pageView) {\n\n        // If already initialized, move away from here!\n        if (self._initialized) {\n          if (callback)\n            callback();\n          return;\n        }\n\n        // Update initialization state: must be done now to avoid recursive mess\n        self._initialized = true;\n\n        // Render views\n        if (!App.pageView) {\n          App.pageView = new pageView();\n          App.pageView.init().render();\n        }\n\n        // If a callback is set (a route has already been called), run it\n        // otherwise, show the default list\n        if (callback)\n          callback();\n        else\n          self.list();\n      });\n    },\n    /**\n     * Start route. Simply check if initialized.\n     */\n    start: function() {\n      this.init();\n    },\n    /**\n     * Show item details by searching a class or a class item (method, property or event).\n     * @param {string} searchClass The class name (mandatory).\n     * @param {string} searchItem The class item name: can be a method, property or event name.\n     */\n    get: function(searchClass, searchItem) {\n\n      // if looking for a library page, redirect\n      if (searchClass === 'p5.sound' && !searchItem) {\n        window.location.hash = '/libraries/'+searchClass;\n        return;\n      }\n\n      var self = this;\n      this.init(function() {\n        var item = self.getItem(searchClass, searchItem);\n\n        App.menuView.hide();\n\n        if (item) {\n          App.itemView.show(item);\n        } else {\n          //App.itemView.nothingFound();\n\n          self.list();\n        }\n\n        styleCodeLinks();\n      });\n    },\n    /**\n     * Returns one item object by searching a class or a class item (method, property or event).\n     * @param {string} searchClass The class name (mandatory).\n     * @param {string} searchItem The class item name: can be a method, property or event name.\n     * @returns {object} The item found or undefined if nothing was found.\n     */\n    getItem: function(searchClass, searchItem) {\n      var classes = App.classes,\n              items = App.allItems,\n              classesCount = classes.length,\n              itemsCount = items.length,\n              className = searchClass ? searchClass.toLowerCase() : undefined,\n              itemName = searchItem ? searchItem : undefined,\n              found;\n\n      // Only search for a class, if itemName is undefined\n      if (className && !itemName) {\n        for (var i = 0; i < classesCount; i++) {\n          if (classes[i].name.toLowerCase() === className) {\n            found = classes[i];\n            _.each(found.items, function(i, idx) {\n              i.hash = App.router.getHash(i);\n            });\n            break;\n          }\n        }\n        // Search for a class item\n      } else if (className && itemName) {\n        // Search case sensitively\n        for (var i = 0; i < itemsCount; i++) {\n          if (items[i].class.toLowerCase() === className &&\n            items[i].name === itemName) {\n            found = items[i];\n            break;\n          }\n        }\n\n        // If no match was found, fallback to search case insensitively\n        if(!found){\n          for (var i = 0; i < itemsCount; i++) {\n            if(items[i].class.toLowerCase() === className &&\n              items[i].name.toLowerCase() === itemName.toLowerCase()){\n              found = items[i];\n              break;\n            }\n          }\n        }\n      }\n\n      return found;\n    },\n    /**\n     * List items.\n     * @param {string} collection The name of the collection to list.\n     */\n    list: function(collection) {\n\n      collection = 'allItems';\n\n      // Make sure collection is valid\n      if (App.collections.indexOf(collection) < 0) {\n        return;\n      }\n\n      this.init(function() {\n        App.menuView.show(collection);\n        App.menuView.update(collection);\n        App.listView.show(collection);\n        styleCodeLinks();\n      });\n    },\n    /**\n     * Display information for a library.\n     * @param {string} collection The name of the collection to list.\n     */\n    library: function(collection) {\n      this.init(function() {\n        App.menuView.hide();\n        App.libraryView.show(collection.substring(3)); //remove p5.\n        styleCodeLinks();\n      });\n    },\n    /**\n     * Close all content views.\n     */\n    search: function() {\n      this.init(function() {\n        App.menuView.hide();\n        App.pageView.hideContentViews();\n      });\n    },\n\n    /**\n     * Create an hash/url for the item.\n     * @param {Object} item A class, method, property or event object.\n     * @returns {String} The hash string, including the '#'.\n     */\n     getHash: function(item) {\n\n       if (!item.hash) {\n\n         // FIX TO INVISIBLE OBJECTS: DH (see also listView.js)\n\n         if (item.class) {\n           var clsFunc = '#/' + item.class + '.' + item.name;\n           var idx = clsFunc.lastIndexOf('.');\n           item.hash = clsFunc.substring(0,idx) + '/' + clsFunc.substring(idx+1);\n         } else {\n          item.hash = '#/' + item.name;\n         }\n       }\n\n       return item.hash;\n    }\n  });\n\n  \n  function styleCodeLinks() {\n    var links = document.getElementsByTagName(\"a\");\n    for (var iLink = 0; iLink < links.length; iLink++) {\n      var link = links[iLink];\n      if (link.hash.startsWith('#/p5')) {\n        link.classList.add('code');\n      }\n    }\n  }\n\n\n  // Get the router\n  App.router = new Router();\n\n  // Start history\n  Backbone.history.start();\n\n  return App.router;\n\n});\n\n",
        +    "/**\n * Define global App.\n */\nvar App = window.App || {};\ndefine('App', [],function() {\n  return App;\n});\n\n/**\n * Load json API data and start the router.\n * @param {module} App\n * @param {module} router\n */\nrequire([\n  'App',\n  './documented-method'], function(App, DocumentedMethod) {\n\n  // Set collections\n  App.collections = ['allItems', 'classes', 'events', 'methods', 'properties', 'p5.sound'];\n\n  // Get json API data\n  $.getJSON('data.min.json', function(data) {\n    App.data = data;\n    App.classes = [];\n    App.methods = [];\n    App.properties = [];\n    App.events = [];\n    App.allItems = [];\n    App.sound = { items: [] };\n    App.dom = { items: [] };\n    App.modules = [];\n    App.project = data.project;\n\n\n    var modules = data.modules;\n\n    // Get class items (methods, properties, events)\n    _.each(modules, function(m, idx, array) {\n      App.modules.push(m);\n      if (m.name == \"p5.sound\") {\n        App.sound.module = m;\n      }\n    });\n\n\n    var items = data.classitems;\n    var classes = data.classes;\n\n    // Get classes\n    _.each(classes, function(c, idx, array) {\n      if (!c.private) {\n        App.classes.push(c);\n      }\n    });\n\n\n    // Get class items (methods, properties, events)\n    _.each(items, function(el, idx, array) {\n      if (el.itemtype) {\n        if (el.itemtype === \"method\") {\n          el = new DocumentedMethod(el);\n          App.methods.push(el);\n          App.allItems.push(el);\n        } else if (el.itemtype === \"property\") {\n          App.properties.push(el);\n          App.allItems.push(el);\n        } else if (el.itemtype === \"event\") {\n          App.events.push(el);\n          App.allItems.push(el);\n        }\n\n        // libraries\n        if (el.module === \"p5.sound\") {\n          App.sound.items.push(el);\n        }\n      }\n    });\n\n    _.each(App.classes, function(c, idx) {\n      c.items = _.filter(App.allItems, function(it){ return it.class === c.name; });\n    });\n\n    require(['router']);\n  });\n});\n\ndefine(\"main\", function(){});\n\n",
        +    "}());"
        +  ]
        +}
        \ No newline at end of file
        
        From 88f86faa60259c731f2b0c44a39b59abb5f27036 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Wed, 4 Jun 2025 21:24:51 +0000
        Subject: [PATCH 178/282] docs: update README.md [skip ci]
        
        ---
         README.md | 1 +
         1 file changed, 1 insertion(+)
        
        diff --git a/README.md b/README.md
        index ef45a87a39..97b411a021 100644
        --- a/README.md
        +++ b/README.md
        @@ -1146,6 +1146,7 @@ We recognize all types of contributions. This project follows the [all-contribut
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/wlaith"><img src="https://avatars.githubusercontent.com/u/98265005?v=4?s=64" width="64px;" alt="Laith Alwazani"/><br /><sub><b>Laith Alwazani</b></sub></a><br /><a href="#ideas-Wlaith" title="Ideas, Planning, & Feedback">🤔</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/jep-a"><img src="https://avatars.githubusercontent.com/u/20326207?v=4?s=64" width="64px;" alt="jep"/><br /><sub><b>jep</b></sub></a><br /><a href="#ideas-jep-a" title="Ideas, Planning, & Feedback">🤔</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/dpanshug"><img src="https://avatars.githubusercontent.com/u/97534722?v=4?s=64" width="64px;" alt="Dipanshu Gupta"/><br /><sub><b>Dipanshu Gupta</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=dpanshug" title="Documentation">📖</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="https://github.com/sukrucildirr"><img src="https://avatars.githubusercontent.com/u/32969880?v=4?s=64" width="64px;" alt="sukrucildirr"/><br /><sub><b>sukrucildirr</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=sukrucildirr" title="Documentation">📖</a></td>
             </tr>
           </tbody>
         </table>
        
        From 1ef1b6f8e0e996f422c1d55e1ede2d82c03eb60a Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Wed, 4 Jun 2025 21:24:52 +0000
        Subject: [PATCH 179/282] docs: update .all-contributorsrc [skip ci]
        
        ---
         .all-contributorsrc | 9 +++++++++
         1 file changed, 9 insertions(+)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index 1114714537..2cdb2f076d 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -6896,6 +6896,15 @@
               "contributions": [
                 "doc"
               ]
        +    },
        +    {
        +      "login": "sukrucildirr",
        +      "name": "sukrucildirr",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/32969880?v=4",
        +      "profile": "https://github.com/sukrucildirr",
        +      "contributions": [
        +        "doc"
        +      ]
             }
           ],
           "repoType": "github",
        
        From f123ad460bff566daeadee46c4e66a71f2b57e98 Mon Sep 17 00:00:00 2001
        From: ksen0 <katie.kuksenok@gmail.com>
        Date: Thu, 5 Jun 2025 20:31:55 +0200
        Subject: [PATCH 180/282] Fixes in guideline and new stewards
        
        ---
         README.md                              | 44 ++++++++++++++------------
         contributor_docs/steward_guidelines.md | 10 +++---
         stewards.yml                           | 28 ++++++++++++++++
         utils/stewards-table.js                | 21 ++++++++----
         4 files changed, 70 insertions(+), 33 deletions(-)
        
        diff --git a/README.md b/README.md
        index ef45a87a39..e1d72afba3 100644
        --- a/README.md
        +++ b/README.md
        @@ -86,27 +86,29 @@ Lead/Mentor Alumni
         * [@qianqianye](https://github.com/qianqianye) - p5.js Lead,2021-present (on leave)
         * [@outofambit](https://github.com/outofambit) - p5.js Co-Lead 2021-22, Mentor 2022-2023
         * [@mcturner1995](https://github.com/mcturner1995) - p5.js Lead 2020
        -  
        -| Area                                                                                 | Steward(s)                                                                                                               |
        -| ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ |
        -| Overall                                                                              | [@ksen0](https://github.com/ksen0)                                                                                                             |
        -| [Accessibility](https://github.com/processing/p5.js/tree/main/src/accessibility)     | [@calebfoss](https://github.com/calebfoss), [@cosmicbhejafry](https://github.com/cosmicbhejafry), [@apoorva-a98](https://github.com/apoorva-a98), [@tedkmburu](https://github.com/tedkmburu), [@Zarkv](https://github.com/Zarkv), [@SkylerW99](https://github.com/SkylerW99), [@itsjoopark](https://github.com/itsjoopark), [@hannahvy](https://github.com/hannahvy), [@nhasalajoshi](https://github.com/nhasalajoshi)|
        -| [Color](https://github.com/processing/p5.js/tree/main/src/color)                     | [@paulaxisabel](https://github.com/paulaxisabel), [@SoundaryaKoutharapu](https://github.com/SoundaryaKoutharapu), [@mrbrack](https://github.com/mrbrack), [@TJ723](https://github.com/TJ723), [@Zarkv](https://github.com/Zarkv), [@SkylerW99](https://github.com/SkylerW99), [@ramya202000](https://github.com/ramya202000), [@hannahvy](https://github.com/hannahvy), [@robin-haxx](https://github.com/robin-haxx), [@hiddenenigma](https://github.com/hiddenenigma)  |
        -| [Core](https://github.com/processing/p5.js/tree/main/src/core)/Environment/Rendering | [@limzykenneth](https://github.com/limzykenneth), [@davepagurek](https://github.com/davepagurek), [@ChihYungChang](https://github.com/ChihYungChang), [@teragramgius](https://github.com/teragramgius), [@tuminzee](https://github.com/tuminzee), [@Zarkv](https://github.com/Zarkv), [@robin-haxx](https://github.com/robin-haxx), [@Gaurav-1306](https://github.com/Gaurav-1306) |
        -| [Data](https://github.com/processing/p5.js/tree/main/src/data)                       | [@angelabelle](https://github.com/angelabelle), [@shahankhatch](https://github.com/shahankhatch), [@TanviKumar](https://github.com/TanviKumar), [@SkylerW99](https://github.com/SkylerW99), [@nhasalajoshi](https://github.com/nhasalajoshi)   |
        -| [DOM](https://github.com/processing/p5.js/tree/main/src/dom)                         | [@SarveshLimaye](https://github.com/SarveshLimaye), [@SoundaryaKoutharapu](https://github.com/SoundaryaKoutharapu), [@ramya202000](https://github.com/ramya202000), [@BamaCharanChhandogi](https://github.com/BamaCharanChhandogi), [@Obi-Engine10](https://github.com/Obi-Engine10), [@MarceloGoncalves](https://github.com/MarceloGoncalves), [@hiddenenigma](https://github.com/hiddenenigma)                   |
        -| [Events](https://github.com/processing/p5.js/tree/main/src/events)                   | [@limzykenneth](https://github.com/limzykenneth), [@richardegil](https://github.com/richardegil), [@angelabelle](https://github.com/angelabelle), [@littlejacinthe](https://github.com/littlejacinthe), [@TanviKumar](https://github.com/TanviKumar), [@tuminzee](https://github.com/tuminzee)       |
        -| [Image](https://github.com/processing/p5.js/tree/main/src/image)                     | [@cgusb](https://github.com/cgusb), [@albertomancia](https://github.com/albertomancia), [@ramya202000](https://github.com/ramya202000), [@hannahvy](https://github.com/hannahvy), [@robin-haxx](https://github.com/robin-haxx)|
        -| [IO](https://github.com/processing/p5.js/tree/main/src/io)                           | [@limzykenneth](https://github.com/limzykenneth), [@Pritam1136](https://github.com/Pritam1136), [@shahankhatch](https://github.com/shahankhatch), [@TanviKumar](https://github.com/TanviKumar), [@jeanetteandrews](https://github.com/jeanetteandrews)|
        -| [Math](https://github.com/processing/p5.js/tree/main/src/math)                       | [@limzykenneth](https://github.com/limzykenneth), [@ericnlchen](https://github.com/ericnlchen), [@ChihYungChang](https://github.com/ChihYungChang), [@bsubbaraman](https://github.com/bsubbaraman), [@albertomancia](https://github.com/albertomancia), [@JazerUCSB](https://github.com/JazerUCSB), [@tedkmburu](https://github.com/tedkmburu), [@perminder-17](https://github.com/perminder-17), [@Obi-Engine10](https://github.com/Obi-Engine10), [@jeanetteandrews](https://github.com/jeanetteandrews)       |
        -| [Typography](https://github.com/processing/p5.js/tree/main/src/typography)           | [@dhowe](https://github.com/dhowe), [@paulaxisabel](https://github.com/paulaxisabel), [@SarveshLimaye](https://github.com/SarveshLimaye), [@SkylerW99](https://github.com/SkylerW99), [@BamaCharanChhandogi](https://github.com/BamaCharanChhandogi), [@Obi-Engine10](https://github.com/Obi-Engine10), [@hannahvy](https://github.com/hannahvy), [@singshris](https://github.com/singshris), [@hiddenenigma](https://github.com/hiddenenigma)       |
        -| [Utilities](https://github.com/processing/p5.js/tree/main/src/utilities)             | [@limzykenneth](https://github.com/limzykenneth), [@glopzel](https://github.com/glopzel)     |
        -| [WebGL](https://github.com/processing/p5.js/tree/main/src/webgl)                     | [@davepagurek](https://github.com/davepagurek), [@aferriss](https://github.com/aferriss), [@aceslowman](https://github.com/aceslowman), [@ShenpaiSharma](https://github.com/ShenpaiSharma), [@ChihYungChang](https://github.com/ChihYungChang), [@teragramgius](https://github.com/teragramgius), [@JazerUCSB](https://github.com/JazerUCSB), [@richardegil](https://github.com/richardegil), [@itsjoopark](https://github.com/itsjoopark), [@Gaurav-1306](https://github.com/Gaurav-1306), [@jeanetteandrews](https://github.com/jeanetteandrews)  |
        -| [Internalization](https://github.com/processing/p5.js/blob/main/src/core/internationalization.js)           | [@limzykenneth](https://github.com/limzykenneth)        |
        -| [Friendly Errors](https://github.com/processing/p5.js/tree/main/src/core/friendly_errors)         | [@richardegil](https://github.com/richardegil), [@itsjoopark](https://github.com/itsjoopark), [@hannahvy](https://github.com/hannahvy), [@bisabi-01](https://github.com/bisabi-01), [@singshris](https://github.com/singshris)   |
        -| [Contributor Docs](https://github.com/processing/p5.js/tree/main/contributor_docs)   |[@limzykenneth](https://github.com/limzykenneth), [@asukaminato0721](https://github.com/asukaminato0721), [@SoundaryaKoutharapu](https://github.com/SoundaryaKoutharapu), [@richardegil](https://github.com/richardegil), [@hannahvy](https://github.com/hannahvy), [@bayomayo](https://github.com/bayomayo)  |
        -| [p5.sound](https://github.com/processing/p5.sound.js)   |[@miguellacorte](https://github.com/miguellacorte), [@JazerUCSB](https://github.com/JazerUCSB), [@angelabelle](https://github.com/angelabelle), [@littlejacinthe](https://github.com/littlejacinthe), [@hannahvy](https://github.com/hannahvy), [@glopzel](https://github.com/glopzel), [@singshris](https://github.com/singshris), [@jeanetteandrews](https://github.com/jeanetteandrews)  |
        -| Build Process/Unit Testing                                                           | [@limzykenneth](https://github.com/limzykenneth)      |
        +
        +
        +<!-- STEWARDS-LIST:START - Do not remove or modify this section -->
        +| Area | Steward(s) |
        +|------|-------------|
        +| Maintainers | [@davepagurek](https://github.com/davepagurek), [@ksen0](https://github.com/ksen0), [@limzykenneth](https://github.com/limzykenneth), [@perminder-17](https://github.com/perminder-17), [@qianqianye](https://github.com/qianqianye) |
        +| Accessibility | [@calebfoss](https://github.com/calebfoss) |
        +| Color | [@limzykenneth](https://github.com/limzykenneth) |
        +| Core | [@davepagurek](https://github.com/davepagurek) |
        +| DevOps | [@Vaivaswat2244](https://github.com/Vaivaswat2244), [@error-four-o-four](https://github.com/error-four-o-four), [@limzykenneth](https://github.com/limzykenneth), [@lirenjie95](https://github.com/lirenjie95) |
        +| Documentation | [@VANSH3104](https://github.com/VANSH3104), [@limzykenneth](https://github.com/limzykenneth), [@perminder-17](https://github.com/perminder-17) |
        +| Friendly Errors | [@IITM-Jay](https://github.com/IITM-Jay) |
        +| Graphics (p5.strands) | [@lukeplowden](https://github.com/lukeplowden) |
        +| Graphics (WebGL) | [@aferriss](https://github.com/aferriss), [@davepagurek](https://github.com/davepagurek), [@lukeplowden](https://github.com/lukeplowden), [@perminder-17](https://github.com/perminder-17) |
        +| i18n (hi) | [@Divyansh013](https://github.com/Divyansh013), [@takshittt](https://github.com/takshittt) |
        +| i18n (zh) | [@limzykenneth](https://github.com/limzykenneth), [@lirenjie95](https://github.com/lirenjie95) |
        +| Math | [@GregStanton](https://github.com/GregStanton), [@holomorfo](https://github.com/holomorfo) |
        +| p5.js-website | [@clairep94](https://github.com/clairep94), [@ksen0](https://github.com/ksen0) |
        +| p5.sound.js | [@ogbabydiesal](https://github.com/ogbabydiesal) |
        +| Shapes | [@GregStanton](https://github.com/GregStanton) |
        +| Typography | [@dhowe](https://github.com/dhowe) |
        +| WebGL | [@RandomGamingDev](https://github.com/RandomGamingDev) |
        +<!-- STEWARDS-LIST:END -->
         
         ## Contributors
         
        diff --git a/contributor_docs/steward_guidelines.md b/contributor_docs/steward_guidelines.md
        index f85d903671..fca90c23cc 100644
        --- a/contributor_docs/steward_guidelines.md
        +++ b/contributor_docs/steward_guidelines.md
        @@ -2,7 +2,7 @@
         
         # Steward Guidelines
         
        -Whether you are new to p5.js contribution, are already active on the p5.js GitHub repositories, or are somewhere in between, this guide contains information about p5.js stewardship. If you are not sure what to expect from stewards, or if you considering how to volunteer or get started as a steward, read on!
        +Whether you are new to p5.js contribution, are already active on the p5.js GitHub repositories, or are somewhere in between, you'll find what you need in this guide to p5.js stewardship. If you are not sure what to expect from stewards, or if you are considering how to volunteer or get started as a steward, read on!
         
         
         ## Table of Contents
        @@ -44,7 +44,7 @@ An open source ethos includes [accessibility, education, collaboration, transpar
         
         The rest of these guidelines provide some tips and tricks that will help you effectively contribute to p5.js, and to helpfully guide others' contributions. Most of what is written here are guidelines unless otherwise stated, which means you can adapt the practices shown here to suit your workflow.
         
        -Everyone is invited to help steward the community when you can! We are happy to see contributors welcome new contributors, review others' code, and provide API design feedback. There are also some concrete roles:
        +Everyone is invited to help steward the community when they can! We are happy to see contributors welcome new contributors, review others' code, and provide API design feedback. There are also some concrete roles:
         
         1. Contributors are able to make Issues, PRs, Comments, and Code Reviews.
         2. Maintainers are also able to merge PRs and admin other parts of the codebase.
        @@ -62,15 +62,15 @@ There are different areas of work that stewards can be responsible for. These ar
         - **Accessibility**: This area specifically refers to digital and web accessibility, including, for example, screen reader support via API like `describe(..)` as well as accessibility support on the reference website
         - **Core**: Refers to core p5.js API, including rendering and environment
         - **DevOps**: Refers to build process, unit testing, and other aspects of the development experience
        -- **Documentation**: includes both reference in the core codebase that is exposed on the website, the contributor docs, and other website content
        +- **Documentation**: Includes both reference in the core codebase that is exposed on the website, the contributor docs, and other website content
         - i18n (Internationalization / **Translation**): Includes reviewing translations, particularly for `es`, `hi`, `ko`, `zh`
         - **Graphics**: Contains subareas of WebGL and [p5.strands](https://beta.p5js.org/tutorials/intro-to-p5-strands/)
        -- **Color**: Includes Color, ColorMode, accessibility improvements around color usage, colro in 2D and 3D, and so on
        +- **Color**: Includes Color, ColorMode, accessibility improvements around color usage
         - **Typography**: Refers to all topics on handling text and font
         - **Math**: Includes both external Math API and internal performance improvements
         - **Shapes**: Includes working with custom shapes in both 1.11.x and 2.x versions of p5.js
         - **Maintainers**: This group can merge PRs
        -- **p5.sound.js**: The [new p5.sound.js](https://github.com/processing/p5.sound.js) addon library
        +- **p5.sound.js**: The [new p5.sound.js](https://github.com/processing/p5.sound.js) add-on library
         - **p5.js-website**: Non-content aspects of the [reference website](https://p5js.org/) - for example, its structure, automations, technical improvements and so on.
         
         These focus areas may change over time depending on the needs of the project - so if you are going through the process of applying to be a steward, you are welcome to proposals new areas!
        diff --git a/stewards.yml b/stewards.yml
        index 907c5e73d1..e1465bec97 100644
        --- a/stewards.yml
        +++ b/stewards.yml
        @@ -54,3 +54,31 @@ GregStanton:
         holomorfo:
           - Math
         
        +lirenjie95:
        +  - i18n:
        +      - zh
        +  - DevOps
        +
        +IITM-Jay:
        +  - Friendly Errors
        +
        +Vaivaswat2244:
        +  - DevOps
        +
        +RandomGamingDev:
        +  - WebGL
        +
        +VANSH3104:
        +  - Documentation
        +
        +error-four-o-four:
        +  - DevOps
        +
        +takshittt:
        +  - i18n:
        +      - hi
        +
        +clairep94:
        +  - p5.js-website
        +
        +
        diff --git a/utils/stewards-table.js b/utils/stewards-table.js
        index 632202c033..9d679315c4 100644
        --- a/utils/stewards-table.js
        +++ b/utils/stewards-table.js
        @@ -8,6 +8,7 @@ const areaMap = {};
         const maintainers = new Set();
         const supportedi18n = new Set(['hi', 'ko', 'zh', 'es']);
         
        +
         for (const [user, roles] of Object.entries(parsed)) {
           roles.forEach(role => {
             if (typeof role === 'string') {
        @@ -15,20 +16,24 @@ for (const [user, roles] of Object.entries(parsed)) {
                 maintainers.add(user);
               }
               areaMap[role] = areaMap[role] || new Set();
        -      areaMap[role].add(`@${user}`);
        +      areaMap[role].add(`${user}`);
             } else {
               for (const [main, subs] of Object.entries(role)) {
                 subs.forEach(sub => {
                   if (main === 'i18n' && !supportedi18n.has(sub)) return;
                   const key = `${main} (${sub})`;
                   areaMap[key] = areaMap[key] || new Set();
        -          areaMap[key].add(`@${user}`);
        +          areaMap[key].add(`${user}`);
                 });
               }
             }
           });
         }
         
        +
        +const startMarker = '<!-- STEWARDS-LIST:START - Do not remove or modify this section -->';
        +const endMarker = '<!-- STEWARDS-LIST:END -->';
        +
         const header = '| Area | Steward(s) |';
         const divider = '|------|-------------|';
         
        @@ -41,13 +46,15 @@ const sortedEntries = Object.entries(areaMap).sort(([aKey], [bKey]) => {
         const rows = sortedEntries.map(([area, users]) => `| ${area} | ${[...users].sort().map(
           u => `[@${u}](https://github.com/${u})`
         ).join(', ')} |`).join('\n');
        -const newTable = [header, divider, rows].join('\n');
        +const newTable = [startMarker, header, divider, rows, endMarker].join('\n');
         
         let readme = fs.readFileSync('README.md', 'utf8');
         
        -readme = readme.replace(
        -  /\| *Area *\|.*\n\|[-| ]+\|\n(?:\|.*\|\n?)*/g,
        -  newTable + '\n'
        -);
        +const startIndex = readme.indexOf(startMarker);
        +const endIndex = readme.indexOf(endMarker) + endMarker.length;
        +
        +if (startIndex !== -1 && endIndex !== -1) {
        +  readme = readme.slice(0, startIndex) + newTable + readme.slice(endIndex);
        +}
         
         fs.writeFileSync('README.md', readme);
        
        From 4577058e21d4b9e626f8a512d66c603b383daad4 Mon Sep 17 00:00:00 2001
        From: ksen0 <katie.kuksenok@gmail.com>
        Date: Thu, 5 Jun 2025 20:44:15 +0200
        Subject: [PATCH 181/282] Add onboarding to steward guideline
        
        ---
         contributor_docs/steward_guidelines.md | 7 +++++++
         1 file changed, 7 insertions(+)
        
        diff --git a/contributor_docs/steward_guidelines.md b/contributor_docs/steward_guidelines.md
        index fca90c23cc..2b271f8ba1 100644
        --- a/contributor_docs/steward_guidelines.md
        +++ b/contributor_docs/steward_guidelines.md
        @@ -11,6 +11,7 @@ Whether you are new to p5.js contribution, are already active on the p5.js GitHu
           - [Community Care](#community-care)
           - [Areas](#areas)
           - [Becoming a Steward](#becoming-a-steward)
        +  - [Getting Started with Stewardship](#getting-started-with-stewardship)
         - [Issues](#issues)
           - [Bug report](#bug-report)
           - [Feature request](#feature-request)
        @@ -84,6 +85,12 @@ There are two ways to become a steward:
         
         To remain a steward, you must contribute as a steward to at least 1 of the 2 most recent minor releases (e.g., 2.1.0 or 1.11.0 - when the middle number changes). These are not as frequent as patches (e.g., 2.0.3 to 2.0.4 - when the rightmost number changes), and in practice this means that stewards are expected to be active every 4-6 months or so, supporting other contributors through discussion or code review - not necessarily writing code. To step down from stewardship, you can make a PR to remove yourself from `stewards.yml`. You are always welcome to take a pause and reapply in the future!
         
        +### Getting Started with Stewardship
        +
        +1. Keep this guideline handy as a reference - how to help with new issues, bugs, and features. For example, the "Feature request" section includes tips on how to use the the p5.js [access statement](access.md) as a steward.
        +2. When helping to answer technical questions or review, try to apply the Processing Foundation [guideline on answering questions](https://discourse.processing.org/t/guidelines-answering-questions/2145) - these can be especially helpful for giving constructive technical feedback.
        +3. Join the [p5.js Discord](https://discord.com/invite/SHQ8dH25r9)  - in the `#contribute-to-p5` you're welcome to ask any questions you have about this process - or suggest how it can be improved!
        +
         ## Issues
         
         We encourage most source code contributions to start with an issue, and as such, issues are the place where most of the discussions will take place. The steps to take when reviewing an issue will depend on what kind of issue it is. The repo uses [GitHub issue templates](https://github.com/processing/p5.js/blob/main/.github/ISSUE_TEMPLATE) in order to better organize different kinds of issues and encourage issue authors to provide all relevant information about their problems. The first step in reviewing the issue will often be looking through the filled-out template and determining if you need additional information (e.g., because some fields weren't filled in or the incorrect template was used).
        
        From a64d54a2d1dcd337eae8cd0958f082a89705da91 Mon Sep 17 00:00:00 2001
        From: ksen0 <katie.kuksenok@gmail.com>
        Date: Thu, 5 Jun 2025 22:29:07 +0200
        Subject: [PATCH 182/282] 1.11.8
        
        ---
         package-lock.json | 4 ++--
         package.json      | 2 +-
         2 files changed, 3 insertions(+), 3 deletions(-)
        
        diff --git a/package-lock.json b/package-lock.json
        index 6ee4bf47e1..2ebb5c8159 100644
        --- a/package-lock.json
        +++ b/package-lock.json
        @@ -1,12 +1,12 @@
         {
           "name": "p5",
        -  "version": "1.11.7",
        +  "version": "1.11.8",
           "lockfileVersion": 3,
           "requires": true,
           "packages": {
             "": {
               "name": "p5",
        -      "version": "1.11.7",
        +      "version": "1.11.8",
               "license": "LGPL-2.1",
               "devDependencies": {
                 "@babel/core": "^7.7.7",
        diff --git a/package.json b/package.json
        index 132b2ad0e4..24646e81a8 100644
        --- a/package.json
        +++ b/package.json
        @@ -24,7 +24,7 @@
               "node --require @babel/register ./utils/sample-linter.js"
             ]
           },
        -  "version": "1.11.7",
        +  "version": "1.11.8",
           "devDependencies": {
             "@babel/core": "^7.7.7",
             "@babel/preset-env": "^7.10.2",
        
        From 0ede2fb682a6e0b1ac96174af765223e1a5381a0 Mon Sep 17 00:00:00 2001
        From: ksen0 <katie.kuksenok@gmail.com>
        Date: Fri, 6 Jun 2025 10:08:01 +0200
        Subject: [PATCH 183/282] Clean up stewards table generation
        
        ---
         utils/stewards-table.js | 4 ----
         1 file changed, 4 deletions(-)
        
        diff --git a/utils/stewards-table.js b/utils/stewards-table.js
        index 9d679315c4..fe5060f7ba 100644
        --- a/utils/stewards-table.js
        +++ b/utils/stewards-table.js
        @@ -5,16 +5,12 @@ const yamlData = fs.readFileSync('stewards.yml', 'utf8');
         const parsed = yaml.load(yamlData);
         
         const areaMap = {};
        -const maintainers = new Set();
         const supportedi18n = new Set(['hi', 'ko', 'zh', 'es']);
         
         
         for (const [user, roles] of Object.entries(parsed)) {
           roles.forEach(role => {
             if (typeof role === 'string') {
        -      if (role.toLowerCase() === 'maintainers') {
        -        maintainers.add(user);
        -      }
               areaMap[role] = areaMap[role] || new Set();
               areaMap[role].add(`${user}`);
             } else {
        
        From fda190fad4cfa781c3f128857d8096f04fa3ef75 Mon Sep 17 00:00:00 2001
        From: ksen0 <katie.kuksenok@gmail.com>
        Date: Fri, 6 Jun 2025 11:55:54 +0200
        Subject: [PATCH 184/282] Update issue labeler to include new steward areas
        
        ---
         .github/ISSUE_TEMPLATE/2-found-a-bug.yml |  8 ++++----
         .github/labeler.yml                      | 10 ++++++++--
         2 files changed, 12 insertions(+), 6 deletions(-)
        
        diff --git a/.github/ISSUE_TEMPLATE/2-found-a-bug.yml b/.github/ISSUE_TEMPLATE/2-found-a-bug.yml
        index dd06e29725..948c2f1c37 100644
        --- a/.github/ISSUE_TEMPLATE/2-found-a-bug.yml
        +++ b/.github/ISSUE_TEMPLATE/2-found-a-bug.yml
        @@ -19,11 +19,11 @@ body:
                 - label: Math
                 - label: Typography
                 - label: Utilities
        +        - label: p5.strands
                 - label: WebGL
        -        - label: Build process
        -        - label: Unit testing
        -        - label: Internationalization
        -        - label: Friendly errors
        +        - label: DevOps, Build process, Unit testing
        +        - label: Internationalization (i18n)
        +        - label: Friendly Errors
                 - label: Other (specify if possible)
         - type: input
           attributes:
        diff --git a/.github/labeler.yml b/.github/labeler.yml
        index daa971834c..a593e7c8e9 100644
        --- a/.github/labeler.yml
        +++ b/.github/labeler.yml
        @@ -22,11 +22,17 @@
           - '\[[xX]\]\s*Utilities'
         "Area:WebGL":
           - '\[[xX]\]\s*WebGL'
        +"Internationalization":
        +  - '\[[xX]\]\s*Internationalization'
        +"DevOps":
        +  - '\[[xX]\]\s*Build Process'
        +"DevOps":
        +  - '\[[xX]\]\s*Unit Testing'
         "Build Process":
           - '\[[xX]\]\s*Build Process'
         "Unit Testing":
           - '\[[xX]\]\s*Unit Testing'
        -"Internationalization":
        -  - '\[[xX]\]\s*Internationalization'
         "Friendly Errors":
           - '\[[xX]\]\s*Friendly Errors'
        +"p5.strands":
        +  - '\[[xX]\]\s*p5.strands'
        
        From 29a95147f65d7e8836ba3359d5380bb777a92111 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Fri, 6 Jun 2025 09:59:12 +0000
        Subject: [PATCH 185/282] docs: update README.md [skip ci]
        
        ---
         README.md | 1 +
         1 file changed, 1 insertion(+)
        
        diff --git a/README.md b/README.md
        index 97b411a021..ff94232d3b 100644
        --- a/README.md
        +++ b/README.md
        @@ -1147,6 +1147,7 @@ We recognize all types of contributions. This project follows the [all-contribut
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/jep-a"><img src="https://avatars.githubusercontent.com/u/20326207?v=4?s=64" width="64px;" alt="jep"/><br /><sub><b>jep</b></sub></a><br /><a href="#ideas-jep-a" title="Ideas, Planning, & Feedback">🤔</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/dpanshug"><img src="https://avatars.githubusercontent.com/u/97534722?v=4?s=64" width="64px;" alt="Dipanshu Gupta"/><br /><sub><b>Dipanshu Gupta</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=dpanshug" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/sukrucildirr"><img src="https://avatars.githubusercontent.com/u/32969880?v=4?s=64" width="64px;" alt="sukrucildirr"/><br /><sub><b>sukrucildirr</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=sukrucildirr" title="Documentation">📖</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="https://linktr.ee/andrewmcwhae"><img src="https://avatars.githubusercontent.com/u/8450380?v=4?s=64" width="64px;" alt="Andrew McWhae"/><br /><sub><b>Andrew McWhae</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=andrewmcwhae" title="Documentation">📖</a></td>
             </tr>
           </tbody>
         </table>
        
        From aa8a907680e4a9d7533775d05795873179d664fd Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Fri, 6 Jun 2025 09:59:13 +0000
        Subject: [PATCH 186/282] docs: update .all-contributorsrc [skip ci]
        
        ---
         .all-contributorsrc | 9 +++++++++
         1 file changed, 9 insertions(+)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index 2cdb2f076d..f4cfbabfb1 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -6905,6 +6905,15 @@
               "contributions": [
                 "doc"
               ]
        +    },
        +    {
        +      "login": "andrewmcwhae",
        +      "name": "Andrew McWhae",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/8450380?v=4",
        +      "profile": "https://linktr.ee/andrewmcwhae",
        +      "contributions": [
        +        "doc"
        +      ]
             }
           ],
           "repoType": "github",
        
        From b66dcdf414a415699a25bc8d234843e47980161b Mon Sep 17 00:00:00 2001
        From: Ben Gilbert <bensgilbert@outlook.com>
        Date: Sat, 7 Jun 2025 17:19:19 +0100
        Subject: [PATCH 187/282] Merge (#1)
        
        * Fixed loop variable in createFileInput() docs (dom.js)
        
        * Bump serialize-javascript and mocha
        
        Bumps [serialize-javascript](https://github.com/yahoo/serialize-javascript) to 6.0.2 and updates ancestor dependency [mocha](https://github.com/mochajs/mocha). These dependencies need to be updated together.
        
        
        Updates `serialize-javascript` from 6.0.0 to 6.0.2
        - [Release notes](https://github.com/yahoo/serialize-javascript/releases)
        - [Commits](https://github.com/yahoo/serialize-javascript/compare/v6.0.0...v6.0.2)
        
        Updates `mocha` from 10.2.0 to 10.8.2
        - [Release notes](https://github.com/mochajs/mocha/releases)
        - [Changelog](https://github.com/mochajs/mocha/blob/main/CHANGELOG.md)
        - [Commits](https://github.com/mochajs/mocha/compare/v10.2.0...v10.8.2)
        
        ---
        updated-dependencies:
        - dependency-name: serialize-javascript
          dependency-type: indirect
        - dependency-name: mocha
          dependency-type: direct:development
        ...
        
        Signed-off-by: dependabot[bot] <support@github.com>
        
        * Bump elliptic from 6.6.0 to 6.6.1
        
        Bumps [elliptic](https://github.com/indutny/elliptic) from 6.6.0 to 6.6.1.
        - [Commits](https://github.com/indutny/elliptic/compare/v6.6.0...v6.6.1)
        
        ---
        updated-dependencies:
        - dependency-name: elliptic
          dependency-type: indirect
        ...
        
        Signed-off-by: dependabot[bot] <support@github.com>
        
        * added instance of video in callback
        
        * Revert "fix: push() ignoring the ColorMode #7402"
        
        * Fix typos
        
        * docs: update README.md [skip ci]
        
        * docs: update .all-contributorsrc [skip ci]
        
        * docs: update README.md [skip ci]
        
        * docs: update .all-contributorsrc [skip ci]
        
        * docs: update README.md [skip ci]
        
        * docs: update .all-contributorsrc [skip ci]
        
        * docs: update README.md [skip ci]
        
        * docs: update .all-contributorsrc [skip ci]
        
        * Add @dpanshug for doc
        
        * Update reference.js
        
        * Update reference.js.map
        
        * Update books.xml
        
        * Update error_helpers.js
        
        * Update sketch.js
        
        * Update sketch.js
        
        * Update p5.Table.js
        
        * Update p5.Image.js
        
        * Update pixels.js
        
        * Remove generated reference.js.map from PR
        
        * Restore generated file to match upstream main
        
        * docs: update README.md [skip ci]
        
        * docs: update .all-contributorsrc [skip ci]
        
        * 1.11.8
        
        * docs: update README.md [skip ci]
        
        * docs: update .all-contributorsrc [skip ci]
        
        ---------
        
        Signed-off-by: dependabot[bot] <support@github.com>
        Co-authored-by: Andrew McWhae <andrew.mcwhae@gmail.com>
        Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
        Co-authored-by: Soubhagya Mohapatra <ssm.allrounder@gmail.com>
        Co-authored-by: kit <1304340+ksen0@users.noreply.github.com>
        Co-authored-by: omahs <73983677+omahs@users.noreply.github.com>
        Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
        Co-authored-by: raclim <43053081+raclim@users.noreply.github.com>
        Co-authored-by: Perminder Singh <127239756+perminder-17@users.noreply.github.com>
        Co-authored-by: ksen0 <katie.kuksenok@gmail.com>
        Co-authored-by: sukrucildirr <sukrucildirr@gmail.com>
        ---
         .all-contributorsrc                           |  63 ++++++
         README.md                                     |  10 +-
         .../project_wrapups/DIVYANSHU_RAJ_GSOC_20.md  |   2 +-
         .../project_wrapups/munusshih_gsoc_2023.md    |   2 +-
         docs/yuidoc-p5-theme/assets/js/reference.js   |  20 +-
         lib/addons/p5.sound.js                        |   6 +-
         package-lock.json                             | 180 ++++++++----------
         package.json                                  |   2 +-
         src/accessibility/outputs.js                  |   2 +-
         src/core/friendly_errors/sketch_reader.js     |   2 +-
         src/core/p5.Renderer.js                       |   4 +-
         src/dom/dom.js                                |  20 +-
         src/image/p5.Image.js                         |   2 +-
         src/image/pixels.js                           |   2 +-
         src/io/p5.Table.js                            |   4 +-
         src/webgl/shaders/lighting.glsl               |   2 +-
         tasks/build/browserify.js                     |   2 +-
         tasks/build/combineModules.js                 |   2 +-
         .../tutorials/DOM-extensions/6/sketch.js      |   2 +-
         .../tutorials/DOM-extensions/7/sketch.js      |   2 +-
         test/unit/assets/books.xml                    |   4 +-
         test/unit/core/environment.js                 |   2 +-
         test/unit/core/error_helpers.js               |  10 +-
         test/unit/core/rendering.js                   |   4 +-
         24 files changed, 198 insertions(+), 153 deletions(-)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index c4cc53ddeb..f4cfbabfb1 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -6851,6 +6851,69 @@
               "contributions": [
                 "doc"
               ]
        +    },
        +    {
        +      "login": "irina-wang",
        +      "name": "Irina Mengqi Wang",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/59970384?v=4",
        +      "profile": "https://github.com/irina-wang",
        +      "contributions": [
        +        "example"
        +      ]
        +    },
        +    {
        +      "login": "jennybkowalski",
        +      "name": "Jenny Biette Kowalski",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/11235412?v=4",
        +      "profile": "http://jennybkowalski.com",
        +      "contributions": [
        +        "ideas"
        +      ]
        +    },
        +    {
        +      "login": "Wlaith",
        +      "name": "Laith Alwazani",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/98265005?v=4",
        +      "profile": "https://github.com/wlaith",
        +      "contributions": [
        +        "ideas"
        +      ]
        +    },
        +    {
        +      "login": "jep-a",
        +      "name": "jep",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/20326207?v=4",
        +      "profile": "https://github.com/jep-a",
        +      "contributions": [
        +        "ideas"
        +      ]
        +    },
        +    {
        +      "login": "dpanshug",
        +      "name": "Dipanshu Gupta",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/97534722?v=4",
        +      "profile": "https://github.com/dpanshug",
        +      "contributions": [
        +        "doc"
        +      ]
        +    },
        +    {
        +      "login": "sukrucildirr",
        +      "name": "sukrucildirr",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/32969880?v=4",
        +      "profile": "https://github.com/sukrucildirr",
        +      "contributions": [
        +        "doc"
        +      ]
        +    },
        +    {
        +      "login": "andrewmcwhae",
        +      "name": "Andrew McWhae",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/8450380?v=4",
        +      "profile": "https://linktr.ee/andrewmcwhae",
        +      "contributions": [
        +        "doc"
        +      ]
             }
           ],
           "repoType": "github",
        diff --git a/README.md b/README.md
        index 6f4b71cce8..ff94232d3b 100644
        --- a/README.md
        +++ b/README.md
        @@ -1134,12 +1134,20 @@ We recognize all types of contributions. This project follows the [all-contribut
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/HughJacks"><img src="https://avatars.githubusercontent.com/u/102194905?v=4?s=64" width="64px;" alt="HughJacks"/><br /><sub><b>HughJacks</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=HughJacks" title="Code">💻</a></td>
             </tr>
             <tr>
        -      <td align="center" valign="top" width="16.66%"><a href="http://jackeddielove.github.io"><img src="https://avatars.githubusercontent.com/u/130420780?v=4?s=64" width="64px;" alt="Jack L"/><br /><sub><b>Jack L</b></sub></a><br /><a href="https://github.com/processing/p5.js/issues?q=author%3Ajackeddielove" title="Bug reports">🐛</a> <a href="https://github.com/processing/p5.js/commits?author=jackeddielove" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="http://jackeddielove.github.io"><img src="https://avatars.githubusercontent.com/u/130420780?v=4?s=64" width="64px;" alt="Jack L"/><br /><sub><b>Jack L</b></sub></a><br /><a href="https://github.com/processing/p5.js/issues?q=author%3Ajackeddielove" title="Bug reports">🐛</a> <a href="https://github.com/processing/p5.js/commits?author=jackeddielove" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/clairep94"><img src="https://avatars.githubusercontent.com/u/128436909?v=4?s=64" width="64px;" alt="Claire Peng"/><br /><sub><b>Claire Peng</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=clairep94" title="Code">💻</a> <a href="https://github.com/processing/p5.js/issues?q=author%3Aclairep94" title="Bug reports">🐛</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/IIITM-Jay"><img src="https://avatars.githubusercontent.com/u/65283880?v=4?s=64" width="64px;" alt="Jay Dev Jha"/><br /><sub><b>Jay Dev Jha</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=IIITM-Jay" title="Code">💻</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://yugalkaushik.vercel.app"><img src="https://avatars.githubusercontent.com/u/138966980?v=4?s=64" width="64px;" alt="Yugal Kaushik"/><br /><sub><b>Yugal Kaushik</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=yugalkaushik" title="Code">💻</a> <a href="https://github.com/processing/p5.js/commits?author=yugalkaushik" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/LalitNarayanYadav"><img src="https://avatars.githubusercontent.com/u/162928571?v=4?s=64" width="64px;" alt="Lalit Narayan Yadav"/><br /><sub><b>Lalit Narayan Yadav</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=LalitNarayanYadav" title="Documentation">📖</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="https://github.com/irina-wang"><img src="https://avatars.githubusercontent.com/u/59970384?v=4?s=64" width="64px;" alt="Irina Mengqi Wang"/><br /><sub><b>Irina Mengqi Wang</b></sub></a><br /><a href="#example-irina-wang" title="Examples">💡</a></td>
        +    </tr>
        +    <tr>
        +      <td align="center" valign="top" width="16.66%"><a href="http://jennybkowalski.com"><img src="https://avatars.githubusercontent.com/u/11235412?v=4?s=64" width="64px;" alt="Jenny Biette Kowalski"/><br /><sub><b>Jenny Biette Kowalski</b></sub></a><br /><a href="#ideas-jennybkowalski" title="Ideas, Planning, & Feedback">🤔</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="https://github.com/wlaith"><img src="https://avatars.githubusercontent.com/u/98265005?v=4?s=64" width="64px;" alt="Laith Alwazani"/><br /><sub><b>Laith Alwazani</b></sub></a><br /><a href="#ideas-Wlaith" title="Ideas, Planning, & Feedback">🤔</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="https://github.com/jep-a"><img src="https://avatars.githubusercontent.com/u/20326207?v=4?s=64" width="64px;" alt="jep"/><br /><sub><b>jep</b></sub></a><br /><a href="#ideas-jep-a" title="Ideas, Planning, & Feedback">🤔</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="https://github.com/dpanshug"><img src="https://avatars.githubusercontent.com/u/97534722?v=4?s=64" width="64px;" alt="Dipanshu Gupta"/><br /><sub><b>Dipanshu Gupta</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=dpanshug" title="Documentation">📖</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="https://github.com/sukrucildirr"><img src="https://avatars.githubusercontent.com/u/32969880?v=4?s=64" width="64px;" alt="sukrucildirr"/><br /><sub><b>sukrucildirr</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=sukrucildirr" title="Documentation">📖</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="https://linktr.ee/andrewmcwhae"><img src="https://avatars.githubusercontent.com/u/8450380?v=4?s=64" width="64px;" alt="Andrew McWhae"/><br /><sub><b>Andrew McWhae</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=andrewmcwhae" title="Documentation">📖</a></td>
             </tr>
           </tbody>
         </table>
        diff --git a/contributor_docs/project_wrapups/DIVYANSHU_RAJ_GSOC_20.md b/contributor_docs/project_wrapups/DIVYANSHU_RAJ_GSOC_20.md
        index d4117393fd..41c377675e 100644
        --- a/contributor_docs/project_wrapups/DIVYANSHU_RAJ_GSOC_20.md
        +++ b/contributor_docs/project_wrapups/DIVYANSHU_RAJ_GSOC_20.md
        @@ -53,7 +53,7 @@ The introduction of es6 classes into the JS world , was a great relief for devel
         
         when it comes to AUDIO GRAPHS , where one node is connected to so many other nodes and inherit property from its parent nodes , a more robust and cleaner  implementation of Nodes was required and ES6 classes rocked the way  .
         
        -Following PR REVAMPED the p5.sound's   AUDIO NODES from ``funtion syntax`` to  ``ES6 classes syntax``
        +Following PR REVAMPED the p5.sound's   AUDIO NODES from ``function syntax`` to  ``ES6 classes syntax``
         
         [#502](https://github.com/processing/p5.js-sound/pull/502)
         [#503](https://github.com/processing/p5.js-sound/pull/503)
        diff --git a/contributor_docs/project_wrapups/munusshih_gsoc_2023.md b/contributor_docs/project_wrapups/munusshih_gsoc_2023.md
        index 238f673deb..8a2712b32e 100644
        --- a/contributor_docs/project_wrapups/munusshih_gsoc_2023.md
        +++ b/contributor_docs/project_wrapups/munusshih_gsoc_2023.md
        @@ -69,7 +69,7 @@ In conclusion, I am grateful for my time working with p5.js typography during GS
         ## Features Requested
         
         ```jsx
        -If they're not dependent/relevant, we should do seperate PRs.
        +If they're not dependent/relevant, we should do separate PRs.
         ```
         
         | Topic | Status | Coded? | PR? | Pushed? |
        diff --git a/docs/yuidoc-p5-theme/assets/js/reference.js b/docs/yuidoc-p5-theme/assets/js/reference.js
        index 455d4425d9..bfcfe7c281 100644
        --- a/docs/yuidoc-p5-theme/assets/js/reference.js
        +++ b/docs/yuidoc-p5-theme/assets/js/reference.js
        @@ -1317,7 +1317,7 @@ define('typeahead',[], function() {
                     wordsOnly: false,
                     caseSensitive: false
                 };
        -        return function hightlight(o) {
        +        return function highlight(o) {
                     var regex;
                     o = _.mixin({}, defaults, o);
                     if (!o.node || !o.pattern) {
        @@ -1325,8 +1325,8 @@ define('typeahead',[], function() {
                     }
                     o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ];
                     regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly);
        -            traverse(o.node, hightlightTextNode);
        -            function hightlightTextNode(textNode) {
        +            traverse(o.node, highlightTextNode);
        +            function highlightTextNode(textNode) {
                         var match, patternNode;
                         if (match = regex.exec(textNode.data)) {
                             wrapperNode = doc.createElement(o.tagName);
        @@ -1338,14 +1338,14 @@ define('typeahead',[], function() {
                         }
                         return !!match;
                     }
        -            function traverse(el, hightlightTextNode) {
        +            function traverse(el, highlightTextNode) {
                         var childNode, TEXT_NODE_TYPE = 3;
                         for (var i = 0; i < el.childNodes.length; i++) {
                             childNode = el.childNodes[i];
                             if (childNode.nodeType === TEXT_NODE_TYPE) {
        -                        i += hightlightTextNode(childNode) ? 1 : 0;
        +                        i += highlightTextNode(childNode) ? 1 : 0;
                             } else {
        -                        traverse(childNode, hightlightTextNode);
        +                        traverse(childNode, highlightTextNode);
                             }
                         }
                     }
        @@ -3104,7 +3104,7 @@ var prettyPrint;
             * recognized.
             *
             * Shortcut is an optional string of characters, any of which, if the first
        -    * character, gurantee that this pattern and only this pattern matches.
        +    * character, guarantee that this pattern and only this pattern matches.
             *
             * @param {Array} shortcutStylePatterns patterns that always start with
             *   a known character.  Must have a shortcut string.
        @@ -3387,12 +3387,12 @@ var prettyPrint;
               // preprocessor directives.
         
               // This definition of punctuation does not include # in the list of
        -      // follow-on exclusions, so # will not be broken before if preceeded
        +      // follow-on exclusions, so # will not be broken before if preceded
               // by a punctuation character.  We could try to exclude # after
               // [|&;<>] but that doesn't seem to cause many major problems.
               // If that does turn out to be a problem, we should change the below
               // when hc is truthy to include # in the run of punctuation characters
        -      // only when not followint [|&;<>].
        +      // only when not following [|&;<>].
               '^.[^\\s\\w.$@\'"`/\\\\]*';
             if (options['regexLiterals']) {
               punctuation += '(?!\s*\/)';
        @@ -4546,7 +4546,7 @@ define('pageView',[
           'libraryView'
         ], function(App, searchView, listView, itemView, menuView, libraryView) {
         
        -  // Store the original title parts so we can substitue different endings.
        +  // Store the original title parts so we can substitute different endings.
           var _originalDocumentTitle = window.document.title;
         
           var pageView = Backbone.View.extend({
        diff --git a/lib/addons/p5.sound.js b/lib/addons/p5.sound.js
        index a8a7e3f450..f7216fca04 100644
        --- a/lib/addons/p5.sound.js
        +++ b/lib/addons/p5.sound.js
        @@ -8308,7 +8308,7 @@ function reverb_setPrototypeOf(o, p) { reverb_setPrototypeOf = Object.setPrototy
         /**
          *  Reverb adds depth to a sound through a large number of decaying
          *  echoes. It creates the perception that sound is occurring in a
        - *  physical space. The p5.Reverb has paramters for Time (how long does the
        + *  physical space. The p5.Reverb has parameters for Time (how long does the
          *  reverb last) and decayRate (how much the sound decays with each echo)
          *  that can be set with the .set() or .process() methods. The p5.Convolver
          *  extends p5.Reverb allowing you to recreate the sound of actual physical
        @@ -9727,7 +9727,7 @@ function () {
             soundLoop_classCallCheck(this, SoundLoop);
         
             /**
        -     * Getters and Setters, setting any paramter will result in a change in the clock's
        +     * Getters and Setters, setting any parameter will result in a change in the clock's
              * frequency, that will be reflected after the next callback
              * beats per minute (defaults to 60)
              * @property {Number} bpm
        @@ -10110,7 +10110,7 @@ function (_Effect) {
               this.set(attack, knee, ratio, threshold, release);
             }
             /**
        -     * Set the paramters of a compressor.
        +     * Set the parameters of a compressor.
              * @method  set
              * @for p5.Compressor
              * @param {Number} attack     The amount of time (in seconds) to reduce the gain by 10dB,
        diff --git a/package-lock.json b/package-lock.json
        index e9291f1fc6..c4b5c08bcb 100644
        --- a/package-lock.json
        +++ b/package-lock.json
        @@ -1,12 +1,12 @@
         {
           "name": "p5",
        -  "version": "1.11.7",
        +  "version": "1.11.8",
           "lockfileVersion": 3,
           "requires": true,
           "packages": {
             "": {
               "name": "p5",
        -      "version": "1.11.7",
        +      "version": "1.11.8",
               "license": "LGPL-2.1",
               "devDependencies": {
                 "@babel/core": "^7.7.7",
        @@ -2590,10 +2590,11 @@
               }
             },
             "node_modules/ansi-colors": {
        -      "version": "4.1.1",
        -      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
        -      "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
        +      "version": "4.1.3",
        +      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
        +      "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
               "dev": true,
        +      "license": "MIT",
               "engines": {
                 "node": ">=6"
               }
        @@ -5236,10 +5237,11 @@
               "dev": true
             },
             "node_modules/diff": {
        -      "version": "5.0.0",
        -      "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
        -      "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
        +      "version": "5.2.0",
        +      "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz",
        +      "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==",
               "dev": true,
        +      "license": "BSD-3-Clause",
               "engines": {
                 "node": ">=0.3.1"
               }
        @@ -5365,10 +5367,11 @@
               }
             },
             "node_modules/elliptic": {
        -      "version": "6.6.0",
        -      "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.0.tgz",
        -      "integrity": "sha512-dpwoQcLc/2WLQvJvLRHKZ+f9FgOdjnq11rurqwekGQygGPsYSK29OMMD2WalatiqQ+XGFDglTNixpPfI+lpaAA==",
        +      "version": "6.6.1",
        +      "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz",
        +      "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==",
               "dev": true,
        +      "license": "MIT",
               "dependencies": {
                 "bn.js": "^4.11.9",
                 "brorand": "^1.1.0",
        @@ -11098,32 +11101,32 @@
               "dev": true
             },
             "node_modules/mocha": {
        -      "version": "10.2.0",
        -      "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz",
        -      "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==",
        +      "version": "10.8.2",
        +      "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz",
        +      "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==",
               "dev": true,
        +      "license": "MIT",
               "dependencies": {
        -        "ansi-colors": "4.1.1",
        -        "browser-stdout": "1.3.1",
        -        "chokidar": "3.5.3",
        -        "debug": "4.3.4",
        -        "diff": "5.0.0",
        -        "escape-string-regexp": "4.0.0",
        -        "find-up": "5.0.0",
        -        "glob": "7.2.0",
        -        "he": "1.2.0",
        -        "js-yaml": "4.1.0",
        -        "log-symbols": "4.1.0",
        -        "minimatch": "5.0.1",
        -        "ms": "2.1.3",
        -        "nanoid": "3.3.3",
        -        "serialize-javascript": "6.0.0",
        -        "strip-json-comments": "3.1.1",
        -        "supports-color": "8.1.1",
        -        "workerpool": "6.2.1",
        -        "yargs": "16.2.0",
        -        "yargs-parser": "20.2.4",
        -        "yargs-unparser": "2.0.0"
        +        "ansi-colors": "^4.1.3",
        +        "browser-stdout": "^1.3.1",
        +        "chokidar": "^3.5.3",
        +        "debug": "^4.3.5",
        +        "diff": "^5.2.0",
        +        "escape-string-regexp": "^4.0.0",
        +        "find-up": "^5.0.0",
        +        "glob": "^8.1.0",
        +        "he": "^1.2.0",
        +        "js-yaml": "^4.1.0",
        +        "log-symbols": "^4.1.0",
        +        "minimatch": "^5.1.6",
        +        "ms": "^2.1.3",
        +        "serialize-javascript": "^6.0.2",
        +        "strip-json-comments": "^3.1.1",
        +        "supports-color": "^8.1.1",
        +        "workerpool": "^6.5.1",
        +        "yargs": "^16.2.0",
        +        "yargs-parser": "^20.2.9",
        +        "yargs-unparser": "^2.0.0"
               },
               "bin": {
                 "_mocha": "bin/_mocha",
        @@ -11131,10 +11134,6 @@
               },
               "engines": {
                 "node": ">= 14.0.0"
        -      },
        -      "funding": {
        -        "type": "opencollective",
        -        "url": "https://opencollective.com/mochajs"
               }
             },
             "node_modules/mocha/node_modules/ansi-regex": {
        @@ -11167,6 +11166,16 @@
               "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
               "dev": true
             },
        +    "node_modules/mocha/node_modules/brace-expansion": {
        +      "version": "2.0.1",
        +      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
        +      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
        +      "dev": true,
        +      "license": "MIT",
        +      "dependencies": {
        +        "balanced-match": "^1.0.0"
        +      }
        +    },
             "node_modules/mocha/node_modules/chalk": {
               "version": "4.1.2",
               "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
        @@ -11219,12 +11228,13 @@
               }
             },
             "node_modules/mocha/node_modules/debug": {
        -      "version": "4.3.4",
        -      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
        -      "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
        +      "version": "4.4.0",
        +      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
        +      "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
               "dev": true,
        +      "license": "MIT",
               "dependencies": {
        -        "ms": "2.1.2"
        +        "ms": "^2.1.3"
               },
               "engines": {
                 "node": ">=6.0"
        @@ -11235,12 +11245,6 @@
                 }
               }
             },
        -    "node_modules/mocha/node_modules/debug/node_modules/ms": {
        -      "version": "2.1.2",
        -      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
        -      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
        -      "dev": true
        -    },
             "node_modules/mocha/node_modules/emoji-regex": {
               "version": "8.0.0",
               "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
        @@ -11276,37 +11280,26 @@
               }
             },
             "node_modules/mocha/node_modules/glob": {
        -      "version": "7.2.0",
        -      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
        -      "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
        +      "version": "8.1.0",
        +      "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
        +      "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
        +      "deprecated": "Glob versions prior to v9 are no longer supported",
               "dev": true,
        +      "license": "ISC",
               "dependencies": {
                 "fs.realpath": "^1.0.0",
                 "inflight": "^1.0.4",
                 "inherits": "2",
        -        "minimatch": "^3.0.4",
        -        "once": "^1.3.0",
        -        "path-is-absolute": "^1.0.0"
        +        "minimatch": "^5.0.1",
        +        "once": "^1.3.0"
               },
               "engines": {
        -        "node": "*"
        +        "node": ">=12"
               },
               "funding": {
                 "url": "https://github.com/sponsors/isaacs"
               }
             },
        -    "node_modules/mocha/node_modules/glob/node_modules/minimatch": {
        -      "version": "3.1.2",
        -      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
        -      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
        -      "dev": true,
        -      "dependencies": {
        -        "brace-expansion": "^1.1.7"
        -      },
        -      "engines": {
        -        "node": "*"
        -      }
        -    },
             "node_modules/mocha/node_modules/has-flag": {
               "version": "4.0.0",
               "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
        @@ -11369,10 +11362,11 @@
               }
             },
             "node_modules/mocha/node_modules/minimatch": {
        -      "version": "5.0.1",
        -      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
        -      "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
        +      "version": "5.1.6",
        +      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
        +      "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
               "dev": true,
        +      "license": "ISC",
               "dependencies": {
                 "brace-expansion": "^2.0.1"
               },
        @@ -11380,15 +11374,6 @@
                 "node": ">=10"
               }
             },
        -    "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": {
        -      "version": "2.0.1",
        -      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
        -      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
        -      "dev": true,
        -      "dependencies": {
        -        "balanced-match": "^1.0.0"
        -      }
        -    },
             "node_modules/mocha/node_modules/ms": {
               "version": "2.1.3",
               "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
        @@ -11523,10 +11508,11 @@
               }
             },
             "node_modules/mocha/node_modules/yargs-parser": {
        -      "version": "20.2.4",
        -      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
        -      "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
        +      "version": "20.2.9",
        +      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
        +      "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
               "dev": true,
        +      "license": "ISC",
               "engines": {
                 "node": ">=10"
               }
        @@ -11597,18 +11583,6 @@
               "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
               "dev": true
             },
        -    "node_modules/nanoid": {
        -      "version": "3.3.3",
        -      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
        -      "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==",
        -      "dev": true,
        -      "bin": {
        -        "nanoid": "bin/nanoid.cjs"
        -      },
        -      "engines": {
        -        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
        -      }
        -    },
             "node_modules/natural-compare": {
               "version": "1.4.0",
               "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
        @@ -15807,10 +15781,11 @@
               }
             },
             "node_modules/serialize-javascript": {
        -      "version": "6.0.0",
        -      "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
        -      "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
        +      "version": "6.0.2",
        +      "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
        +      "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
               "dev": true,
        +      "license": "BSD-3-Clause",
               "dependencies": {
                 "randombytes": "^2.1.0"
               }
        @@ -17536,10 +17511,11 @@
               }
             },
             "node_modules/workerpool": {
        -      "version": "6.2.1",
        -      "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
        -      "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==",
        -      "dev": true
        +      "version": "6.5.1",
        +      "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz",
        +      "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==",
        +      "dev": true,
        +      "license": "Apache-2.0"
             },
             "node_modules/wrap-ansi": {
               "version": "6.2.0",
        diff --git a/package.json b/package.json
        index 132b2ad0e4..24646e81a8 100644
        --- a/package.json
        +++ b/package.json
        @@ -24,7 +24,7 @@
               "node --require @babel/register ./utils/sample-linter.js"
             ]
           },
        -  "version": "1.11.7",
        +  "version": "1.11.8",
           "devDependencies": {
             "@babel/core": "^7.7.7",
             "@babel/preset-env": "^7.10.2",
        diff --git a/src/accessibility/outputs.js b/src/accessibility/outputs.js
        index 1680f18e31..d712c008bc 100644
        --- a/src/accessibility/outputs.js
        +++ b/src/accessibility/outputs.js
        @@ -461,7 +461,7 @@ p5.prototype._accsOutput = function(f, args) {
           if (f === 'line') {
             //make color stroke
             include.color = this.ingredients.colors.stroke;
        -    //get lenght
        +    //get length
             include.length = Math.round(this.dist(args[0], args[1], args[2], args[3]));
             //get position of end points
             let p1 = this._getPos(args[0], [1]);
        diff --git a/src/core/friendly_errors/sketch_reader.js b/src/core/friendly_errors/sketch_reader.js
        index 01e0076edc..b70e86bf96 100644
        --- a/src/core/friendly_errors/sketch_reader.js
        +++ b/src/core/friendly_errors/sketch_reader.js
        @@ -202,7 +202,7 @@ if (typeof IS_MINIFIED !== 'undefined') {
         
           /**
            * Converts code written by the user to an array
        -   * every element of which is a seperate line of code.
        +   * every element of which is a separate line of code.
            *
            * @method codeToLines
            * @private
        diff --git a/src/core/p5.Renderer.js b/src/core/p5.Renderer.js
        index 41417b3606..21ce3bd64b 100644
        --- a/src/core/p5.Renderer.js
        +++ b/src/core/p5.Renderer.js
        @@ -86,9 +86,7 @@ class Renderer extends p5.Element {
                 _textAlign: this._textAlign,
                 _textBaseline: this._textBaseline,
                 _textStyle: this._textStyle,
        -        _textWrap: this._textWrap,
        -        _colorMode: this._colorMode,
        -        _colorMaxes: this._colorMaxes.slice()
        +        _textWrap: this._textWrap
               }
             };
           }
        diff --git a/src/dom/dom.js b/src/dom/dom.js
        index 6bafb5bae4..a5e1c54a5c 100644
        --- a/src/dom/dom.js
        +++ b/src/dom/dom.js
        @@ -2023,7 +2023,7 @@ p5.prototype.createInput = function (value = '', type = 'text') {
          *     let y = i * 20;
          *
          *     // Draw the image.
        - *     image(img, 0, y, 100, 100);
        + *     image(images[i], 0, y, 100, 100);
          *   }
          *
          *   describe('A gray square with a file input beneath it. If the user selects multiple image files to load, they are displayed on the square.');
        @@ -2082,15 +2082,6 @@ function createMedia(pInst, type, src, callback) {
             elt.appendChild(sourceEl);
           }
         
        -  // If callback is provided, attach to element
        -  if (typeof callback === 'function') {
        -    const callbackHandler = () => {
        -      callback();
        -      elt.removeEventListener('canplaythrough', callbackHandler);
        -    };
        -    elt.addEventListener('canplaythrough', callbackHandler);
        -  }
        -
           const mediaEl = addElement(elt, pInst, true);
           mediaEl.loadedmetadata = false;
         
        @@ -2109,6 +2100,15 @@ function createMedia(pInst, type, src, callback) {
             mediaEl.loadedmetadata = true;
           });
         
        +  // If callback is provided, attach to element
        +  if (typeof callback === 'function') {
        +    const callbackHandler = () => {
        +      callback(mediaEl);
        +      elt.removeEventListener('canplaythrough', callbackHandler);
        +    };
        +    elt.addEventListener('canplaythrough', callbackHandler);
        +  }
        +
           return mediaEl;
         }
         
        diff --git a/src/image/p5.Image.js b/src/image/p5.Image.js
        index 8ab3175afc..1db788cd9c 100644
        --- a/src/image/p5.Image.js
        +++ b/src/image/p5.Image.js
        @@ -798,7 +798,7 @@ p5.Image = class {
            *   // Display the image.
            *   image(img, 17, 17);
            *
        -   *   describe('A square with a horiztonal color gradient from black to white drawn on a gray background.');
        +   *   describe('A square with a horizontal color gradient from black to white drawn on a gray background.');
            * }
            * </code>
            * </div>
        diff --git a/src/image/pixels.js b/src/image/pixels.js
        index effda98199..aeaf6761a2 100644
        --- a/src/image/pixels.js
        +++ b/src/image/pixels.js
        @@ -1083,7 +1083,7 @@ p5.prototype.loadPixels = function(...args) {
          *   // Update the canvas.
          *   updatePixels();
          *
        - *   describe('A horiztonal color gradient from black to white.');
        + *   describe('A horizontal color gradient from black to white.');
          * }
          * </code>
          * </div>
        diff --git a/src/io/p5.Table.js b/src/io/p5.Table.js
        index 4e05615bee..cc0e3f92e9 100644
        --- a/src/io/p5.Table.js
        +++ b/src/io/p5.Table.js
        @@ -1196,7 +1196,7 @@ p5.Table = class {
          *
          * function preload() {
          *   // table is comma separated value "CSV"
        - *   // and has specifiying header for column labels
        + *   // and has specifying header for column labels
          *   table = loadTable('assets/mammals.csv', 'csv', 'header');
          * }
          *
        @@ -1303,7 +1303,7 @@ p5.Table = class {
          *
          * function preload() {
          *   // table is comma separated value "CSV"
        - *   // and has specifiying header for column labels
        + *   // and has specifying header for column labels
          *   table = loadTable('assets/mammals.csv', 'csv', 'header');
          * }
          *
        diff --git a/src/webgl/shaders/lighting.glsl b/src/webgl/shaders/lighting.glsl
        index b66ac083d1..4110fcf2a4 100644
        --- a/src/webgl/shaders/lighting.glsl
        +++ b/src/webgl/shaders/lighting.glsl
        @@ -108,7 +108,7 @@ vec2 mapTextureToNormal( vec3 v ){
         
         
         vec3 calculateImageDiffuse(vec3 vNormal, vec3 vViewPosition, float metallic){
        -  // make 2 seperate builds 
        +  // make 2 separate builds 
           vec3 worldCameraPosition =  vec3(0.0, 0.0, 0.0);  // hardcoded world camera position
           vec3 worldNormal = normalize(vNormal * uCameraRotation);
           vec2 newTexCoor = mapTextureToNormal( worldNormal );
        diff --git a/tasks/build/browserify.js b/tasks/build/browserify.js
        index 2d3fa59245..0af45c985a 100644
        --- a/tasks/build/browserify.js
        +++ b/tasks/build/browserify.js
        @@ -37,7 +37,7 @@ module.exports = function(grunt) {
               if (isDev) {
                 globalVars['P5_DEV_BUILD'] = () => true;
               }
        -      // Invoke Browserify programatically to bundle the code
        +      // Invoke Browserify programmatically to bundle the code
               let browserified = browserify(srcFilePath, {
                 standalone: 'p5',
                 insertGlobalVars: globalVars
        diff --git a/tasks/build/combineModules.js b/tasks/build/combineModules.js
        index 17db3f898b..6fb699a66c 100644
        --- a/tasks/build/combineModules.js
        +++ b/tasks/build/combineModules.js
        @@ -52,7 +52,7 @@ module.exports = function(grunt) {
               // Target file path
               const libFilePath = path.resolve('lib/modules/' + filename);
         
        -      // Invoke Browserify programatically to bundle the code
        +      // Invoke Browserify programmatically to bundle the code
               let browseified = browserify(tempFilePath, {
                 standalone: 'p5'
               });
        diff --git a/test/manual-test-examples/tutorials/DOM-extensions/6/sketch.js b/test/manual-test-examples/tutorials/DOM-extensions/6/sketch.js
        index 1bf5484a72..d1df4138ad 100644
        --- a/test/manual-test-examples/tutorials/DOM-extensions/6/sketch.js
        +++ b/test/manual-test-examples/tutorials/DOM-extensions/6/sketch.js
        @@ -35,7 +35,7 @@ function draw() {
           //drawEllipseCanvas();
         }
         
        -// Addtional drawing functions.
        +// Additional drawing functions.
         function drawEllipseCanvas() {
           background(120, 180, 200);
           ellipse(width / 2, height / 2, 100, 100);
        diff --git a/test/manual-test-examples/tutorials/DOM-extensions/7/sketch.js b/test/manual-test-examples/tutorials/DOM-extensions/7/sketch.js
        index 3ad19088fe..c43241d7b2 100644
        --- a/test/manual-test-examples/tutorials/DOM-extensions/7/sketch.js
        +++ b/test/manual-test-examples/tutorials/DOM-extensions/7/sketch.js
        @@ -39,7 +39,7 @@ function draw() {
           drawRectCanvas();
         }
         
        -// Addtional drawing functions.
        +// Additional drawing functions.
         function drawEllipseCanvas() {
           background(120, 180, 200);
           ellipse(width / 2, height / 2, 100, 100);
        diff --git a/test/unit/assets/books.xml b/test/unit/assets/books.xml
        index baf002f7f7..3d54056b05 100644
        --- a/test/unit/assets/books.xml
        +++ b/test/unit/assets/books.xml
        @@ -83,7 +83,7 @@
               <genre>Science Fiction</genre>
               <price>6.95</price>
               <publish_date>2000-11-02</publish_date>
        -      <description>After an inadvertant trip through a Heisenberg
        +      <description>After an inadvertent trip through a Heisenberg
               Uncertainty Device, James Salway discovers the problems
               of being quantum.</description>
            </book>
        @@ -117,4 +117,4 @@
               integrated into a comprehensive development
               environment.</description>
            </book>
        -</catalog>
        \ No newline at end of file
        +</catalog>
        diff --git a/test/unit/core/environment.js b/test/unit/core/environment.js
        index 4ab600a0e9..ed40189581 100644
        --- a/test/unit/core/environment.js
        +++ b/test/unit/core/environment.js
        @@ -41,7 +41,7 @@ suite('Environment', function() {
                     frames += 1;
                     assert.equal(myp5.frameCount, frames);
                     if (frames === start + 5) {
        -              // Test 5 seperate redraws
        +              // Test 5 separate redraws
                       myp5.noLoop();
                       setTimeout(myp5.redraw.bind(myp5), 10);
                       setTimeout(myp5.redraw.bind(myp5), 20);
        diff --git a/test/unit/core/error_helpers.js b/test/unit/core/error_helpers.js
        index 75ad06e31f..ccdd9d3047 100644
        --- a/test/unit/core/error_helpers.js
        +++ b/test/unit/core/error_helpers.js
        @@ -237,7 +237,7 @@ suite('Error Helpers', function() {
         
           suite('validateParameters: argument tree', function() {
             // should not throw a validation error for the same kind of wrong args
        -    // more than once. This prevents repetetive validation logs for a
        +    // more than once. This prevents repetitive validation logs for a
             // function that is called in a loop or draw()
             testUnMinified(
               'no repeated validation error for the same wrong arguments',
        @@ -440,7 +440,7 @@ suite('Error Helpers', function() {
               }
             );
         
        -    testUnMinified('detects spelling + captialization mistakes', function() {
        +    testUnMinified('detects spelling + capitalization mistakes', function() {
               const logMsg = help(new ReferenceError('RandomGossian is not defined'));
               assert.match(
                 logMsg,
        @@ -522,7 +522,7 @@ suite('Error Helpers', function() {
           });
         });
         
        -// seperating in another suite because these don't need to initialize myp5
        +// separating in another suite because these don't need to initialize myp5
         // for each test. Instead they initialize p5 in the iframe. These tests are
         // also slower than the above ones.
         suite('Global Error Handling', function() {
        @@ -566,7 +566,7 @@ suite('Global Error Handling', function() {
             return iframe;
           };
         
        -  testUnMinified('identifies errors happenning internally', function() {
        +  testUnMinified('identifies errors happening internally', function() {
             return new Promise(function(resolve) {
               // quite an unusual way to test, but the error listener doesn't work
               // under mocha. Also the stacktrace gets filled with mocha internal
        @@ -590,7 +590,7 @@ suite('Global Error Handling', function() {
           });
         
           testUnMinified(
        -    'identifies errors happenning internally in ES6 classes',
        +    'identifies errors happening internally in ES6 classes',
             function() {
               return new Promise(function(resolve) {
                 prepSyntaxTest(
        diff --git a/test/unit/core/rendering.js b/test/unit/core/rendering.js
        index 2f917a2ace..8e932761ed 100644
        --- a/test/unit/core/rendering.js
        +++ b/test/unit/core/rendering.js
        @@ -174,14 +174,14 @@ suite('Rendering', function() {
                 webglMethod + '() should throw a WEBGL assertion Error',
                 (function(webglMethod) {
                   return function() {
        -            var validateParamters = myp5.validateParameters;
        +            var validateParameters = myp5.validateParameters;
                     myp5.validateParameters = false;
                     try {
                       expect(function() {
                         myp5[webglMethod].call(myp5);
                       }).to.throw(Error, /is only supported in WEBGL mode/);
                     } finally {
        -              myp5.validateParameters = validateParamters;
        +              myp5.validateParameters = validateParameters;
                     }
                   };
                 })(webglMethod)
        
        From 64bc57aa1d62050ba19f8b9deac27ed061f9a259 Mon Sep 17 00:00:00 2001
        From: Quinton Ashley <quinton-ashley@users.noreply.github.com>
        Date: Sat, 7 Jun 2025 18:21:01 -0500
        Subject: [PATCH 188/282] Respect p5.disableFriendlyErrors
        
        Respect `p5.disableFriendlyErrors` setting when overriding p5 global variables
        ---
         src/core/main.js | 8 +++++---
         1 file changed, 5 insertions(+), 3 deletions(-)
        
        diff --git a/src/core/main.js b/src/core/main.js
        index 4e9684dc80..bd2cd2055a 100644
        --- a/src/core/main.js
        +++ b/src/core/main.js
        @@ -848,9 +848,11 @@ class p5 {
                         value: newValue,
                         writable: true
                       });
        -              log(
        -                `You just changed the value of "${prop}", which was a p5 function. This could cause problems later if you're not careful.`
        -              );
        +              if (!p5.disableFriendlyErrors) {
        +                log(
        +                  `You just changed the value of "${prop}", which was a p5 function. This could cause problems later if you're not careful.`
        +                );
        +              }
                     }
                   });
                 } catch (e) {
        
        From 2a4df66011733ae826301c1d71daf7b022c5db61 Mon Sep 17 00:00:00 2001
        From: kit <1304340+ksen0@users.noreply.github.com>
        Date: Tue, 10 Jun 2025 07:25:38 +0200
        Subject: [PATCH 189/282] Update stewards-update.yml to fix typo and include
         token
        
        ---
         .github/workflows/stewards-update.yml | 3 ++-
         1 file changed, 2 insertions(+), 1 deletion(-)
        
        diff --git a/.github/workflows/stewards-update.yml b/.github/workflows/stewards-update.yml
        index ed6ad9668f..930a4ac63a 100644
        --- a/.github/workflows/stewards-update.yml
        +++ b/.github/workflows/stewards-update.yml
        @@ -29,5 +29,6 @@ jobs:
                   commit-message: "Update README table from stewards.yml"
                   branch: update-readme-table
                   title: 'chore: update README table from stewards.yml'
        -          body: 'This PR updates the README.md table to refelct changes in stewards.yml.'
        +          body: 'This PR updates the README.md table to reflect changes in stewards.yml.'
                   add: README.md
        +          token: ${{ secrets.ACCESS_TOKEN }}
        
        From c87081f528bfc789516e00c96e56ff889c6bc6f7 Mon Sep 17 00:00:00 2001
        From: kit <1304340+ksen0@users.noreply.github.com>
        Date: Tue, 10 Jun 2025 07:38:13 +0200
        Subject: [PATCH 190/282] Added p5.js-website accessibility steward
         stewards.yml
        
        Adding @coseeian community as Web Accessibility Stewards for the p5.js-website
        ---
         stewards.yml | 4 +++-
         1 file changed, 3 insertions(+), 1 deletion(-)
        
        diff --git a/stewards.yml b/stewards.yml
        index e1465bec97..da59ad2da6 100644
        --- a/stewards.yml
        +++ b/stewards.yml
        @@ -81,4 +81,6 @@ takshittt:
         clairep94:
           - p5.js-website
         
        -
        +coseeian:
        +  - Accessibility:
        +      - p5.js-website
        
        From de689ab684f00a7414c3c9fdc1622b24b4f3ee5f Mon Sep 17 00:00:00 2001
        From: ksen0 <katie.kuksenok@gmail.com>
        Date: Tue, 10 Jun 2025 08:06:45 +0200
        Subject: [PATCH 191/282] Enable workflow_dispatch trigger on stewards table
         update
        
        ---
         .github/workflows/stewards-update.yml | 1 +
         1 file changed, 1 insertion(+)
        
        diff --git a/.github/workflows/stewards-update.yml b/.github/workflows/stewards-update.yml
        index 930a4ac63a..04d4ca3f82 100644
        --- a/.github/workflows/stewards-update.yml
        +++ b/.github/workflows/stewards-update.yml
        @@ -5,6 +5,7 @@ on:
             branches: [main]
             paths:
               - stewards.yml
        +    workflow_dispatch:
         
         jobs:
           build:
        
        From c5db908b3482d2c9589f7c8e3e10ecc10bd565c0 Mon Sep 17 00:00:00 2001
        From: kit <1304340+ksen0@users.noreply.github.com>
        Date: Tue, 10 Jun 2025 13:35:00 +0200
        Subject: [PATCH 192/282] Update stewards-update.yml to only make PR with
         README
        
        ---
         .github/workflows/stewards-update.yml | 6 ++++++
         1 file changed, 6 insertions(+)
        
        diff --git a/.github/workflows/stewards-update.yml b/.github/workflows/stewards-update.yml
        index 04d4ca3f82..d8ef9de2ca 100644
        --- a/.github/workflows/stewards-update.yml
        +++ b/.github/workflows/stewards-update.yml
        @@ -24,6 +24,12 @@ jobs:
               - name: Run table generator
                 run: node utils/stewards-table.js
                 
        +      - name: Reset all changes except README.md
        +        run: |
        +          git restore --staged .
        +          git add README.md
        +          git checkout -- .
        +          
               - name: Create Pull Request
                 uses: peter-evans/create-pull-request@v5
                 with:
        
        From 87538dd3d9eab5cb07caed31140f3faa047b4732 Mon Sep 17 00:00:00 2001
        From: ksen0 <ksen0@users.noreply.github.com>
        Date: Tue, 10 Jun 2025 06:17:09 +0000
        Subject: [PATCH 193/282] Update README table from stewards.yml
        
        ---
         .github/workflows/stewards-update.yml | 2 +-
         README.md                             | 1 +
         2 files changed, 2 insertions(+), 1 deletion(-)
        
        diff --git a/.github/workflows/stewards-update.yml b/.github/workflows/stewards-update.yml
        index 04d4ca3f82..a3a6c57b09 100644
        --- a/.github/workflows/stewards-update.yml
        +++ b/.github/workflows/stewards-update.yml
        @@ -5,7 +5,7 @@ on:
             branches: [main]
             paths:
               - stewards.yml
        -    workflow_dispatch:
        +  workflow_dispatch:
         
         jobs:
           build:
        diff --git a/README.md b/README.md
        index 8de3d5a846..9695521337 100644
        --- a/README.md
        +++ b/README.md
        @@ -93,6 +93,7 @@ Lead/Mentor Alumni
         |------|-------------|
         | Maintainers | [@davepagurek](https://github.com/davepagurek), [@ksen0](https://github.com/ksen0), [@limzykenneth](https://github.com/limzykenneth), [@perminder-17](https://github.com/perminder-17), [@qianqianye](https://github.com/qianqianye) |
         | Accessibility | [@calebfoss](https://github.com/calebfoss) |
        +| Accessibility (p5.js-website) | [@coseeian](https://github.com/coseeian) |
         | Color | [@limzykenneth](https://github.com/limzykenneth) |
         | Core | [@davepagurek](https://github.com/davepagurek) |
         | DevOps | [@Vaivaswat2244](https://github.com/Vaivaswat2244), [@error-four-o-four](https://github.com/error-four-o-four), [@limzykenneth](https://github.com/limzykenneth), [@lirenjie95](https://github.com/lirenjie95) |
        
        From 7d82a7fd714e0b0965318abd9228146f02779e66 Mon Sep 17 00:00:00 2001
        From: Ben Gilbert <bensgilbert@outlook.com>
        Date: Tue, 10 Jun 2025 16:00:50 +0100
        Subject: [PATCH 194/282] merge main  (#2)
        
        * Fixed loop variable in createFileInput() docs (dom.js)
        
        * Bump serialize-javascript and mocha
        
        Bumps [serialize-javascript](https://github.com/yahoo/serialize-javascript) to 6.0.2 and updates ancestor dependency [mocha](https://github.com/mochajs/mocha). These dependencies need to be updated together.
        
        
        Updates `serialize-javascript` from 6.0.0 to 6.0.2
        - [Release notes](https://github.com/yahoo/serialize-javascript/releases)
        - [Commits](https://github.com/yahoo/serialize-javascript/compare/v6.0.0...v6.0.2)
        
        Updates `mocha` from 10.2.0 to 10.8.2
        - [Release notes](https://github.com/mochajs/mocha/releases)
        - [Changelog](https://github.com/mochajs/mocha/blob/main/CHANGELOG.md)
        - [Commits](https://github.com/mochajs/mocha/compare/v10.2.0...v10.8.2)
        
        ---
        updated-dependencies:
        - dependency-name: serialize-javascript
          dependency-type: indirect
        - dependency-name: mocha
          dependency-type: direct:development
        ...
        
        Signed-off-by: dependabot[bot] <support@github.com>
        
        * Bump elliptic from 6.6.0 to 6.6.1
        
        Bumps [elliptic](https://github.com/indutny/elliptic) from 6.6.0 to 6.6.1.
        - [Commits](https://github.com/indutny/elliptic/compare/v6.6.0...v6.6.1)
        
        ---
        updated-dependencies:
        - dependency-name: elliptic
          dependency-type: indirect
        ...
        
        Signed-off-by: dependabot[bot] <support@github.com>
        
        * added instance of video in callback
        
        * Revert "fix: push() ignoring the ColorMode #7402"
        
        * Fix typos
        
        * docs: update README.md [skip ci]
        
        * docs: update .all-contributorsrc [skip ci]
        
        * docs: update README.md [skip ci]
        
        * docs: update .all-contributorsrc [skip ci]
        
        * docs: update README.md [skip ci]
        
        * docs: update .all-contributorsrc [skip ci]
        
        * docs: update README.md [skip ci]
        
        * docs: update .all-contributorsrc [skip ci]
        
        * Add @dpanshug for doc
        
        * Add stewards list and updating action
        
        * Udpate stewardship guidelines
        
        * Update steward_guidelines.md
        
        * Update stewards.yml
        
        * Update contributor_docs/steward_guidelines.md
        
        Co-authored-by: Dave Pagurek <dave@davepagurek.com>
        
        * Update contributor_docs/steward_guidelines.md
        
        Co-authored-by: Kenneth Lim <hello@limzykenneth.com>
        
        * Update contributor_docs/steward_guidelines.md
        
        Co-authored-by: Kenneth Lim <hello@limzykenneth.com>
        
        * Clarified to the stewardship responsibilities list
        
        * Update reference.js
        
        * Update reference.js.map
        
        * Update books.xml
        
        * Update error_helpers.js
        
        * Update sketch.js
        
        * Update sketch.js
        
        * Update p5.Table.js
        
        * Update p5.Image.js
        
        * Update pixels.js
        
        * Remove generated reference.js.map from PR
        
        * Restore generated file to match upstream main
        
        * docs: update README.md [skip ci]
        
        * docs: update .all-contributorsrc [skip ci]
        
        * Fixes in guideline and new stewards
        
        * Add onboarding to steward guideline
        
        * 1.11.8
        
        * Clean up stewards table generation
        
        * Update issue labeler to include new steward areas
        
        * docs: update README.md [skip ci]
        
        * docs: update .all-contributorsrc [skip ci]
        
        * Respect p5.disableFriendlyErrors
        
        Respect `p5.disableFriendlyErrors` setting when overriding p5 global variables
        
        * Update stewards-update.yml to fix typo and include token
        
        * Added p5.js-website accessibility steward stewards.yml
        
        Adding @coseeian community as Web Accessibility Stewards for the p5.js-website
        
        * Enable workflow_dispatch trigger on stewards table update
        
        * Update stewards-update.yml to only make PR with README
        
        * Update README table from stewards.yml
        
        ---------
        
        Signed-off-by: dependabot[bot] <support@github.com>
        Co-authored-by: Andrew McWhae <andrew.mcwhae@gmail.com>
        Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
        Co-authored-by: Soubhagya Mohapatra <ssm.allrounder@gmail.com>
        Co-authored-by: kit <1304340+ksen0@users.noreply.github.com>
        Co-authored-by: omahs <73983677+omahs@users.noreply.github.com>
        Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
        Co-authored-by: raclim <43053081+raclim@users.noreply.github.com>
        Co-authored-by: Perminder Singh <127239756+perminder-17@users.noreply.github.com>
        Co-authored-by: ksen0 <katie.kuksenok@gmail.com>
        Co-authored-by: Dave Pagurek <dave@davepagurek.com>
        Co-authored-by: Kenneth Lim <hello@limzykenneth.com>
        Co-authored-by: sukrucildirr <sukrucildirr@gmail.com>
        Co-authored-by: Quinton Ashley <quinton-ashley@users.noreply.github.com>
        Co-authored-by: ksen0 <ksen0@users.noreply.github.com>
        ---
         .github/ISSUE_TEMPLATE/2-found-a-bug.yml |  8 +--
         .github/labeler.yml                      | 10 ++-
         .github/workflows/stewards-update.yml    | 41 +++++++++++
         README.md                                | 45 +++++++------
         contributor_docs/steward_guidelines.md   | 64 +++++++++++++++++-
         src/core/main.js                         |  8 ++-
         stewards.yml                             | 86 ++++++++++++++++++++++++
         utils/stewards-table.js                  | 56 +++++++++++++++
         8 files changed, 287 insertions(+), 31 deletions(-)
         create mode 100644 .github/workflows/stewards-update.yml
         create mode 100644 stewards.yml
         create mode 100644 utils/stewards-table.js
        
        diff --git a/.github/ISSUE_TEMPLATE/2-found-a-bug.yml b/.github/ISSUE_TEMPLATE/2-found-a-bug.yml
        index dd06e29725..948c2f1c37 100644
        --- a/.github/ISSUE_TEMPLATE/2-found-a-bug.yml
        +++ b/.github/ISSUE_TEMPLATE/2-found-a-bug.yml
        @@ -19,11 +19,11 @@ body:
                 - label: Math
                 - label: Typography
                 - label: Utilities
        +        - label: p5.strands
                 - label: WebGL
        -        - label: Build process
        -        - label: Unit testing
        -        - label: Internationalization
        -        - label: Friendly errors
        +        - label: DevOps, Build process, Unit testing
        +        - label: Internationalization (i18n)
        +        - label: Friendly Errors
                 - label: Other (specify if possible)
         - type: input
           attributes:
        diff --git a/.github/labeler.yml b/.github/labeler.yml
        index daa971834c..a593e7c8e9 100644
        --- a/.github/labeler.yml
        +++ b/.github/labeler.yml
        @@ -22,11 +22,17 @@
           - '\[[xX]\]\s*Utilities'
         "Area:WebGL":
           - '\[[xX]\]\s*WebGL'
        +"Internationalization":
        +  - '\[[xX]\]\s*Internationalization'
        +"DevOps":
        +  - '\[[xX]\]\s*Build Process'
        +"DevOps":
        +  - '\[[xX]\]\s*Unit Testing'
         "Build Process":
           - '\[[xX]\]\s*Build Process'
         "Unit Testing":
           - '\[[xX]\]\s*Unit Testing'
        -"Internationalization":
        -  - '\[[xX]\]\s*Internationalization'
         "Friendly Errors":
           - '\[[xX]\]\s*Friendly Errors'
        +"p5.strands":
        +  - '\[[xX]\]\s*p5.strands'
        diff --git a/.github/workflows/stewards-update.yml b/.github/workflows/stewards-update.yml
        new file mode 100644
        index 0000000000..3d2b56ea33
        --- /dev/null
        +++ b/.github/workflows/stewards-update.yml
        @@ -0,0 +1,41 @@
        +name: Update Steward Table in README
        +
        +on:
        +  push:
        +    branches: [main]
        +    paths:
        +      - stewards.yml
        +  workflow_dispatch:
        +
        +jobs:
        +  build:
        +    runs-on: ubuntu-latest
        +    steps:
        +      - uses: actions/checkout@v3
        +
        +      - name: Setup Node
        +        uses: actions/setup-node@v4
        +        with:
        +          node-version: '20'
        +
        +      - name: Install dependencies
        +        run: npm install js-yaml
        +
        +      - name: Run table generator
        +        run: node utils/stewards-table.js
        +        
        +      - name: Reset all changes except README.md
        +        run: |
        +          git restore --staged .
        +          git add README.md
        +          git checkout -- .
        +          
        +      - name: Create Pull Request
        +        uses: peter-evans/create-pull-request@v5
        +        with:
        +          commit-message: "Update README table from stewards.yml"
        +          branch: update-readme-table
        +          title: 'chore: update README table from stewards.yml'
        +          body: 'This PR updates the README.md table to reflect changes in stewards.yml.'
        +          add: README.md
        +          token: ${{ secrets.ACCESS_TOKEN }}
        diff --git a/README.md b/README.md
        index ff94232d3b..9695521337 100644
        --- a/README.md
        +++ b/README.md
        @@ -86,27 +86,30 @@ Lead/Mentor Alumni
         * [@qianqianye](https://github.com/qianqianye) - p5.js Lead,2021-present (on leave)
         * [@outofambit](https://github.com/outofambit) - p5.js Co-Lead 2021-22, Mentor 2022-2023
         * [@mcturner1995](https://github.com/mcturner1995) - p5.js Lead 2020
        -  
        -| Area                                                                                 | Steward(s)                                                                                                               |
        -| ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ |
        -| Overall                                                                              | [@ksen0](https://github.com/ksen0)                                                                                                             |
        -| [Accessibility](https://github.com/processing/p5.js/tree/main/src/accessibility)     | [@calebfoss](https://github.com/calebfoss), [@cosmicbhejafry](https://github.com/cosmicbhejafry), [@apoorva-a98](https://github.com/apoorva-a98), [@tedkmburu](https://github.com/tedkmburu), [@Zarkv](https://github.com/Zarkv), [@SkylerW99](https://github.com/SkylerW99), [@itsjoopark](https://github.com/itsjoopark), [@hannahvy](https://github.com/hannahvy), [@nhasalajoshi](https://github.com/nhasalajoshi)|
        -| [Color](https://github.com/processing/p5.js/tree/main/src/color)                     | [@paulaxisabel](https://github.com/paulaxisabel), [@SoundaryaKoutharapu](https://github.com/SoundaryaKoutharapu), [@mrbrack](https://github.com/mrbrack), [@TJ723](https://github.com/TJ723), [@Zarkv](https://github.com/Zarkv), [@SkylerW99](https://github.com/SkylerW99), [@ramya202000](https://github.com/ramya202000), [@hannahvy](https://github.com/hannahvy), [@robin-haxx](https://github.com/robin-haxx), [@hiddenenigma](https://github.com/hiddenenigma)  |
        -| [Core](https://github.com/processing/p5.js/tree/main/src/core)/Environment/Rendering | [@limzykenneth](https://github.com/limzykenneth), [@davepagurek](https://github.com/davepagurek), [@ChihYungChang](https://github.com/ChihYungChang), [@teragramgius](https://github.com/teragramgius), [@tuminzee](https://github.com/tuminzee), [@Zarkv](https://github.com/Zarkv), [@robin-haxx](https://github.com/robin-haxx), [@Gaurav-1306](https://github.com/Gaurav-1306) |
        -| [Data](https://github.com/processing/p5.js/tree/main/src/data)                       | [@angelabelle](https://github.com/angelabelle), [@shahankhatch](https://github.com/shahankhatch), [@TanviKumar](https://github.com/TanviKumar), [@SkylerW99](https://github.com/SkylerW99), [@nhasalajoshi](https://github.com/nhasalajoshi)   |
        -| [DOM](https://github.com/processing/p5.js/tree/main/src/dom)                         | [@SarveshLimaye](https://github.com/SarveshLimaye), [@SoundaryaKoutharapu](https://github.com/SoundaryaKoutharapu), [@ramya202000](https://github.com/ramya202000), [@BamaCharanChhandogi](https://github.com/BamaCharanChhandogi), [@Obi-Engine10](https://github.com/Obi-Engine10), [@MarceloGoncalves](https://github.com/MarceloGoncalves), [@hiddenenigma](https://github.com/hiddenenigma)                   |
        -| [Events](https://github.com/processing/p5.js/tree/main/src/events)                   | [@limzykenneth](https://github.com/limzykenneth), [@richardegil](https://github.com/richardegil), [@angelabelle](https://github.com/angelabelle), [@littlejacinthe](https://github.com/littlejacinthe), [@TanviKumar](https://github.com/TanviKumar), [@tuminzee](https://github.com/tuminzee)       |
        -| [Image](https://github.com/processing/p5.js/tree/main/src/image)                     | [@cgusb](https://github.com/cgusb), [@albertomancia](https://github.com/albertomancia), [@ramya202000](https://github.com/ramya202000), [@hannahvy](https://github.com/hannahvy), [@robin-haxx](https://github.com/robin-haxx)|
        -| [IO](https://github.com/processing/p5.js/tree/main/src/io)                           | [@limzykenneth](https://github.com/limzykenneth), [@Pritam1136](https://github.com/Pritam1136), [@shahankhatch](https://github.com/shahankhatch), [@TanviKumar](https://github.com/TanviKumar), [@jeanetteandrews](https://github.com/jeanetteandrews)|
        -| [Math](https://github.com/processing/p5.js/tree/main/src/math)                       | [@limzykenneth](https://github.com/limzykenneth), [@ericnlchen](https://github.com/ericnlchen), [@ChihYungChang](https://github.com/ChihYungChang), [@bsubbaraman](https://github.com/bsubbaraman), [@albertomancia](https://github.com/albertomancia), [@JazerUCSB](https://github.com/JazerUCSB), [@tedkmburu](https://github.com/tedkmburu), [@perminder-17](https://github.com/perminder-17), [@Obi-Engine10](https://github.com/Obi-Engine10), [@jeanetteandrews](https://github.com/jeanetteandrews)       |
        -| [Typography](https://github.com/processing/p5.js/tree/main/src/typography)           | [@dhowe](https://github.com/dhowe), [@paulaxisabel](https://github.com/paulaxisabel), [@SarveshLimaye](https://github.com/SarveshLimaye), [@SkylerW99](https://github.com/SkylerW99), [@BamaCharanChhandogi](https://github.com/BamaCharanChhandogi), [@Obi-Engine10](https://github.com/Obi-Engine10), [@hannahvy](https://github.com/hannahvy), [@singshris](https://github.com/singshris), [@hiddenenigma](https://github.com/hiddenenigma)       |
        -| [Utilities](https://github.com/processing/p5.js/tree/main/src/utilities)             | [@limzykenneth](https://github.com/limzykenneth), [@glopzel](https://github.com/glopzel)     |
        -| [WebGL](https://github.com/processing/p5.js/tree/main/src/webgl)                     | [@davepagurek](https://github.com/davepagurek), [@aferriss](https://github.com/aferriss), [@aceslowman](https://github.com/aceslowman), [@ShenpaiSharma](https://github.com/ShenpaiSharma), [@ChihYungChang](https://github.com/ChihYungChang), [@teragramgius](https://github.com/teragramgius), [@JazerUCSB](https://github.com/JazerUCSB), [@richardegil](https://github.com/richardegil), [@itsjoopark](https://github.com/itsjoopark), [@Gaurav-1306](https://github.com/Gaurav-1306), [@jeanetteandrews](https://github.com/jeanetteandrews)  |
        -| [Internalization](https://github.com/processing/p5.js/blob/main/src/core/internationalization.js)           | [@limzykenneth](https://github.com/limzykenneth)        |
        -| [Friendly Errors](https://github.com/processing/p5.js/tree/main/src/core/friendly_errors)         | [@richardegil](https://github.com/richardegil), [@itsjoopark](https://github.com/itsjoopark), [@hannahvy](https://github.com/hannahvy), [@bisabi-01](https://github.com/bisabi-01), [@singshris](https://github.com/singshris)   |
        -| [Contributor Docs](https://github.com/processing/p5.js/tree/main/contributor_docs)   |[@limzykenneth](https://github.com/limzykenneth), [@asukaminato0721](https://github.com/asukaminato0721), [@SoundaryaKoutharapu](https://github.com/SoundaryaKoutharapu), [@richardegil](https://github.com/richardegil), [@hannahvy](https://github.com/hannahvy), [@bayomayo](https://github.com/bayomayo)  |
        -| [p5.sound](https://github.com/processing/p5.sound.js)   |[@miguellacorte](https://github.com/miguellacorte), [@JazerUCSB](https://github.com/JazerUCSB), [@angelabelle](https://github.com/angelabelle), [@littlejacinthe](https://github.com/littlejacinthe), [@hannahvy](https://github.com/hannahvy), [@glopzel](https://github.com/glopzel), [@singshris](https://github.com/singshris), [@jeanetteandrews](https://github.com/jeanetteandrews)  |
        -| Build Process/Unit Testing                                                           | [@limzykenneth](https://github.com/limzykenneth)      |
        +
        +
        +<!-- STEWARDS-LIST:START - Do not remove or modify this section -->
        +| Area | Steward(s) |
        +|------|-------------|
        +| Maintainers | [@davepagurek](https://github.com/davepagurek), [@ksen0](https://github.com/ksen0), [@limzykenneth](https://github.com/limzykenneth), [@perminder-17](https://github.com/perminder-17), [@qianqianye](https://github.com/qianqianye) |
        +| Accessibility | [@calebfoss](https://github.com/calebfoss) |
        +| Accessibility (p5.js-website) | [@coseeian](https://github.com/coseeian) |
        +| Color | [@limzykenneth](https://github.com/limzykenneth) |
        +| Core | [@davepagurek](https://github.com/davepagurek) |
        +| DevOps | [@Vaivaswat2244](https://github.com/Vaivaswat2244), [@error-four-o-four](https://github.com/error-four-o-four), [@limzykenneth](https://github.com/limzykenneth), [@lirenjie95](https://github.com/lirenjie95) |
        +| Documentation | [@VANSH3104](https://github.com/VANSH3104), [@limzykenneth](https://github.com/limzykenneth), [@perminder-17](https://github.com/perminder-17) |
        +| Friendly Errors | [@IITM-Jay](https://github.com/IITM-Jay) |
        +| Graphics (p5.strands) | [@lukeplowden](https://github.com/lukeplowden) |
        +| Graphics (WebGL) | [@aferriss](https://github.com/aferriss), [@davepagurek](https://github.com/davepagurek), [@lukeplowden](https://github.com/lukeplowden), [@perminder-17](https://github.com/perminder-17) |
        +| i18n (hi) | [@Divyansh013](https://github.com/Divyansh013), [@takshittt](https://github.com/takshittt) |
        +| i18n (zh) | [@limzykenneth](https://github.com/limzykenneth), [@lirenjie95](https://github.com/lirenjie95) |
        +| Math | [@GregStanton](https://github.com/GregStanton), [@holomorfo](https://github.com/holomorfo) |
        +| p5.js-website | [@clairep94](https://github.com/clairep94), [@ksen0](https://github.com/ksen0) |
        +| p5.sound.js | [@ogbabydiesal](https://github.com/ogbabydiesal) |
        +| Shapes | [@GregStanton](https://github.com/GregStanton) |
        +| Typography | [@dhowe](https://github.com/dhowe) |
        +| WebGL | [@RandomGamingDev](https://github.com/RandomGamingDev) |
        +<!-- STEWARDS-LIST:END -->
         
         ## Contributors
         
        diff --git a/contributor_docs/steward_guidelines.md b/contributor_docs/steward_guidelines.md
        index 98cbdbebdc..2b271f8ba1 100644
        --- a/contributor_docs/steward_guidelines.md
        +++ b/contributor_docs/steward_guidelines.md
        @@ -2,11 +2,16 @@
         
         # Steward Guidelines
         
        -Whether you have just joined us as a steward, are a seasoned maintainer of p5.js, or are somewhere in between, this guide contains information as well as tips and tricks that will help you effectively contribute to p5.js. Most of what is written here are guidelines unless otherwise stated, which means you can adapt the practices shown here to suit your workflow.
        +Whether you are new to p5.js contribution, are already active on the p5.js GitHub repositories, or are somewhere in between, you'll find what you need in this guide to p5.js stewardship. If you are not sure what to expect from stewards, or if you are considering how to volunteer or get started as a steward, read on!
         
         
         ## Table of Contents
         
        +- [Stewardship](#stewardship)
        +  - [Community Care](#community-care)
        +  - [Areas](#areas)
        +  - [Becoming a Steward](#becoming-a-steward)
        +  - [Getting Started with Stewardship](#getting-started-with-stewardship)
         - [Issues](#issues)
           - [Bug report](#bug-report)
           - [Feature request](#feature-request)
        @@ -28,6 +33,63 @@ Whether you have just joined us as a steward, are a seasoned maintainer of p5.js
         
         ---
         
        +## Stewardship
        +
        +### Community Care
        +
        +An open source ethos includes [accessibility, education, collaboration, transparency, and agency](https://www.opensourceethos.net/). To live and practice these values while we write code together needs a lot of community care. These are the community care practices that are part of our definition of stewardship:
        +
        +1. Welcoming new contributors to GitHub through **friendly comments** and helpful **code reviews**
        +2. Helping to **facilitate feature discussions** and resolve technical disagreements. For example, this means making connections to other past discussion, or offering input from prior relevant experience. Suggesting features or working on them is contribution, rather than stewardship.
        +3. Participating in releases of the p5.js software through **supporting** bug fixing and feature completion. For example, this means guiding other contributors and reviewing their PRs. Fixing bugs is contribution, rather than stewardship.
        +
        +The rest of these guidelines provide some tips and tricks that will help you effectively contribute to p5.js, and to helpfully guide others' contributions. Most of what is written here are guidelines unless otherwise stated, which means you can adapt the practices shown here to suit your workflow.
        +
        +Everyone is invited to help steward the community when they can! We are happy to see contributors welcome new contributors, review others' code, and provide API design feedback. There are also some concrete roles:
        +
        +1. Contributors are able to make Issues, PRs, Comments, and Code Reviews.
        +2. Maintainers are also able to merge PRs and admin other parts of the codebase.
        +
        +Stewards can also be contributors: they can make Issues and PRs as contributors, while they also take on responsibility, when they are stewarding a particular area, to comment on issues and do code reviews, especially when tagged by other contributors to help with discussion and review.
        +
        +As a contributor, you can check the current stewards in the p5.js repository's README file and tag relevant stewards - but please be mindful of our contributor guidelines, which emphasize patience and mindfulness that most of the technical work on an open-source project is volunteer.
        +
        +As a steward, we hope that you regularly chime in on code reviews on Issues or PRs that you did not make, if they are in your area and if you are able to provide helpful guidance!
        +
        +### Areas
        +
        +There are different areas of work that stewards can be responsible for. These areas match the GitHub Labels in most cases, with a couple of exceptions. Below is the list of areas.
        +
        +- **Accessibility**: This area specifically refers to digital and web accessibility, including, for example, screen reader support via API like `describe(..)` as well as accessibility support on the reference website
        +- **Core**: Refers to core p5.js API, including rendering and environment
        +- **DevOps**: Refers to build process, unit testing, and other aspects of the development experience
        +- **Documentation**: Includes both reference in the core codebase that is exposed on the website, the contributor docs, and other website content
        +- i18n (Internationalization / **Translation**): Includes reviewing translations, particularly for `es`, `hi`, `ko`, `zh`
        +- **Graphics**: Contains subareas of WebGL and [p5.strands](https://beta.p5js.org/tutorials/intro-to-p5-strands/)
        +- **Color**: Includes Color, ColorMode, accessibility improvements around color usage
        +- **Typography**: Refers to all topics on handling text and font
        +- **Math**: Includes both external Math API and internal performance improvements
        +- **Shapes**: Includes working with custom shapes in both 1.11.x and 2.x versions of p5.js
        +- **Maintainers**: This group can merge PRs
        +- **p5.sound.js**: The [new p5.sound.js](https://github.com/processing/p5.sound.js) add-on library
        +- **p5.js-website**: Non-content aspects of the [reference website](https://p5js.org/) - for example, its structure, automations, technical improvements and so on.
        +
        +These focus areas may change over time depending on the needs of the project - so if you are going through the process of applying to be a steward, you are welcome to proposals new areas!
        +
        +### Becoming a Steward
        +
        +There are two ways to become a steward:
        +
        +1. _Nomination_ by maintainers or other stewards, such as in conversation over Discord, Discourse, or GitHub.
        +2. _Application_ by creating a PR to update `stewards.yml` with your GitHub @ and proposed areas. Please keep in mind each area should have 1-3 stewards. We are always looking for **translation stewards**! Once you make your application PR, other maintainers or stewards may ask for additional supporting material, like making a PR related to the areas you're interested in, or participating in some related discussion.
        +
        +To remain a steward, you must contribute as a steward to at least 1 of the 2 most recent minor releases (e.g., 2.1.0 or 1.11.0 - when the middle number changes). These are not as frequent as patches (e.g., 2.0.3 to 2.0.4 - when the rightmost number changes), and in practice this means that stewards are expected to be active every 4-6 months or so, supporting other contributors through discussion or code review - not necessarily writing code. To step down from stewardship, you can make a PR to remove yourself from `stewards.yml`. You are always welcome to take a pause and reapply in the future!
        +
        +### Getting Started with Stewardship
        +
        +1. Keep this guideline handy as a reference - how to help with new issues, bugs, and features. For example, the "Feature request" section includes tips on how to use the the p5.js [access statement](access.md) as a steward.
        +2. When helping to answer technical questions or review, try to apply the Processing Foundation [guideline on answering questions](https://discourse.processing.org/t/guidelines-answering-questions/2145) - these can be especially helpful for giving constructive technical feedback.
        +3. Join the [p5.js Discord](https://discord.com/invite/SHQ8dH25r9)  - in the `#contribute-to-p5` you're welcome to ask any questions you have about this process - or suggest how it can be improved!
         
         ## Issues
         
        diff --git a/src/core/main.js b/src/core/main.js
        index b58f4de936..0e19d75ec1 100644
        --- a/src/core/main.js
        +++ b/src/core/main.js
        @@ -846,9 +846,11 @@ class p5 {
                         value: newValue,
                         writable: true
                       });
        -              log(
        -                `You just changed the value of "${prop}", which was a p5 function. This could cause problems later if you're not careful.`
        -              );
        +              if (!p5.disableFriendlyErrors) {
        +                log(
        +                  `You just changed the value of "${prop}", which was a p5 function. This could cause problems later if you're not careful.`
        +                );
        +              }
                     }
                   });
                 } catch (e) {
        diff --git a/stewards.yml b/stewards.yml
        new file mode 100644
        index 0000000000..da59ad2da6
        --- /dev/null
        +++ b/stewards.yml
        @@ -0,0 +1,86 @@
        +aferriss:
        +  - Graphics:
        +      - WebGL
        +
        +calebfoss:
        +  - Accessibility
        +
        +davepagurek:
        +  - Core
        +  - Maintainers
        +  - Graphics:
        +      - WebGL
        +
        +dhowe:
        +  - Typography
        +
        +qianqianye:
        +  - Maintainers
        +
        +ogbabydiesal:
        +  - p5.sound.js
        +
        +limzykenneth:
        +  - Maintainers
        +  - DevOps
        +  - Documentation
        +  - Color
        +  - i18n:
        +      - zh
        +
        +perminder-17:
        +  - Graphics:
        +      - WebGL
        +  - Documentation
        +  - Maintainers
        +
        +lukeplowden:
        +  - Graphics:
        +      - WebGL
        +      - p5.strands
        +
        +ksen0:
        +  - Maintainers
        +  - p5.js-website
        +
        +Divyansh013:
        +  - i18n:
        +      - hi
        +
        +GregStanton:
        +  - Math
        +  - Shapes
        +
        +holomorfo:
        +  - Math
        +
        +lirenjie95:
        +  - i18n:
        +      - zh
        +  - DevOps
        +
        +IITM-Jay:
        +  - Friendly Errors
        +
        +Vaivaswat2244:
        +  - DevOps
        +
        +RandomGamingDev:
        +  - WebGL
        +
        +VANSH3104:
        +  - Documentation
        +
        +error-four-o-four:
        +  - DevOps
        +
        +takshittt:
        +  - i18n:
        +      - hi
        +
        +clairep94:
        +  - p5.js-website
        +
        +coseeian:
        +  - Accessibility:
        +      - p5.js-website
        diff --git a/utils/stewards-table.js b/utils/stewards-table.js
        new file mode 100644
        index 0000000000..fe5060f7ba
        --- /dev/null
        +++ b/utils/stewards-table.js
        @@ -0,0 +1,56 @@
        +const yaml = require('js-yaml');
        +const fs = require('fs');
        +
        +const yamlData = fs.readFileSync('stewards.yml', 'utf8');
        +const parsed = yaml.load(yamlData);
        +
        +const areaMap = {};
        +const supportedi18n = new Set(['hi', 'ko', 'zh', 'es']);
        +
        +
        +for (const [user, roles] of Object.entries(parsed)) {
        +  roles.forEach(role => {
        +    if (typeof role === 'string') {
        +      areaMap[role] = areaMap[role] || new Set();
        +      areaMap[role].add(`${user}`);
        +    } else {
        +      for (const [main, subs] of Object.entries(role)) {
        +        subs.forEach(sub => {
        +          if (main === 'i18n' && !supportedi18n.has(sub)) return;
        +          const key = `${main} (${sub})`;
        +          areaMap[key] = areaMap[key] || new Set();
        +          areaMap[key].add(`${user}`);
        +        });
        +      }
        +    }
        +  });
        +}
        +
        +
        +const startMarker = '<!-- STEWARDS-LIST:START - Do not remove or modify this section -->';
        +const endMarker = '<!-- STEWARDS-LIST:END -->';
        +
        +const header = '| Area | Steward(s) |';
        +const divider = '|------|-------------|';
        +
        +const sortedEntries = Object.entries(areaMap).sort(([aKey], [bKey]) => {
        +  if (aKey === 'Maintainers') return -1;
        +  if (bKey === 'Maintainers') return 1;
        +  return aKey.localeCompare(bKey);
        +});
        +
        +const rows = sortedEntries.map(([area, users]) => `| ${area} | ${[...users].sort().map(
        +  u => `[@${u}](https://github.com/${u})`
        +).join(', ')} |`).join('\n');
        +const newTable = [startMarker, header, divider, rows, endMarker].join('\n');
        +
        +let readme = fs.readFileSync('README.md', 'utf8');
        +
        +const startIndex = readme.indexOf(startMarker);
        +const endIndex = readme.indexOf(endMarker) + endMarker.length;
        +
        +if (startIndex !== -1 && endIndex !== -1) {
        +  readme = readme.slice(0, startIndex) + newTable + readme.slice(endIndex);
        +}
        +
        +fs.writeFileSync('README.md', readme);
        
        From 0507b95233b5bc0cb77d86c26f73a18b587d7d8f Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Wed, 11 Jun 2025 09:51:23 +0000
        Subject: [PATCH 195/282] docs: update README.md [skip ci]
        
        ---
         README.md | 3 +++
         1 file changed, 3 insertions(+)
        
        diff --git a/README.md b/README.md
        index 9695521337..f18365968e 100644
        --- a/README.md
        +++ b/README.md
        @@ -1152,6 +1152,9 @@ We recognize all types of contributions. This project follows the [all-contribut
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/sukrucildirr"><img src="https://avatars.githubusercontent.com/u/32969880?v=4?s=64" width="64px;" alt="sukrucildirr"/><br /><sub><b>sukrucildirr</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=sukrucildirr" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://linktr.ee/andrewmcwhae"><img src="https://avatars.githubusercontent.com/u/8450380?v=4?s=64" width="64px;" alt="Andrew McWhae"/><br /><sub><b>Andrew McWhae</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=andrewmcwhae" title="Documentation">📖</a></td>
             </tr>
        +    <tr>
        +      <td align="center" valign="top" width="16.66%"><a href="https://github.com/atmajaa"><img src="https://avatars.githubusercontent.com/u/69838867?v=4?s=64" width="64px;" alt="Atmaja P."/><br /><sub><b>Atmaja P.</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=atmajaa" title="Documentation">📖</a></td>
        +    </tr>
           </tbody>
         </table>
         
        
        From 63c34e9e45ff8776c37d925e01adcc54346ed557 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Wed, 11 Jun 2025 09:51:25 +0000
        Subject: [PATCH 196/282] docs: update .all-contributorsrc [skip ci]
        
        ---
         .all-contributorsrc | 9 +++++++++
         1 file changed, 9 insertions(+)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index f4cfbabfb1..1fe0af16e9 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -6914,6 +6914,15 @@
               "contributions": [
                 "doc"
               ]
        +    },
        +    {
        +      "login": "atmajaa",
        +      "name": "Atmaja P.",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/69838867?v=4",
        +      "profile": "https://github.com/atmajaa",
        +      "contributions": [
        +        "doc"
        +      ]
             }
           ],
           "repoType": "github",
        
        From 5c4225b7ea53230fafbffc6d2705defca4ee1c7c Mon Sep 17 00:00:00 2001
        From: kit <1304340+ksen0@users.noreply.github.com>
        Date: Thu, 12 Jun 2025 16:04:25 +0200
        Subject: [PATCH 197/282] Update labeler.yml to correctly group DevOps lables
        
        ---
         .github/labeler.yml | 1 -
         1 file changed, 1 deletion(-)
        
        diff --git a/.github/labeler.yml b/.github/labeler.yml
        index a593e7c8e9..613755a8ac 100644
        --- a/.github/labeler.yml
        +++ b/.github/labeler.yml
        @@ -26,7 +26,6 @@
           - '\[[xX]\]\s*Internationalization'
         "DevOps":
           - '\[[xX]\]\s*Build Process'
        -"DevOps":
           - '\[[xX]\]\s*Unit Testing'
         "Build Process":
           - '\[[xX]\]\s*Build Process'
        
        From 7cc79b640e54e8c951aab0951d82bf266dee93eb Mon Sep 17 00:00:00 2001
        From: shiva <shiva_05@outlook.com>
        Date: Thu, 12 Jun 2025 20:28:37 +0530
        Subject: [PATCH 198/282] feat:revamp config.yml
        
        ---
         .github/config.yml | 20 +++++++++++++++++---
         1 file changed, 17 insertions(+), 3 deletions(-)
        
        diff --git a/.github/config.yml b/.github/config.yml
        index c4629c14ed..7a92f38473 100644
        --- a/.github/config.yml
        +++ b/.github/config.yml
        @@ -4,12 +4,26 @@
         
         # Comment to be posted to on first time issues
         newIssueWelcomeComment: >
        -  Welcome! 👋 Thanks for opening your first issue here! And to ensure the community is able to respond to your issue, please make sure to fill out the inputs in the issue forms. Thank you!
        -# Configuration for new-pr-welcome - https://github.com/behaviorbot/new-pr-welcome
        +   Welcome! 👋 Thanks for opening your first issue here! And to ensure the community is able to respond to your issue, please make sure to fill out the inputs in the issue forms.
        +    
        +   For guidance on contributing, check out our [contributing guidelines](https://github.com/processing/p5.js/blob/main/CONTRIBUTING.md) and other [resources for contributors](https://p5js.org/contribute/).
        +
        +   💬 If you have questions or need support,  feel free to join the [Processing Foundation Forum](https://discourse.processing.org/) or visit our [Community page](https://p5js.org/community/).
         
        +   📜 Please also review our [Code of Conduct](https://p5js.org/code-of-conduct/) to understand our community standards.
        +
        +   Thank You!
        +# Configuration for new-pr-welcome - https://github.com/behaviorbot/new-pr-welcome
         # Comment to be posted to on PRs from first time contributors in your repository
         newPRWelcomeComment: >
        -  🎉 Thanks for opening this pull request! Please check out our [contributing guidelines](https://github.com/processing/p5.js/blob/main/CONTRIBUTING.md) if you haven't already. And be sure to add yourself to the [list of contributors on the readme page](https://github.com/processing/p5.js#contributors)!
        +   🎉 Thanks for opening this pull request! For guidance on contributing, check out our [contributor guidelines](https://p5js.org/contribute/contributor_guidelines/) and other [resources for contributors](https://p5js.org/contribute)!
        +
        +   🤔 Please ensure that your PR links to an issue, which has been approved for work by a maintainer; otherwise, there might already be someone working on it, or still ongoing discussion about implementation. You are welcome to join the discussion in an Issue if you're not sure!
        +
        +   🌸  Once your PR is merged, be sure to [add yourself](https://github.com/processing/p5.js/issues/2309) to the [list of contributors on the readme page](https://github.com/processing/p5.js#contributors) !
        +
        +
        +   Thank You!
         
         # Configuration for first-pr-merge - https://github.com/behaviorbot/first-pr-merge
         
        
        From a54755ae4e4696cefd89386e863a214ad30daadd Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Thu, 12 Jun 2025 22:13:36 +0000
        Subject: [PATCH 199/282] docs: update README.md [skip ci]
        
        ---
         README.md | 1 +
         1 file changed, 1 insertion(+)
        
        diff --git a/README.md b/README.md
        index f18365968e..97ad8e446e 100644
        --- a/README.md
        +++ b/README.md
        @@ -1154,6 +1154,7 @@ We recognize all types of contributions. This project follows the [all-contribut
             </tr>
             <tr>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/atmajaa"><img src="https://avatars.githubusercontent.com/u/69838867?v=4?s=64" width="64px;" alt="Atmaja P."/><br /><sub><b>Atmaja P.</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=atmajaa" title="Documentation">📖</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="https://github.com/SonyaCode"><img src="https://avatars.githubusercontent.com/u/99513449?v=4?s=64" width="64px;" alt="SonyaCode"/><br /><sub><b>SonyaCode</b></sub></a><br /><a href="#a11y-SonyaCode" title="Accessibility">️️️️♿️</a> <a href="#blog-SonyaCode" title="Blogposts">📝</a> <a href="https://github.com/processing/p5.js/issues?q=author%3ASonyaCode" title="Bug reports">🐛</a> <a href="https://github.com/processing/p5.js/commits?author=SonyaCode" title="Code">💻</a> <a href="#design-SonyaCode" title="Design">🎨</a> <a href="https://github.com/processing/p5.js/commits?author=SonyaCode" title="Documentation">📖</a></td>
             </tr>
           </tbody>
         </table>
        
        From 9147086334a16e1dc6a2227b9587ca125de29434 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Thu, 12 Jun 2025 22:13:37 +0000
        Subject: [PATCH 200/282] docs: update .all-contributorsrc [skip ci]
        
        ---
         .all-contributorsrc | 14 ++++++++++++++
         1 file changed, 14 insertions(+)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index 1fe0af16e9..396ec276ff 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -6923,6 +6923,20 @@
               "contributions": [
                 "doc"
               ]
        +    },
        +    {
        +      "login": "SonyaCode",
        +      "name": "SonyaCode",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/99513449?v=4",
        +      "profile": "https://github.com/SonyaCode",
        +      "contributions": [
        +        "a11y",
        +        "blog",
        +        "bug",
        +        "code",
        +        "design",
        +        "doc"
        +      ]
             }
           ],
           "repoType": "github",
        
        From 12a30298aaac6bf5eb613f64181e6da16756424f Mon Sep 17 00:00:00 2001
        From: "fuder.eth" <139509124+vtjl10@users.noreply.github.com>
        Date: Sat, 14 Jun 2025 16:23:29 +0200
        Subject: [PATCH 201/282] Update textOutput.js
        
        ---
         src/accessibility/textOutput.js | 4 ++--
         1 file changed, 2 insertions(+), 2 deletions(-)
        
        diff --git a/src/accessibility/textOutput.js b/src/accessibility/textOutput.js
        index 5e37fd5781..1fe2dc8137 100644
        --- a/src/accessibility/textOutput.js
        +++ b/src/accessibility/textOutput.js
        @@ -59,7 +59,7 @@ function _textSummary(numShapes, background, width, height) {
         function _shapeDetails(idT, ingredients) {
           let shapeDetails = '';
           let shapeNumber = 0;
        -  //goes trhough every shape type in ingredients
        +  //goes through every shape type in ingredients
           for (let x in ingredients) {
             //and for every shape
             for (let y in ingredients[x]) {
        @@ -91,7 +91,7 @@ function _shapeDetails(idT, ingredients) {
         function _shapeList(idT, ingredients) {
           let shapeList = '';
           let shapeNumber = 0;
        -  //goes trhough every shape type in ingredients
        +  //goes through every shape type in ingredients
           for (let x in ingredients) {
             for (let y in ingredients[x]) {
               //it creates a line in a list
        
        From d72130957cd35305c931e48d0a2fde5d9d78d217 Mon Sep 17 00:00:00 2001
        From: IIITM-Jay <jaydev.neuroscitech@gmail.com>
        Date: Sat, 14 Jun 2025 19:53:37 +0530
        Subject: [PATCH 202/282] Correct username in stewards.yml
        
        ---
         stewards.yml | 2 +-
         1 file changed, 1 insertion(+), 1 deletion(-)
        
        diff --git a/stewards.yml b/stewards.yml
        index da59ad2da6..0c96b3337c 100644
        --- a/stewards.yml
        +++ b/stewards.yml
        @@ -59,7 +59,7 @@ lirenjie95:
               - zh
           - DevOps
         
        -IITM-Jay:
        +IIITM-Jay:
           - Friendly Errors
         
         Vaivaswat2244:
        
        From 5b30f9cb2f136137819b3fed0527c637bd976c14 Mon Sep 17 00:00:00 2001
        From: perminder-17 <perminder-17@users.noreply.github.com>
        Date: Mon, 16 Jun 2025 12:03:17 +0000
        Subject: [PATCH 203/282] Update README table from stewards.yml
        
        ---
         README.md | 2 +-
         1 file changed, 1 insertion(+), 1 deletion(-)
        
        diff --git a/README.md b/README.md
        index 97ad8e446e..6b89d2294d 100644
        --- a/README.md
        +++ b/README.md
        @@ -98,7 +98,7 @@ Lead/Mentor Alumni
         | Core | [@davepagurek](https://github.com/davepagurek) |
         | DevOps | [@Vaivaswat2244](https://github.com/Vaivaswat2244), [@error-four-o-four](https://github.com/error-four-o-four), [@limzykenneth](https://github.com/limzykenneth), [@lirenjie95](https://github.com/lirenjie95) |
         | Documentation | [@VANSH3104](https://github.com/VANSH3104), [@limzykenneth](https://github.com/limzykenneth), [@perminder-17](https://github.com/perminder-17) |
        -| Friendly Errors | [@IITM-Jay](https://github.com/IITM-Jay) |
        +| Friendly Errors | [@IIITM-Jay](https://github.com/IIITM-Jay) |
         | Graphics (p5.strands) | [@lukeplowden](https://github.com/lukeplowden) |
         | Graphics (WebGL) | [@aferriss](https://github.com/aferriss), [@davepagurek](https://github.com/davepagurek), [@lukeplowden](https://github.com/lukeplowden), [@perminder-17](https://github.com/perminder-17) |
         | i18n (hi) | [@Divyansh013](https://github.com/Divyansh013), [@takshittt](https://github.com/takshittt) |
        
        From 2129ba339b99b494d37753ff35c459052ab754c2 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Mon, 16 Jun 2025 12:07:55 +0000
        Subject: [PATCH 204/282] docs: update README.md [skip ci]
        
        ---
         README.md | 1 +
         1 file changed, 1 insertion(+)
        
        diff --git a/README.md b/README.md
        index 97ad8e446e..6f6542f82c 100644
        --- a/README.md
        +++ b/README.md
        @@ -1155,6 +1155,7 @@ We recognize all types of contributions. This project follows the [all-contribut
             <tr>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/atmajaa"><img src="https://avatars.githubusercontent.com/u/69838867?v=4?s=64" width="64px;" alt="Atmaja P."/><br /><sub><b>Atmaja P.</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=atmajaa" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/SonyaCode"><img src="https://avatars.githubusercontent.com/u/99513449?v=4?s=64" width="64px;" alt="SonyaCode"/><br /><sub><b>SonyaCode</b></sub></a><br /><a href="#a11y-SonyaCode" title="Accessibility">️️️️♿️</a> <a href="#blog-SonyaCode" title="Blogposts">📝</a> <a href="https://github.com/processing/p5.js/issues?q=author%3ASonyaCode" title="Bug reports">🐛</a> <a href="https://github.com/processing/p5.js/commits?author=SonyaCode" title="Code">💻</a> <a href="#design-SonyaCode" title="Design">🎨</a> <a href="https://github.com/processing/p5.js/commits?author=SonyaCode" title="Documentation">📖</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="https://github.com/vtjl10"><img src="https://avatars.githubusercontent.com/u/139509124?v=4?s=64" width="64px;" alt="fuder.eth"/><br /><sub><b>fuder.eth</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=vtjl10" title="Documentation">📖</a></td>
             </tr>
           </tbody>
         </table>
        
        From a3308ca6dd58bf55eaa27dc21a050b881f78f398 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Mon, 16 Jun 2025 12:07:56 +0000
        Subject: [PATCH 205/282] docs: update .all-contributorsrc [skip ci]
        
        ---
         .all-contributorsrc | 9 +++++++++
         1 file changed, 9 insertions(+)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index 396ec276ff..efc05acbed 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -6937,6 +6937,15 @@
                 "design",
                 "doc"
               ]
        +    },
        +    {
        +      "login": "vtjl10",
        +      "name": "fuder.eth",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/139509124?v=4",
        +      "profile": "https://github.com/vtjl10",
        +      "contributions": [
        +        "doc"
        +      ]
             }
           ],
           "repoType": "github",
        
        From cb0460924002a21db3bd3986298a9b4e7683d1f6 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Mon, 16 Jun 2025 17:03:33 +0000
        Subject: [PATCH 206/282] docs: update README.md [skip ci]
        
        ---
         README.md | 2 +-
         1 file changed, 1 insertion(+), 1 deletion(-)
        
        diff --git a/README.md b/README.md
        index c0548e4f5a..0e4fbfc203 100644
        --- a/README.md
        +++ b/README.md
        @@ -1141,7 +1141,7 @@ We recognize all types of contributions. This project follows the [all-contribut
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/clairep94"><img src="https://avatars.githubusercontent.com/u/128436909?v=4?s=64" width="64px;" alt="Claire Peng"/><br /><sub><b>Claire Peng</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=clairep94" title="Code">💻</a> <a href="https://github.com/processing/p5.js/issues?q=author%3Aclairep94" title="Bug reports">🐛</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/IIITM-Jay"><img src="https://avatars.githubusercontent.com/u/65283880?v=4?s=64" width="64px;" alt="Jay Dev Jha"/><br /><sub><b>Jay Dev Jha</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=IIITM-Jay" title="Code">💻</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://yugalkaushik.vercel.app"><img src="https://avatars.githubusercontent.com/u/138966980?v=4?s=64" width="64px;" alt="Yugal Kaushik"/><br /><sub><b>Yugal Kaushik</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=yugalkaushik" title="Code">💻</a> <a href="https://github.com/processing/p5.js/commits?author=yugalkaushik" title="Documentation">📖</a></td>
        -      <td align="center" valign="top" width="16.66%"><a href="https://github.com/LalitNarayanYadav"><img src="https://avatars.githubusercontent.com/u/162928571?v=4?s=64" width="64px;" alt="Lalit Narayan Yadav"/><br /><sub><b>Lalit Narayan Yadav</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=LalitNarayanYadav" title="Documentation">📖</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="https://github.com/LalitNarayanYadav"><img src="https://avatars.githubusercontent.com/u/162928571?v=4?s=64" width="64px;" alt="Lalit Narayan Yadav"/><br /><sub><b>Lalit Narayan Yadav</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=LalitNarayanYadav" title="Documentation">📖</a> <a href="https://github.com/processing/p5.js/commits?author=LalitNarayanYadav" title="Code">💻</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/irina-wang"><img src="https://avatars.githubusercontent.com/u/59970384?v=4?s=64" width="64px;" alt="Irina Mengqi Wang"/><br /><sub><b>Irina Mengqi Wang</b></sub></a><br /><a href="#example-irina-wang" title="Examples">💡</a></td>
             </tr>
             <tr>
        
        From 0bb096d7cae03bd05a3d68c2ecc2410b3187dc10 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Mon, 16 Jun 2025 17:03:34 +0000
        Subject: [PATCH 207/282] docs: update .all-contributorsrc [skip ci]
        
        ---
         .all-contributorsrc | 3 ++-
         1 file changed, 2 insertions(+), 1 deletion(-)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index efc05acbed..11c49940fa 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -6849,7 +6849,8 @@
               "avatar_url": "https://avatars.githubusercontent.com/u/162928571?v=4",
               "profile": "https://github.com/LalitNarayanYadav",
               "contributions": [
        -        "doc"
        +        "doc",
        +        "code"
               ]
             },
             {
        
        From 215220dc0c2378ad5537a3bd8923df90f63044a1 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Wed, 18 Jun 2025 06:08:35 +0000
        Subject: [PATCH 208/282] docs: update README.md [skip ci]
        
        ---
         README.md | 1 +
         1 file changed, 1 insertion(+)
        
        diff --git a/README.md b/README.md
        index 0e4fbfc203..2b2d05c3bd 100644
        --- a/README.md
        +++ b/README.md
        @@ -1156,6 +1156,7 @@ We recognize all types of contributions. This project follows the [all-contribut
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/atmajaa"><img src="https://avatars.githubusercontent.com/u/69838867?v=4?s=64" width="64px;" alt="Atmaja P."/><br /><sub><b>Atmaja P.</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=atmajaa" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/SonyaCode"><img src="https://avatars.githubusercontent.com/u/99513449?v=4?s=64" width="64px;" alt="SonyaCode"/><br /><sub><b>SonyaCode</b></sub></a><br /><a href="#a11y-SonyaCode" title="Accessibility">️️️️♿️</a> <a href="#blog-SonyaCode" title="Blogposts">📝</a> <a href="https://github.com/processing/p5.js/issues?q=author%3ASonyaCode" title="Bug reports">🐛</a> <a href="https://github.com/processing/p5.js/commits?author=SonyaCode" title="Code">💻</a> <a href="#design-SonyaCode" title="Design">🎨</a> <a href="https://github.com/processing/p5.js/commits?author=SonyaCode" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/vtjl10"><img src="https://avatars.githubusercontent.com/u/139509124?v=4?s=64" width="64px;" alt="fuder.eth"/><br /><sub><b>fuder.eth</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=vtjl10" title="Documentation">📖</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="https://github.com/FerrinThreatt"><img src="https://avatars.githubusercontent.com/u/51208056?v=4?s=64" width="64px;" alt="FerrinThreatt"/><br /><sub><b>FerrinThreatt</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=FerrinThreatt" title="Documentation">📖</a></td>
             </tr>
           </tbody>
         </table>
        
        From 3190af78b4cef69128ae02d3d5306e705a39892a Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Wed, 18 Jun 2025 06:08:35 +0000
        Subject: [PATCH 209/282] docs: update .all-contributorsrc [skip ci]
        
        ---
         .all-contributorsrc | 9 +++++++++
         1 file changed, 9 insertions(+)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index 11c49940fa..a634a9cb39 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -6947,6 +6947,15 @@
               "contributions": [
                 "doc"
               ]
        +    },
        +    {
        +      "login": "FerrinThreatt",
        +      "name": "FerrinThreatt",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/51208056?v=4",
        +      "profile": "https://github.com/FerrinThreatt",
        +      "contributions": [
        +        "doc"
        +      ]
             }
           ],
           "repoType": "github",
        
        From 90ae3f4bbe13ca3169709d1d5c976c15c52225ad Mon Sep 17 00:00:00 2001
        From: kit <1304340+ksen0@users.noreply.github.com>
        Date: Thu, 19 Jun 2025 20:17:31 +0200
        Subject: [PATCH 210/282] Update stewards.yml
        
        Fixing a typo that created two separate WebGL sections unintentionally
        ---
         stewards.yml | 3 ++-
         1 file changed, 2 insertions(+), 1 deletion(-)
        
        diff --git a/stewards.yml b/stewards.yml
        index 0c96b3337c..451fee6b88 100644
        --- a/stewards.yml
        +++ b/stewards.yml
        @@ -66,7 +66,8 @@ Vaivaswat2244:
           - DevOps
         
         RandomGamingDev:
        -  - WebGL
        +  - Graphics:
        +      - WebGL
         
         VANSH3104:
           - Documentation
        
        From a7bfeda0bda7754b36bc7e281192270fedf1b00c Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Thu, 19 Jun 2025 19:02:42 +0000
        Subject: [PATCH 211/282] docs: update README.md [skip ci]
        
        ---
         README.md | 1 +
         1 file changed, 1 insertion(+)
        
        diff --git a/README.md b/README.md
        index 2b2d05c3bd..e22855af94 100644
        --- a/README.md
        +++ b/README.md
        @@ -1157,6 +1157,7 @@ We recognize all types of contributions. This project follows the [all-contribut
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/SonyaCode"><img src="https://avatars.githubusercontent.com/u/99513449?v=4?s=64" width="64px;" alt="SonyaCode"/><br /><sub><b>SonyaCode</b></sub></a><br /><a href="#a11y-SonyaCode" title="Accessibility">️️️️♿️</a> <a href="#blog-SonyaCode" title="Blogposts">📝</a> <a href="https://github.com/processing/p5.js/issues?q=author%3ASonyaCode" title="Bug reports">🐛</a> <a href="https://github.com/processing/p5.js/commits?author=SonyaCode" title="Code">💻</a> <a href="#design-SonyaCode" title="Design">🎨</a> <a href="https://github.com/processing/p5.js/commits?author=SonyaCode" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/vtjl10"><img src="https://avatars.githubusercontent.com/u/139509124?v=4?s=64" width="64px;" alt="fuder.eth"/><br /><sub><b>fuder.eth</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=vtjl10" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/FerrinThreatt"><img src="https://avatars.githubusercontent.com/u/51208056?v=4?s=64" width="64px;" alt="FerrinThreatt"/><br /><sub><b>FerrinThreatt</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=FerrinThreatt" title="Documentation">📖</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="http://bensgilbert.com"><img src="https://avatars.githubusercontent.com/u/68397475?v=4?s=64" width="64px;" alt="Ben Gilbert"/><br /><sub><b>Ben Gilbert</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=bensgilbert" title="Code">💻</a></td>
             </tr>
           </tbody>
         </table>
        
        From 03188f0908afc4dc6d9515bc65f0337c369b96be Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Thu, 19 Jun 2025 19:02:43 +0000
        Subject: [PATCH 212/282] docs: update .all-contributorsrc [skip ci]
        
        ---
         .all-contributorsrc | 9 +++++++++
         1 file changed, 9 insertions(+)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index a634a9cb39..9222a3e1aa 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -6956,6 +6956,15 @@
               "contributions": [
                 "doc"
               ]
        +    },
        +    {
        +      "login": "bensgilbert",
        +      "name": "Ben Gilbert",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/68397475?v=4",
        +      "profile": "http://bensgilbert.com",
        +      "contributions": [
        +        "code"
        +      ]
             }
           ],
           "repoType": "github",
        
        From ead593e2f7ab32c81120e47bf50fced6c40f0af4 Mon Sep 17 00:00:00 2001
        From: Ben Gilbert <bensgilbert@outlook.com>
        Date: Thu, 19 Jun 2025 20:26:35 +0100
        Subject: [PATCH 213/282] fix contributor
        
        ---
         .all-contributorsrc | 15 +++------------
         README.md           |  2 +-
         2 files changed, 4 insertions(+), 13 deletions(-)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index 9222a3e1aa..e73f0a6655 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -6088,10 +6088,10 @@
               ]
             },
             {
        -      "login": "Evorage0",
        -      "name": "Evorage",
        +      "login": "bensgilbert",
        +      "name": "Ben Gilbert",
               "avatar_url": "https://avatars.githubusercontent.com/u/68397475?v=4",
        -      "profile": "https://github.com/Evorage0",
        +      "profile": "http://bensgilbert.com",
               "contributions": [
                 "bug",
                 "code"
        @@ -6956,15 +6956,6 @@
               "contributions": [
                 "doc"
               ]
        -    },
        -    {
        -      "login": "bensgilbert",
        -      "name": "Ben Gilbert",
        -      "avatar_url": "https://avatars.githubusercontent.com/u/68397475?v=4",
        -      "profile": "http://bensgilbert.com",
        -      "contributions": [
        -        "code"
        -      ]
             }
           ],
           "repoType": "github",
        diff --git a/README.md b/README.md
        index e22855af94..7e16d565e0 100644
        --- a/README.md
        +++ b/README.md
        @@ -1035,7 +1035,7 @@ We recognize all types of contributions. This project follows the [all-contribut
             <tr>
               <td align="center" valign="top" width="16.66%"><a href="http://abhinavcode13.github.io"><img src="https://avatars.githubusercontent.com/u/126642111?v=4?s=64" width="64px;" alt="Abhinav kumar"/><br /><sub><b>Abhinav kumar</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=Abhinavcode13" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/chhaski"><img src="https://avatars.githubusercontent.com/u/71788879?v=4?s=64" width="64px;" alt="chaski"/><br /><sub><b>chaski</b></sub></a><br /><a href="#research-chhaski" title="Research">🔬</a> <a href="https://github.com/processing/p5.js/commits?author=chhaski" title="Code">💻</a> <a href="#example-chhaski" title="Examples">💡</a></td>
        -      <td align="center" valign="top" width="16.66%"><a href="https://github.com/Evorage0"><img src="https://avatars.githubusercontent.com/u/68397475?v=4?s=64" width="64px;" alt="Evorage"/><br /><sub><b>Evorage</b></sub></a><br /><a href="https://github.com/processing/p5.js/issues?q=author%3AEvorage0" title="Bug reports">🐛</a> <a href="https://github.com/processing/p5.js/commits?author=Evorage0" title="Code">💻</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="https://github.com/bensgilbert"><img src="https://avatars.githubusercontent.com/u/68397475?v=4?s=64" width="64px;" alt="Ben Gilbert"/><br /><sub><b>Ben Gilbert</b></sub></a><br /><a href="https://github.com/processing/p5.js/issues?q=author%3Abensgilbert" title="Bug reports">🐛</a> <a href="https://github.com/processing/p5.js/commits?author=bensgilbert" title="Code">💻</a></td>
               <td align="center" valign="top" width="16.66%"><a href="http://iamdanielmarino.com"><img src="https://avatars.githubusercontent.com/u/171375?v=4?s=64" width="64px;" alt="Daniel Marino"/><br /><sub><b>Daniel Marino</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=starzonmyarmz" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/shahmaz0/"><img src="https://avatars.githubusercontent.com/Shahmaz0?s=64" width="64px;" alt="Shahma Ansari"/><br /><sub><b>Shahma Ansari</b></sub></a><br /><a href="https://github.com/processing/p5.js/issues?q=author%3AShahmaz0" title="Bug reports">🐛</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/Manancode"><img src="https://avatars.githubusercontent.com/u/144525586?v=4?s=64" width="64px;" alt="Manan Arora"/><br /><sub><b>Manan Arora</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=Manancode" title="Documentation">📖</a></td>
        
        From e72839c247fde65e437b005199cd2599f53b7e04 Mon Sep 17 00:00:00 2001
        From: ksen0 <ksen0@users.noreply.github.com>
        Date: Thu, 19 Jun 2025 19:47:19 +0000
        Subject: [PATCH 214/282] Update README table from stewards.yml
        
        ---
         README.md | 3 +--
         1 file changed, 1 insertion(+), 2 deletions(-)
        
        diff --git a/README.md b/README.md
        index e22855af94..c2ee200185 100644
        --- a/README.md
        +++ b/README.md
        @@ -100,7 +100,7 @@ Lead/Mentor Alumni
         | Documentation | [@VANSH3104](https://github.com/VANSH3104), [@limzykenneth](https://github.com/limzykenneth), [@perminder-17](https://github.com/perminder-17) |
         | Friendly Errors | [@IIITM-Jay](https://github.com/IIITM-Jay) |
         | Graphics (p5.strands) | [@lukeplowden](https://github.com/lukeplowden) |
        -| Graphics (WebGL) | [@aferriss](https://github.com/aferriss), [@davepagurek](https://github.com/davepagurek), [@lukeplowden](https://github.com/lukeplowden), [@perminder-17](https://github.com/perminder-17) |
        +| Graphics (WebGL) | [@RandomGamingDev](https://github.com/RandomGamingDev), [@aferriss](https://github.com/aferriss), [@davepagurek](https://github.com/davepagurek), [@lukeplowden](https://github.com/lukeplowden), [@perminder-17](https://github.com/perminder-17) |
         | i18n (hi) | [@Divyansh013](https://github.com/Divyansh013), [@takshittt](https://github.com/takshittt) |
         | i18n (zh) | [@limzykenneth](https://github.com/limzykenneth), [@lirenjie95](https://github.com/lirenjie95) |
         | Math | [@GregStanton](https://github.com/GregStanton), [@holomorfo](https://github.com/holomorfo) |
        @@ -108,7 +108,6 @@ Lead/Mentor Alumni
         | p5.sound.js | [@ogbabydiesal](https://github.com/ogbabydiesal) |
         | Shapes | [@GregStanton](https://github.com/GregStanton) |
         | Typography | [@dhowe](https://github.com/dhowe) |
        -| WebGL | [@RandomGamingDev](https://github.com/RandomGamingDev) |
         <!-- STEWARDS-LIST:END -->
         
         ## Contributors
        
        From f9091fb1e2e5b3d5a790562423e78966ae8fe264 Mon Sep 17 00:00:00 2001
        From: Ben Gilbert <bensgilbert@outlook.com>
        Date: Thu, 19 Jun 2025 21:20:50 +0100
        Subject: [PATCH 215/282] remove duplicate contributor from README.md
        
        ---
         README.md | 1 -
         1 file changed, 1 deletion(-)
        
        diff --git a/README.md b/README.md
        index 7e16d565e0..b6f5f0abe4 100644
        --- a/README.md
        +++ b/README.md
        @@ -1157,7 +1157,6 @@ We recognize all types of contributions. This project follows the [all-contribut
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/SonyaCode"><img src="https://avatars.githubusercontent.com/u/99513449?v=4?s=64" width="64px;" alt="SonyaCode"/><br /><sub><b>SonyaCode</b></sub></a><br /><a href="#a11y-SonyaCode" title="Accessibility">️️️️♿️</a> <a href="#blog-SonyaCode" title="Blogposts">📝</a> <a href="https://github.com/processing/p5.js/issues?q=author%3ASonyaCode" title="Bug reports">🐛</a> <a href="https://github.com/processing/p5.js/commits?author=SonyaCode" title="Code">💻</a> <a href="#design-SonyaCode" title="Design">🎨</a> <a href="https://github.com/processing/p5.js/commits?author=SonyaCode" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/vtjl10"><img src="https://avatars.githubusercontent.com/u/139509124?v=4?s=64" width="64px;" alt="fuder.eth"/><br /><sub><b>fuder.eth</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=vtjl10" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/FerrinThreatt"><img src="https://avatars.githubusercontent.com/u/51208056?v=4?s=64" width="64px;" alt="FerrinThreatt"/><br /><sub><b>FerrinThreatt</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=FerrinThreatt" title="Documentation">📖</a></td>
        -      <td align="center" valign="top" width="16.66%"><a href="http://bensgilbert.com"><img src="https://avatars.githubusercontent.com/u/68397475?v=4?s=64" width="64px;" alt="Ben Gilbert"/><br /><sub><b>Ben Gilbert</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=bensgilbert" title="Code">💻</a></td>
             </tr>
           </tbody>
         </table>
        
        From 22bc8413d46761d7686beab48964f3a692cda90c Mon Sep 17 00:00:00 2001
        From: leopardracer <136604165+leopardracer@users.noreply.github.com>
        Date: Fri, 20 Jun 2025 00:54:30 +0300
        Subject: [PATCH 216/282] Update loading_displaying.js
        
        ---
         src/image/loading_displaying.js | 2 +-
         1 file changed, 1 insertion(+), 1 deletion(-)
        
        diff --git a/src/image/loading_displaying.js b/src/image/loading_displaying.js
        index c0ce679117..f257b2a0d3 100644
        --- a/src/image/loading_displaying.js
        +++ b/src/image/loading_displaying.js
        @@ -924,7 +924,7 @@ function _sAssign(sVal, iVal) {
          * destination rectangle. This may have the effect of zooming into the
          * subsection.
          *
        - * The tenth and eleventh paremeters, `xAlign` and `yAlign`, are also
        + * The tenth and eleventh parameters, `xAlign` and `yAlign`, are also
          * optional. They determine how to align the fitted subsection. `xAlign` can
          * be set to either `LEFT`, `RIGHT`, or `CENTER`. `yAlign` can be set to
          * either `TOP`, `BOTTOM`, or `CENTER`. By default, both `xAlign` and `yAlign`
        
        From 11df112005dff1252fb74dcd47bff94a5715027c Mon Sep 17 00:00:00 2001
        From: leopardracer <136604165+leopardracer@users.noreply.github.com>
        Date: Fri, 20 Jun 2025 00:54:51 +0300
        Subject: [PATCH 217/282] Update trigonometry.js
        
        ---
         src/math/trigonometry.js | 2 +-
         1 file changed, 1 insertion(+), 1 deletion(-)
        
        diff --git a/src/math/trigonometry.js b/src/math/trigonometry.js
        index 788dbfb1ff..69d8b7f366 100644
        --- a/src/math/trigonometry.js
        +++ b/src/math/trigonometry.js
        @@ -540,7 +540,7 @@ p5.prototype.degrees = angle => angle * constants.RAD_TO_DEG;
          *
          *   background(200);
          *
        - *   // Caclulate the angle conversion.
        + *   // Calculate the angle conversion.
          *   let deg = 45;
          *   let rad = radians(deg);
          *
        
        From 18ac6e3538fc7dd8cd3effd0be8e034973c67f7f Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Fri, 20 Jun 2025 10:39:03 +0000
        Subject: [PATCH 218/282] docs: update README.md [skip ci]
        
        ---
         README.md | 3 ++-
         1 file changed, 2 insertions(+), 1 deletion(-)
        
        diff --git a/README.md b/README.md
        index b7c4ec5bd6..8075410248 100644
        --- a/README.md
        +++ b/README.md
        @@ -1034,7 +1034,7 @@ We recognize all types of contributions. This project follows the [all-contribut
             <tr>
               <td align="center" valign="top" width="16.66%"><a href="http://abhinavcode13.github.io"><img src="https://avatars.githubusercontent.com/u/126642111?v=4?s=64" width="64px;" alt="Abhinav kumar"/><br /><sub><b>Abhinav kumar</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=Abhinavcode13" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/chhaski"><img src="https://avatars.githubusercontent.com/u/71788879?v=4?s=64" width="64px;" alt="chaski"/><br /><sub><b>chaski</b></sub></a><br /><a href="#research-chhaski" title="Research">🔬</a> <a href="https://github.com/processing/p5.js/commits?author=chhaski" title="Code">💻</a> <a href="#example-chhaski" title="Examples">💡</a></td>
        -      <td align="center" valign="top" width="16.66%"><a href="https://github.com/bensgilbert"><img src="https://avatars.githubusercontent.com/u/68397475?v=4?s=64" width="64px;" alt="Ben Gilbert"/><br /><sub><b>Ben Gilbert</b></sub></a><br /><a href="https://github.com/processing/p5.js/issues?q=author%3Abensgilbert" title="Bug reports">🐛</a> <a href="https://github.com/processing/p5.js/commits?author=bensgilbert" title="Code">💻</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="http://bensgilbert.com"><img src="https://avatars.githubusercontent.com/u/68397475?v=4?s=64" width="64px;" alt="Ben Gilbert"/><br /><sub><b>Ben Gilbert</b></sub></a><br /><a href="https://github.com/processing/p5.js/issues?q=author%3Abensgilbert" title="Bug reports">🐛</a> <a href="https://github.com/processing/p5.js/commits?author=bensgilbert" title="Code">💻</a></td>
               <td align="center" valign="top" width="16.66%"><a href="http://iamdanielmarino.com"><img src="https://avatars.githubusercontent.com/u/171375?v=4?s=64" width="64px;" alt="Daniel Marino"/><br /><sub><b>Daniel Marino</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=starzonmyarmz" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/shahmaz0/"><img src="https://avatars.githubusercontent.com/Shahmaz0?s=64" width="64px;" alt="Shahma Ansari"/><br /><sub><b>Shahma Ansari</b></sub></a><br /><a href="https://github.com/processing/p5.js/issues?q=author%3AShahmaz0" title="Bug reports">🐛</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/Manancode"><img src="https://avatars.githubusercontent.com/u/144525586?v=4?s=64" width="64px;" alt="Manan Arora"/><br /><sub><b>Manan Arora</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=Manancode" title="Documentation">📖</a></td>
        @@ -1156,6 +1156,7 @@ We recognize all types of contributions. This project follows the [all-contribut
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/SonyaCode"><img src="https://avatars.githubusercontent.com/u/99513449?v=4?s=64" width="64px;" alt="SonyaCode"/><br /><sub><b>SonyaCode</b></sub></a><br /><a href="#a11y-SonyaCode" title="Accessibility">️️️️♿️</a> <a href="#blog-SonyaCode" title="Blogposts">📝</a> <a href="https://github.com/processing/p5.js/issues?q=author%3ASonyaCode" title="Bug reports">🐛</a> <a href="https://github.com/processing/p5.js/commits?author=SonyaCode" title="Code">💻</a> <a href="#design-SonyaCode" title="Design">🎨</a> <a href="https://github.com/processing/p5.js/commits?author=SonyaCode" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/vtjl10"><img src="https://avatars.githubusercontent.com/u/139509124?v=4?s=64" width="64px;" alt="fuder.eth"/><br /><sub><b>fuder.eth</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=vtjl10" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/FerrinThreatt"><img src="https://avatars.githubusercontent.com/u/51208056?v=4?s=64" width="64px;" alt="FerrinThreatt"/><br /><sub><b>FerrinThreatt</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=FerrinThreatt" title="Documentation">📖</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="https://github.com/leopardracer"><img src="https://avatars.githubusercontent.com/u/136604165?v=4?s=64" width="64px;" alt="leopardracer"/><br /><sub><b>leopardracer</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=leopardracer" title="Documentation">📖</a></td>
             </tr>
           </tbody>
         </table>
        
        From ae3012187d58dd86ef1c9d89d5a5c4d78fbf59f2 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Fri, 20 Jun 2025 10:39:04 +0000
        Subject: [PATCH 219/282] docs: update .all-contributorsrc [skip ci]
        
        ---
         .all-contributorsrc | 9 +++++++++
         1 file changed, 9 insertions(+)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index e73f0a6655..c043ba5b5d 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -6956,6 +6956,15 @@
               "contributions": [
                 "doc"
               ]
        +    },
        +    {
        +      "login": "leopardracer",
        +      "name": "leopardracer",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/136604165?v=4",
        +      "profile": "https://github.com/leopardracer",
        +      "contributions": [
        +        "doc"
        +      ]
             }
           ],
           "repoType": "github",
        
        From aafe8c7dd56caa4f4bf734cf480f7fb60ced7a68 Mon Sep 17 00:00:00 2001
        From: kilavvy <140459108+kilavvy@users.noreply.github.com>
        Date: Sun, 22 Jun 2025 15:17:39 +0200
        Subject: [PATCH 220/282] Update documentation_style_guide.md
        
        ---
         contributor_docs/documentation_style_guide.md | 2 +-
         1 file changed, 1 insertion(+), 1 deletion(-)
        
        diff --git a/contributor_docs/documentation_style_guide.md b/contributor_docs/documentation_style_guide.md
        index be6a48ddda..c238180172 100644
        --- a/contributor_docs/documentation_style_guide.md
        +++ b/contributor_docs/documentation_style_guide.md
        @@ -4,7 +4,7 @@
         
         Hello! Welcome to the guidelines for writing p5.js documentation. This document is a remix of the following resources:
         
        -- Ruby on Rails [API Documentation Guidlines](https://guides.rubyonrails.org/api_documentation_guidelines.html) (CC BY-SA 4.0)
        +- Ruby on Rails [API Documentation Guidelines](https://guides.rubyonrails.org/api_documentation_guidelines.html) (CC BY-SA 4.0)
         - WordPress documentation guidelines for [accessibility](https://make.wordpress.org/docs/style-guide/general-guidelines/accessibility/) and [inclusivity](https://make.wordpress.org/docs/style-guide/general-guidelines/inclusivity/) (CC0)
         - Airbnb [JavaScript Style Guide](https://airbnb.io/javascript/) (MIT)
         
        
        From 6d0dce6acaf966284f20232c91f0fd5f1b4b7d96 Mon Sep 17 00:00:00 2001
        From: kilavvy <140459108+kilavvy@users.noreply.github.com>
        Date: Sun, 22 Jun 2025 15:18:45 +0200
        Subject: [PATCH 221/282] Update elginmclaren_gsoc_2018.md
        
        ---
         contributor_docs/project_wrapups/elginmclaren_gsoc_2018.md | 2 +-
         1 file changed, 1 insertion(+), 1 deletion(-)
        
        diff --git a/contributor_docs/project_wrapups/elginmclaren_gsoc_2018.md b/contributor_docs/project_wrapups/elginmclaren_gsoc_2018.md
        index 8b97c19e77..8207c5404f 100644
        --- a/contributor_docs/project_wrapups/elginmclaren_gsoc_2018.md
        +++ b/contributor_docs/project_wrapups/elginmclaren_gsoc_2018.md
        @@ -30,7 +30,7 @@ hello.p5js.org is likely to be many users’ first introduction to p5.js (and po
         
         
         ## Challenges
        -* Crowdsourcing the video content was fun and filled with delightful suprises; however, it was challenging to coordinate video-making tasks with community members over the summer (e.g. tight GSOC time constraints, people's summer vacations).
        +* Crowdsourcing the video content was fun and filled with delightful surprises; however, it was challenging to coordinate video-making tasks with community members over the summer (e.g. tight GSOC time constraints, people's summer vacations).
         * Creating a dynamic, post-production greenscreen effect was more difficult than I imagined. Using seriously.js for the canvas background removal worked well; however, setting videos to a neutral background color in After Effects was difficult without a neutral background.
         * When incorporating browserify to pre-process my javascript, I missed one crucial line of code. This required tremendous digging to figure out why it wouldn't compile. It set me back several days, but I learned  a lot!
         
        
        From 50dff769c464a199231ee479ecb2eb2866804009 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Sun, 22 Jun 2025 14:00:59 +0000
        Subject: [PATCH 222/282] docs: update README.md [skip ci]
        
        ---
         README.md | 1 +
         1 file changed, 1 insertion(+)
        
        diff --git a/README.md b/README.md
        index 8075410248..e4840ab423 100644
        --- a/README.md
        +++ b/README.md
        @@ -1157,6 +1157,7 @@ We recognize all types of contributions. This project follows the [all-contribut
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/vtjl10"><img src="https://avatars.githubusercontent.com/u/139509124?v=4?s=64" width="64px;" alt="fuder.eth"/><br /><sub><b>fuder.eth</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=vtjl10" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/FerrinThreatt"><img src="https://avatars.githubusercontent.com/u/51208056?v=4?s=64" width="64px;" alt="FerrinThreatt"/><br /><sub><b>FerrinThreatt</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=FerrinThreatt" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/leopardracer"><img src="https://avatars.githubusercontent.com/u/136604165?v=4?s=64" width="64px;" alt="leopardracer"/><br /><sub><b>leopardracer</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=leopardracer" title="Documentation">📖</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="https://github.com/kilavvy"><img src="https://avatars.githubusercontent.com/u/140459108?v=4?s=64" width="64px;" alt="kilavvy"/><br /><sub><b>kilavvy</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=kilavvy" title="Documentation">📖</a></td>
             </tr>
           </tbody>
         </table>
        
        From 08fed9012036ad8e63c3ee763b62ad71ea165903 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Sun, 22 Jun 2025 14:01:00 +0000
        Subject: [PATCH 223/282] docs: update .all-contributorsrc [skip ci]
        
        ---
         .all-contributorsrc | 9 +++++++++
         1 file changed, 9 insertions(+)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index c043ba5b5d..ee573b3a21 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -6965,6 +6965,15 @@
               "contributions": [
                 "doc"
               ]
        +    },
        +    {
        +      "login": "kilavvy",
        +      "name": "kilavvy",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/140459108?v=4",
        +      "profile": "https://github.com/kilavvy",
        +      "contributions": [
        +        "doc"
        +      ]
             }
           ],
           "repoType": "github",
        
        From 0c4e6cd793a97e384a5811ea5a37ac31d26de820 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Fri, 27 Jun 2025 16:38:08 +0000
        Subject: [PATCH 224/282] docs: update README.md [skip ci]
        
        ---
         README.md | 3 +++
         1 file changed, 3 insertions(+)
        
        diff --git a/README.md b/README.md
        index e4840ab423..8da9c0ab68 100644
        --- a/README.md
        +++ b/README.md
        @@ -1159,6 +1159,9 @@ We recognize all types of contributions. This project follows the [all-contribut
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/leopardracer"><img src="https://avatars.githubusercontent.com/u/136604165?v=4?s=64" width="64px;" alt="leopardracer"/><br /><sub><b>leopardracer</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=leopardracer" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/kilavvy"><img src="https://avatars.githubusercontent.com/u/140459108?v=4?s=64" width="64px;" alt="kilavvy"/><br /><sub><b>kilavvy</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=kilavvy" title="Documentation">📖</a></td>
             </tr>
        +    <tr>
        +      <td align="center" valign="top" width="16.66%"><a href="https://github.com/shivasankaran18"><img src="https://avatars.githubusercontent.com/u/148421597?v=4?s=64" width="64px;" alt="Shiva"/><br /><sub><b>Shiva</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=shivasankaran18" title="Documentation">📖</a></td>
        +    </tr>
           </tbody>
         </table>
         
        
        From e0863cb8e678e4eb5e729de696d561d195a4d6eb Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Fri, 27 Jun 2025 16:38:09 +0000
        Subject: [PATCH 225/282] docs: update .all-contributorsrc [skip ci]
        
        ---
         .all-contributorsrc | 9 +++++++++
         1 file changed, 9 insertions(+)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index ee573b3a21..c845c4788a 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -6974,6 +6974,15 @@
               "contributions": [
                 "doc"
               ]
        +    },
        +    {
        +      "login": "shivasankaran18",
        +      "name": "Shiva",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/148421597?v=4",
        +      "profile": "https://github.com/shivasankaran18",
        +      "contributions": [
        +        "doc"
        +      ]
             }
           ],
           "repoType": "github",
        
        From c767ed86c7583c9701c37940a85b741154fff053 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Sun, 29 Jun 2025 16:43:23 +0000
        Subject: [PATCH 226/282] docs: update README.md [skip ci]
        
        ---
         README.md | 1 +
         1 file changed, 1 insertion(+)
        
        diff --git a/README.md b/README.md
        index 8da9c0ab68..ac3e8115a5 100644
        --- a/README.md
        +++ b/README.md
        @@ -1161,6 +1161,7 @@ We recognize all types of contributions. This project follows the [all-contribut
             </tr>
             <tr>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/shivasankaran18"><img src="https://avatars.githubusercontent.com/u/148421597?v=4?s=64" width="64px;" alt="Shiva"/><br /><sub><b>Shiva</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=shivasankaran18" title="Documentation">📖</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="https://github.com/madhav2348"><img src="https://avatars.githubusercontent.com/u/161720210?v=4?s=64" width="64px;" alt="Madhav Majumdar"/><br /><sub><b>Madhav Majumdar</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=madhav2348" title="Code">💻</a></td>
             </tr>
           </tbody>
         </table>
        
        From 5038ff998afe5dc19c4ee0900576126aba718200 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Sun, 29 Jun 2025 16:43:24 +0000
        Subject: [PATCH 227/282] docs: update .all-contributorsrc [skip ci]
        
        ---
         .all-contributorsrc | 9 +++++++++
         1 file changed, 9 insertions(+)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index c845c4788a..314f5d381d 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -6983,6 +6983,15 @@
               "contributions": [
                 "doc"
               ]
        +    },
        +    {
        +      "login": "madhav2348",
        +      "name": "Madhav Majumdar",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/161720210?v=4",
        +      "profile": "https://github.com/madhav2348",
        +      "contributions": [
        +        "code"
        +      ]
             }
           ],
           "repoType": "github",
        
        From e1641aa64918473560340d5dbad53ae57b4f0bc7 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Wed, 9 Jul 2025 16:43:32 +0000
        Subject: [PATCH 228/282] docs: update README.md [skip ci]
        
        ---
         README.md | 1 +
         1 file changed, 1 insertion(+)
        
        diff --git a/README.md b/README.md
        index ac3e8115a5..2b72e8293c 100644
        --- a/README.md
        +++ b/README.md
        @@ -1162,6 +1162,7 @@ We recognize all types of contributions. This project follows the [all-contribut
             <tr>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/shivasankaran18"><img src="https://avatars.githubusercontent.com/u/148421597?v=4?s=64" width="64px;" alt="Shiva"/><br /><sub><b>Shiva</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=shivasankaran18" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/madhav2348"><img src="https://avatars.githubusercontent.com/u/161720210?v=4?s=64" width="64px;" alt="Madhav Majumdar"/><br /><sub><b>Madhav Majumdar</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=madhav2348" title="Code">💻</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="https://github.com/nking07049925"><img src="https://avatars.githubusercontent.com/u/11886663?v=4?s=64" width="64px;" alt="Nikita Korol"/><br /><sub><b>Nikita Korol</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=nking07049925" title="Code">💻</a></td>
             </tr>
           </tbody>
         </table>
        
        From 14397371568651dc5a4ef8f6eb0faca1ca0238c8 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Wed, 9 Jul 2025 16:43:33 +0000
        Subject: [PATCH 229/282] docs: update .all-contributorsrc [skip ci]
        
        ---
         .all-contributorsrc | 9 +++++++++
         1 file changed, 9 insertions(+)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index 314f5d381d..ad91e83d5f 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -6992,6 +6992,15 @@
               "contributions": [
                 "code"
               ]
        +    },
        +    {
        +      "login": "nking07049925",
        +      "name": "Nikita Korol",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/11886663?v=4",
        +      "profile": "https://github.com/nking07049925",
        +      "contributions": [
        +        "code"
        +      ]
             }
           ],
           "repoType": "github",
        
        From 33ae080b0c311979621299cea45a3214cbdad29c Mon Sep 17 00:00:00 2001
        From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
        Date: Thu, 17 Jul 2025 21:18:57 +0000
        Subject: [PATCH 230/282] Bump on-headers and morgan
        
        ---
        updated-dependencies:
        - dependency-name: on-headers
          dependency-version: 1.1.0
          dependency-type: indirect
        - dependency-name: morgan
          dependency-version: 1.10.1
          dependency-type: indirect
        ...
        
        Signed-off-by: dependabot[bot] <support@github.com>
        ---
         package-lock.json | 16 +++++++++-------
         1 file changed, 9 insertions(+), 7 deletions(-)
        
        diff --git a/package-lock.json b/package-lock.json
        index c4b5c08bcb..2329b4455e 100644
        --- a/package-lock.json
        +++ b/package-lock.json
        @@ -11547,16 +11547,17 @@
               }
             },
             "node_modules/morgan": {
        -      "version": "1.10.0",
        -      "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz",
        -      "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==",
        +      "version": "1.10.1",
        +      "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.1.tgz",
        +      "integrity": "sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==",
               "dev": true,
        +      "license": "MIT",
               "dependencies": {
                 "basic-auth": "~2.0.1",
                 "debug": "2.6.9",
                 "depd": "~2.0.0",
                 "on-finished": "~2.3.0",
        -        "on-headers": "~1.0.2"
        +        "on-headers": "~1.1.0"
               },
               "engines": {
                 "node": ">= 0.8.0"
        @@ -13339,10 +13340,11 @@
               }
             },
             "node_modules/on-headers": {
        -      "version": "1.0.2",
        -      "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
        -      "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
        +      "version": "1.1.0",
        +      "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
        +      "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==",
               "dev": true,
        +      "license": "MIT",
               "engines": {
                 "node": ">= 0.8"
               }
        
        From b9cdbd79987f333ccdeb1f4609657eed69d7131d Mon Sep 17 00:00:00 2001
        From: ksen0 <katie.kuksenok@gmail.com>
        Date: Thu, 17 Jul 2025 23:39:25 +0200
        Subject: [PATCH 231/282] 1.11.9
        
        ---
         package-lock.json | 4 ++--
         package.json      | 2 +-
         2 files changed, 3 insertions(+), 3 deletions(-)
        
        diff --git a/package-lock.json b/package-lock.json
        index c4b5c08bcb..54ce12aba4 100644
        --- a/package-lock.json
        +++ b/package-lock.json
        @@ -1,12 +1,12 @@
         {
           "name": "p5",
        -  "version": "1.11.8",
        +  "version": "1.11.9",
           "lockfileVersion": 3,
           "requires": true,
           "packages": {
             "": {
               "name": "p5",
        -      "version": "1.11.8",
        +      "version": "1.11.9",
               "license": "LGPL-2.1",
               "devDependencies": {
                 "@babel/core": "^7.7.7",
        diff --git a/package.json b/package.json
        index 24646e81a8..1345b0798c 100644
        --- a/package.json
        +++ b/package.json
        @@ -24,7 +24,7 @@
               "node --require @babel/register ./utils/sample-linter.js"
             ]
           },
        -  "version": "1.11.8",
        +  "version": "1.11.9",
           "devDependencies": {
             "@babel/core": "^7.7.7",
             "@babel/preset-env": "^7.10.2",
        
        From 784665d80b5b8e80172a88608a2e2ebbcf032fbb Mon Sep 17 00:00:00 2001
        From: Sajal-Kulshreshtha <sajalkulshreshtha9@gmail.com>
        Date: Fri, 18 Jul 2025 20:03:29 +0530
        Subject: [PATCH 232/282] Changing URL which was leading to somewhere else
        
        ---
         src/webgl/p5.RendererGL.js | 2 +-
         1 file changed, 1 insertion(+), 1 deletion(-)
        
        diff --git a/src/webgl/p5.RendererGL.js b/src/webgl/p5.RendererGL.js
        index d3864a8171..fa67acc34d 100644
        --- a/src/webgl/p5.RendererGL.js
        +++ b/src/webgl/p5.RendererGL.js
        @@ -2537,7 +2537,7 @@ p5.RendererGL = class RendererGL extends p5.Renderer {
         p5.prototype._assert3d = function (name) {
           if (!this._renderer.isP3D)
             throw new Error(
        -      `${name}() is only supported in WEBGL mode. If you'd like to use 3D graphics and WebGL, see  https://p5js.org/examples/form-3d-primitives.html for more information.`
        +      `${name}() is only supported in WEBGL mode. If you'd like to use 3D graphics and WebGL, see https://p5js.org/examples/3d-geometries/ for more information.`
             );
         };
         
        
        From 192c116fe5026cd995fac7dd5dbe69f3d3f76bcb Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Fri, 18 Jul 2025 17:52:02 +0000
        Subject: [PATCH 233/282] docs: update README.md [skip ci]
        
        ---
         README.md | 1 +
         1 file changed, 1 insertion(+)
        
        diff --git a/README.md b/README.md
        index 2b72e8293c..31b466fe45 100644
        --- a/README.md
        +++ b/README.md
        @@ -1163,6 +1163,7 @@ We recognize all types of contributions. This project follows the [all-contribut
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/shivasankaran18"><img src="https://avatars.githubusercontent.com/u/148421597?v=4?s=64" width="64px;" alt="Shiva"/><br /><sub><b>Shiva</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=shivasankaran18" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/madhav2348"><img src="https://avatars.githubusercontent.com/u/161720210?v=4?s=64" width="64px;" alt="Madhav Majumdar"/><br /><sub><b>Madhav Majumdar</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=madhav2348" title="Code">💻</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/nking07049925"><img src="https://avatars.githubusercontent.com/u/11886663?v=4?s=64" width="64px;" alt="Nikita Korol"/><br /><sub><b>Nikita Korol</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=nking07049925" title="Code">💻</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="https://github.com/skools-here"><img src="https://avatars.githubusercontent.com/u/174816600?v=4?s=64" width="64px;" alt="skools-here"/><br /><sub><b>skools-here</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=skools-here" title="Code">💻</a></td>
             </tr>
           </tbody>
         </table>
        
        From bdec6c2821a994b4f7916b6de2af539d2627e657 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Fri, 18 Jul 2025 17:52:03 +0000
        Subject: [PATCH 234/282] docs: update .all-contributorsrc [skip ci]
        
        ---
         .all-contributorsrc | 9 +++++++++
         1 file changed, 9 insertions(+)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index ad91e83d5f..5c63aa5ede 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -7001,6 +7001,15 @@
               "contributions": [
                 "code"
               ]
        +    },
        +    {
        +      "login": "skools-here",
        +      "name": "skools-here",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/174816600?v=4",
        +      "profile": "https://github.com/skools-here",
        +      "contributions": [
        +        "code"
        +      ]
             }
           ],
           "repoType": "github",
        
        From 4355fe9c78721d16b56743675957a3f922cdc68e Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Tue, 22 Jul 2025 10:12:06 +0000
        Subject: [PATCH 235/282] docs: update README.md [skip ci]
        
        ---
         README.md | 1 +
         1 file changed, 1 insertion(+)
        
        diff --git a/README.md b/README.md
        index 2b72e8293c..5cd15ec8de 100644
        --- a/README.md
        +++ b/README.md
        @@ -1163,6 +1163,7 @@ We recognize all types of contributions. This project follows the [all-contribut
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/shivasankaran18"><img src="https://avatars.githubusercontent.com/u/148421597?v=4?s=64" width="64px;" alt="Shiva"/><br /><sub><b>Shiva</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=shivasankaran18" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/madhav2348"><img src="https://avatars.githubusercontent.com/u/161720210?v=4?s=64" width="64px;" alt="Madhav Majumdar"/><br /><sub><b>Madhav Majumdar</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=madhav2348" title="Code">💻</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/nking07049925"><img src="https://avatars.githubusercontent.com/u/11886663?v=4?s=64" width="64px;" alt="Nikita Korol"/><br /><sub><b>Nikita Korol</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=nking07049925" title="Code">💻</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="https://leetcode.com/u/mudit_mah/"><img src="https://avatars.githubusercontent.com/u/140621191?v=4?s=64" width="64px;" alt="Mudit Maheshwari"/><br /><sub><b>Mudit Maheshwari</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=mudit06mah" title="Documentation">📖</a></td>
             </tr>
           </tbody>
         </table>
        
        From a1cb7af1791ac9c0f6d7a7315c39c2bc63890b34 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Tue, 22 Jul 2025 10:12:07 +0000
        Subject: [PATCH 236/282] docs: update .all-contributorsrc [skip ci]
        
        ---
         .all-contributorsrc | 9 +++++++++
         1 file changed, 9 insertions(+)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index ad91e83d5f..1efa2fac13 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -7001,6 +7001,15 @@
               "contributions": [
                 "code"
               ]
        +    },
        +    {
        +      "login": "mudit06mah",
        +      "name": "Mudit Maheshwari",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/140621191?v=4",
        +      "profile": "https://leetcode.com/u/mudit_mah/",
        +      "contributions": [
        +        "doc"
        +      ]
             }
           ],
           "repoType": "github",
        
        From 3d6302664cf0764624c9318d35c20003863b25a2 Mon Sep 17 00:00:00 2001
        From: Darren Shaw <shawdm@gmail.com>
        Date: Sun, 27 Jul 2025 13:59:17 +0100
        Subject: [PATCH 237/282] Fix parameter documentation for bezierPoint
        
        ---
         src/core/shape/curves.js | 8 ++++----
         1 file changed, 4 insertions(+), 4 deletions(-)
        
        diff --git a/src/core/shape/curves.js b/src/core/shape/curves.js
        index 0a3695118c..35363d07a8 100644
        --- a/src/core/shape/curves.js
        +++ b/src/core/shape/curves.js
        @@ -344,10 +344,10 @@ p5.prototype.bezierDetail = function(d) {
          * between them.
          *
          * @method bezierPoint
        - * @param {Number} a coordinate of first control point.
        - * @param {Number} b coordinate of first anchor point.
        - * @param {Number} c coordinate of second anchor point.
        - * @param {Number} d coordinate of second control point.
        + * @param {Number} a coordinate of first anchor point.
        + * @param {Number} b coordinate of first control point.
        + * @param {Number} c coordinate of second control point.
        + * @param {Number} d coordinate of second anchor point.
          * @param {Number} t amount to interpolate between 0 and 1.
          * @return {Number} coordinate of the point on the curve.
          *
        
        From 5ea3151b3cd2c1da97ba8a35df23360155f417f8 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Sun, 27 Jul 2025 16:40:54 +0000
        Subject: [PATCH 238/282] docs: update README.md [skip ci]
        
        ---
         README.md | 1 +
         1 file changed, 1 insertion(+)
        
        diff --git a/README.md b/README.md
        index 5cd15ec8de..d968c30682 100644
        --- a/README.md
        +++ b/README.md
        @@ -1164,6 +1164,7 @@ We recognize all types of contributions. This project follows the [all-contribut
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/madhav2348"><img src="https://avatars.githubusercontent.com/u/161720210?v=4?s=64" width="64px;" alt="Madhav Majumdar"/><br /><sub><b>Madhav Majumdar</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=madhav2348" title="Code">💻</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/nking07049925"><img src="https://avatars.githubusercontent.com/u/11886663?v=4?s=64" width="64px;" alt="Nikita Korol"/><br /><sub><b>Nikita Korol</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=nking07049925" title="Code">💻</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://leetcode.com/u/mudit_mah/"><img src="https://avatars.githubusercontent.com/u/140621191?v=4?s=64" width="64px;" alt="Mudit Maheshwari"/><br /><sub><b>Mudit Maheshwari</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=mudit06mah" title="Documentation">📖</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="http://acgillette.net"><img src="https://avatars.githubusercontent.com/u/18038450?v=4?s=64" width="64px;" alt="AC"/><br /><sub><b>AC</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=acgillette" title="Code">💻</a></td>
             </tr>
           </tbody>
         </table>
        
        From 5094d477277659966cb08696074697bf06e04e2a Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Sun, 27 Jul 2025 16:40:55 +0000
        Subject: [PATCH 239/282] docs: update .all-contributorsrc [skip ci]
        
        ---
         .all-contributorsrc | 9 +++++++++
         1 file changed, 9 insertions(+)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index 1efa2fac13..d57a2f4178 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -7010,6 +7010,15 @@
               "contributions": [
                 "doc"
               ]
        +    },
        +    {
        +      "login": "acgillette",
        +      "name": "AC",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/18038450?v=4",
        +      "profile": "http://acgillette.net",
        +      "contributions": [
        +        "code"
        +      ]
             }
           ],
           "repoType": "github",
        
        From c96fe1a732b2734d556d5b8cde51d06c35c6bb0e Mon Sep 17 00:00:00 2001
        From: Darren Shaw <shawdm@gmail.com>
        Date: Sun, 27 Jul 2025 17:52:55 +0100
        Subject: [PATCH 240/282] Fix parameter documentation for curvePoint
        
        ---
         src/core/shape/curves.js | 8 ++++----
         1 file changed, 4 insertions(+), 4 deletions(-)
        
        diff --git a/src/core/shape/curves.js b/src/core/shape/curves.js
        index 35363d07a8..fa4e6b395d 100644
        --- a/src/core/shape/curves.js
        +++ b/src/core/shape/curves.js
        @@ -950,10 +950,10 @@ p5.prototype.curveTightness = function(t) {
          * between them.
          *
          * @method curvePoint
        - * @param {Number} a coordinate of first anchor point.
        - * @param {Number} b coordinate of first control point.
        - * @param {Number} c coordinate of second control point.
        - * @param {Number} d coordinate of second anchor point.
        + * @param {Number} a coordinate of first control point.
        + * @param {Number} b coordinate of first anchor point.
        + * @param {Number} c coordinate of second anchor point.
        + * @param {Number} d coordinate of second control point.
          * @param {Number} t amount to interpolate between 0 and 1.
          * @return {Number} coordinate of a point on the curve.
          *
        
        From 8adfce0f5c1c741320996a363280415ff0984d39 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Sun, 27 Jul 2025 17:21:56 +0000
        Subject: [PATCH 241/282] docs: update README.md [skip ci]
        
        ---
         README.md | 1 +
         1 file changed, 1 insertion(+)
        
        diff --git a/README.md b/README.md
        index d968c30682..a0deb5abd1 100644
        --- a/README.md
        +++ b/README.md
        @@ -1165,6 +1165,7 @@ We recognize all types of contributions. This project follows the [all-contribut
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/nking07049925"><img src="https://avatars.githubusercontent.com/u/11886663?v=4?s=64" width="64px;" alt="Nikita Korol"/><br /><sub><b>Nikita Korol</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=nking07049925" title="Code">💻</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://leetcode.com/u/mudit_mah/"><img src="https://avatars.githubusercontent.com/u/140621191?v=4?s=64" width="64px;" alt="Mudit Maheshwari"/><br /><sub><b>Mudit Maheshwari</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=mudit06mah" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="http://acgillette.net"><img src="https://avatars.githubusercontent.com/u/18038450?v=4?s=64" width="64px;" alt="AC"/><br /><sub><b>AC</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=acgillette" title="Code">💻</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="https://darrenshaw.org"><img src="https://avatars.githubusercontent.com/u/157414?v=4?s=64" width="64px;" alt="Darren Shaw"/><br /><sub><b>Darren Shaw</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=shawdm" title="Documentation">📖</a></td>
             </tr>
           </tbody>
         </table>
        
        From 806a62b52abc897d207d940527c4a80e1039e4d2 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Sun, 27 Jul 2025 17:21:57 +0000
        Subject: [PATCH 242/282] docs: update .all-contributorsrc [skip ci]
        
        ---
         .all-contributorsrc | 9 +++++++++
         1 file changed, 9 insertions(+)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index d57a2f4178..b4200aed76 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -7019,6 +7019,15 @@
               "contributions": [
                 "code"
               ]
        +    },
        +    {
        +      "login": "shawdm",
        +      "name": "Darren Shaw",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/157414?v=4",
        +      "profile": "https://darrenshaw.org",
        +      "contributions": [
        +        "doc"
        +      ]
             }
           ],
           "repoType": "github",
        
        From 174d71662594e0d4ea1303b3830f9a500e25380d Mon Sep 17 00:00:00 2001
        From: Dave Pagurek <davepagurek@gmail.com>
        Date: Sun, 27 Jul 2025 14:07:52 -0400
        Subject: [PATCH 243/282] Bring 2.0 stroke ordering fixes to 1.x
        
        ---
         src/webgl/shaders/line.frag                       |   3 ++-
         src/webgl/shaders/line.vert                       |   5 +++--
         test/unit/visual/cases/webgl.js                   |  13 +++++++++++++
         .../000.png                                       | Bin 0 -> 558 bytes
         .../metadata.json                                 |   3 +++
         5 files changed, 21 insertions(+), 3 deletions(-)
         create mode 100644 test/unit/visual/screenshots/WebGL/Strokes/Strokes do not cut into fills in ortho mode/000.png
         create mode 100644 test/unit/visual/screenshots/WebGL/Strokes/Strokes do not cut into fills in ortho mode/metadata.json
        
        diff --git a/src/webgl/shaders/line.frag b/src/webgl/shaders/line.frag
        index f4b5a5c40b..a0ca059040 100644
        --- a/src/webgl/shaders/line.frag
        +++ b/src/webgl/shaders/line.frag
        @@ -1,4 +1,5 @@
        -precision mediump int;
        +precision highp int;
        +precision highp float;
         
         uniform vec4 uMaterialColor;
         uniform int uStrokeCap;
        diff --git a/src/webgl/shaders/line.vert b/src/webgl/shaders/line.vert
        index bc67818ed9..ed8329f8d1 100644
        --- a/src/webgl/shaders/line.vert
        +++ b/src/webgl/shaders/line.vert
        @@ -18,7 +18,8 @@
         
         #define PROCESSING_LINE_SHADER
         
        -precision mediump int;
        +precision highp int;
        +precision highp float;
         
         uniform mat4 uModelViewMatrix;
         uniform mat4 uProjectionMatrix;
        @@ -116,7 +117,7 @@ void main() {
         
           // Moving vertices slightly toward camera when far away 
           // https://github.com/processing/p5.js/issues/6956 
        -  float zOffset = mix(-0.00045, -1., facingCamera);
        +  float zOffset = mix(0., -1., facingCamera);
           float dynamicZAdjustment = mix(0.0, zOffset, distanceFactor); // Closer = less zAdjustment, farther = more
         
           posp.z -= dynamicZAdjustment;
        diff --git a/test/unit/visual/cases/webgl.js b/test/unit/visual/cases/webgl.js
        index 2822b1ead8..2f36feb806 100644
        --- a/test/unit/visual/cases/webgl.js
        +++ b/test/unit/visual/cases/webgl.js
        @@ -128,4 +128,17 @@ visualSuite('WebGL', function() {
               }
             );
           });
        +
        +  visualSuite('Strokes', function() {
        +    visualTest('Strokes do not cut into fills in ortho mode', (p5, screenshot) => {
        +      p5.createCanvas(50, 50, p5.WEBGL);
        +      p5.background(220);
        +      p5.stroke(8);
        +      p5.ortho();
        +      p5.rotateX(p5.PI/4);
        +      p5.rotateY(p5.PI/4);
        +      p5.box(30);
        +      screenshot();
        +    });
        +  });
         });
        diff --git a/test/unit/visual/screenshots/WebGL/Strokes/Strokes do not cut into fills in ortho mode/000.png b/test/unit/visual/screenshots/WebGL/Strokes/Strokes do not cut into fills in ortho mode/000.png
        new file mode 100644
        index 0000000000000000000000000000000000000000..344fa7ceb82638abc01fca7b1cc62bc871034cd0
        GIT binary patch
        literal 558
        zcmV+}0@3}6P)<h;3K|Lk000e1NJLTq001%o001%w1^@s69zTe&0005?Nkl<ZXhZFp
        zL5{;93`Nsr?vneTB+J|*%Z?Zc$#ntyn{U)bvTI8Nk7pY~Ue|TKx1{Shj{iH~_r2}=
        zzMbcp)YG=TGC(vy0V!93DOUy%9i%|if!D#y&-FVt3=KqDknvM2Xpjs$6p$W7&qxJj
        zhT0U!2tW?DWkg$>&7Cla2f{MKgb9J@gdWw@UXJws6D`vah}VKA*)4c9)Z8Eu2qd&L
        z7+MHSkSG9>><l|YkXeWsBWNM$f*=WP&8Ss=y&JGmA@~AeSeQ+AYhqf3-~)tZArnOA
        zp4_iJAV^%ZazvYcjCd_PIRea-F2zfdy^N2YCrd%<eyL706J`lW1!z61v+SgU^dRIy
        z#(+r$K^~%zwyheF0%BPhJq<?f&_SXQv!O-<nFZ)Q5qc{d1%wR|u`>-ao1~t_+tWuF
        zB+Ejy5QIQHGvt}+NSo2wv3nc8+5%$7ZRA%VdWFCQ$=KjULdvqE4<Np_@zIr*Iaupn
        zty9SK;~;BL=<h9va*y-_I&`3;_Bt<Q+w>z-21w6>8>BR3pFE;q9*ALR=?+%|c>(G;
        z&DRPNXcY_!0U6Oi-tBfIlp^ooAtRY~A{L-zAI&H$)Mg>Vp~Wf$41iFwGwm=TXhzUN
        wFj}F};y^dzDFkc_v}CttPrk~_ups;Y1CsA%2ZzUTR{#J207*qoM6N<$f)lUpcmMzZ
        
        literal 0
        HcmV?d00001
        
        diff --git a/test/unit/visual/screenshots/WebGL/Strokes/Strokes do not cut into fills in ortho mode/metadata.json b/test/unit/visual/screenshots/WebGL/Strokes/Strokes do not cut into fills in ortho mode/metadata.json
        new file mode 100644
        index 0000000000..2d4bfe30da
        --- /dev/null
        +++ b/test/unit/visual/screenshots/WebGL/Strokes/Strokes do not cut into fills in ortho mode/metadata.json	
        @@ -0,0 +1,3 @@
        +{
        +  "numScreenshots": 1
        +}
        \ No newline at end of file
        
        From 018dd9b41e0c9f692d85ba6a028cfa9567f64994 Mon Sep 17 00:00:00 2001
        From: Eric Rabinowitz <er@ericrabinowitz.com>
        Date: Tue, 29 Jul 2025 11:38:58 -0400
        Subject: [PATCH 244/282] remove incorrect mouseX/mouseY docs regarding WEBGL
         mode
        
        fixes #8002
        ---
         src/events/mouse.js | 24 ++++--------------------
         1 file changed, 4 insertions(+), 20 deletions(-)
        
        diff --git a/src/events/mouse.js b/src/events/mouse.js
        index 536c68f11f..c9a53cbe96 100644
        --- a/src/events/mouse.js
        +++ b/src/events/mouse.js
        @@ -109,14 +109,10 @@ p5.prototype._hasMouseInteracted = false;
         /**
          * A `Number` system variable that tracks the mouse's horizontal position.
          *
        - * In 2D mode, `mouseX` keeps track of the mouse's position relative to the
        + * `mouseX` keeps track of the mouse's position relative to the
          * top-left corner of the canvas. For example, if the mouse is 50 pixels from
          * the left edge of the canvas, then `mouseX` will be 50.
          *
        - * In WebGL mode, `mouseX` keeps track of the mouse's position relative to the
        - * center of the canvas. For example, if the mouse is 50 pixels to the right
        - * of the canvas' center, then `mouseX` will be 50.
        - *
          * If touch is used instead of the mouse, then `mouseX` will hold the
          * x-coordinate of the most recent touch point.
          *
        @@ -220,14 +216,10 @@ p5.prototype.mouseX = 0;
         /**
          * A `Number` system variable that tracks the mouse's vertical position.
          *
        - * In 2D mode, `mouseY` keeps track of the mouse's position relative to the
        + * `mouseY` keeps track of the mouse's position relative to the
          * top-left corner of the canvas. For example, if the mouse is 50 pixels from
          * the top edge of the canvas, then `mouseY` will be 50.
          *
        - * In WebGL mode, `mouseY` keeps track of the mouse's position relative to the
        - * center of the canvas. For example, if the mouse is 50 pixels below the
        - * canvas' center, then `mouseY` will be 50.
        - *
          * If touch is used instead of the mouse, then `mouseY` will hold the
          * y-coordinate of the most recent touch point.
          *
        @@ -332,16 +324,12 @@ p5.prototype.mouseY = 0;
          * A `Number` system variable that tracks the mouse's previous horizontal
          * position.
          *
        - * In 2D mode, `pmouseX` keeps track of the mouse's position relative to the
        + * `pmouseX` keeps track of the mouse's position relative to the
          * top-left corner of the canvas. Its value is
          * <a href="#/p5/mouseX">mouseX</a> from the previous frame. For example, if
          * the mouse was 50 pixels from the left edge of the canvas during the last
          * frame, then `pmouseX` will be 50.
          *
        - * In WebGL mode, `pmouseX` keeps track of the mouse's position relative to the
        - * center of the canvas. For example, if the mouse was 50 pixels to the right
        - * of the canvas' center during the last frame, then `pmouseX` will be 50.
        - *
          * If touch is used instead of the mouse, then `pmouseX` will hold the
          * x-coordinate of the last touch point.
          *
        @@ -401,16 +389,12 @@ p5.prototype.pmouseX = 0;
          * A `Number` system variable that tracks the mouse's previous vertical
          * position.
          *
        - * In 2D mode, `pmouseY` keeps track of the mouse's position relative to the
        + * `pmouseY` keeps track of the mouse's position relative to the
          * top-left corner of the canvas. Its value is
          * <a href="#/p5/mouseY">mouseY</a> from the previous frame. For example, if
          * the mouse was 50 pixels from the top edge of the canvas during the last
          * frame, then `pmouseY` will be 50.
          *
        - * In WebGL mode, `pmouseY` keeps track of the mouse's position relative to the
        - * center of the canvas. For example, if the mouse was 50 pixels below the
        - * canvas' center during the last frame, then `pmouseY` will be 50.
        - *
          * If touch is used instead of the mouse, then `pmouseY` will hold the
          * y-coordinate of the last touch point.
          *
        
        From 0e0186712bb0719825fdeb28e0d94bc980164433 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Tue, 29 Jul 2025 16:38:03 +0000
        Subject: [PATCH 245/282] docs: update README.md [skip ci]
        
        ---
         README.md | 3 +++
         1 file changed, 3 insertions(+)
        
        diff --git a/README.md b/README.md
        index a195db4f78..930167daef 100644
        --- a/README.md
        +++ b/README.md
        @@ -1166,7 +1166,10 @@ We recognize all types of contributions. This project follows the [all-contribut
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/skools-here"><img src="https://avatars.githubusercontent.com/u/174816600?v=4?s=64" width="64px;" alt="skools-here"/><br /><sub><b>skools-here</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=skools-here" title="Code">💻</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://leetcode.com/u/mudit_mah/"><img src="https://avatars.githubusercontent.com/u/140621191?v=4?s=64" width="64px;" alt="Mudit Maheshwari"/><br /><sub><b>Mudit Maheshwari</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=mudit06mah" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="http://acgillette.net"><img src="https://avatars.githubusercontent.com/u/18038450?v=4?s=64" width="64px;" alt="AC"/><br /><sub><b>AC</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=acgillette" title="Code">💻</a></td>
        +    </tr>
        +    <tr>
               <td align="center" valign="top" width="16.66%"><a href="https://darrenshaw.org"><img src="https://avatars.githubusercontent.com/u/157414?v=4?s=64" width="64px;" alt="Darren Shaw"/><br /><sub><b>Darren Shaw</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=shawdm" title="Documentation">📖</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="http://ericrabinowitz.com/"><img src="https://avatars.githubusercontent.com/u/3066943?v=4?s=64" width="64px;" alt="Eric Rabinowitz"/><br /><sub><b>Eric Rabinowitz</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=ericrav" title="Documentation">📖</a></td>
             </tr>
           </tbody>
         </table>
        
        From 73ee9d80320e6571dcf55d2d46272e41359997a0 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Tue, 29 Jul 2025 16:38:04 +0000
        Subject: [PATCH 246/282] docs: update .all-contributorsrc [skip ci]
        
        ---
         .all-contributorsrc | 9 +++++++++
         1 file changed, 9 insertions(+)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index f46e70a140..94a347b838 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -7037,6 +7037,15 @@
               "contributions": [
                 "doc"
               ]
        +    },
        +    {
        +      "login": "ericrav",
        +      "name": "Eric Rabinowitz",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/3066943?v=4",
        +      "profile": "http://ericrabinowitz.com/",
        +      "contributions": [
        +        "doc"
        +      ]
             }
           ],
           "repoType": "github",
        
        From ee282a7f409051ef2b7664d7899ffda3a2fe8055 Mon Sep 17 00:00:00 2001
        From: ksen0 <katie.kuksenok@gmail.com>
        Date: Thu, 31 Jul 2025 14:37:13 +0200
        Subject: [PATCH 247/282] 1.11.10-rc.0
        
        ---
         package-lock.json | 4 ++--
         package.json      | 2 +-
         2 files changed, 3 insertions(+), 3 deletions(-)
        
        diff --git a/package-lock.json b/package-lock.json
        index ab865a267f..c54f24b5d5 100644
        --- a/package-lock.json
        +++ b/package-lock.json
        @@ -1,12 +1,12 @@
         {
           "name": "p5",
        -  "version": "1.11.9",
        +  "version": "1.11.10-rc.0",
           "lockfileVersion": 3,
           "requires": true,
           "packages": {
             "": {
               "name": "p5",
        -      "version": "1.11.9",
        +      "version": "1.11.10-rc.0",
               "license": "LGPL-2.1",
               "devDependencies": {
                 "@babel/core": "^7.7.7",
        diff --git a/package.json b/package.json
        index 1345b0798c..fb45416be1 100644
        --- a/package.json
        +++ b/package.json
        @@ -24,7 +24,7 @@
               "node --require @babel/register ./utils/sample-linter.js"
             ]
           },
        -  "version": "1.11.9",
        +  "version": "1.11.10-rc.0",
           "devDependencies": {
             "@babel/core": "^7.7.7",
             "@babel/preset-env": "^7.10.2",
        
        From 943c6d319e1ab0a39b1395d923406c4282c6e910 Mon Sep 17 00:00:00 2001
        From: Abu Harish <abuharish186@gmail.com>
        Date: Thu, 31 Jul 2025 22:31:55 +0530
        Subject: [PATCH 248/282] Code block texturemode() fix
        
        ---
         src/webgl/material.js | 12 ++++++------
         1 file changed, 6 insertions(+), 6 deletions(-)
        
        diff --git a/src/webgl/material.js b/src/webgl/material.js
        index 5a8a7c427d..d3fbb8d0a6 100644
        --- a/src/webgl/material.js
        +++ b/src/webgl/material.js
        @@ -1917,18 +1917,18 @@ p5.prototype.texture = function (tex) {
          * to the pixel at coordinates `(u, v)` within an image. For example, the
          * corners of a rectangular image are mapped to the corners of a rectangle by default:
          *
        - * <code>
        + * ```js
          * // Apply the image as a texture.
          * texture(img);
          *
          * // Draw the rectangle.
          * rect(0, 0, 30, 50);
        - * </code>
        + * ```
          *
          * If the image in the code snippet above has dimensions of 300 x 500 pixels,
          * the same result could be achieved as follows:
          *
        - * <code>
        + * ```js
          * // Apply the image as a texture.
          * texture(img);
          *
        @@ -1952,7 +1952,7 @@ p5.prototype.texture = function (tex) {
          * vertex(0, 50, 0, 0, 500);
          *
          * endShape();
        - * </code>
        + * ```
          *
          * `textureMode()` changes the coordinate system for uv coordinates.
          *
        @@ -1962,7 +1962,7 @@ p5.prototype.texture = function (tex) {
          * be helpful for using the same code for multiple images of different sizes.
          * For example, the code snippet above could be rewritten as follows:
          *
        - * <code>
        + * ```js
          * // Set the texture mode to use normalized coordinates.
          * textureMode(NORMAL);
          *
        @@ -1989,7 +1989,7 @@ p5.prototype.texture = function (tex) {
          * vertex(0, 50, 0, 0, 1);
          *
          * endShape();
        - * </code>
        + * ```
          *
          * By default, `mode` is `IMAGE`, which scales uv coordinates to the
          * dimensions of the image. Calling `textureMode(IMAGE)` applies the default.
        
        From 252a7d68e96d838ddc62a74ed34c73be151b149d Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Thu, 31 Jul 2025 18:56:10 +0000
        Subject: [PATCH 249/282] docs: update README.md [skip ci]
        
        ---
         README.md | 1 +
         1 file changed, 1 insertion(+)
        
        diff --git a/README.md b/README.md
        index 930167daef..b14010367d 100644
        --- a/README.md
        +++ b/README.md
        @@ -1170,6 +1170,7 @@ We recognize all types of contributions. This project follows the [all-contribut
             <tr>
               <td align="center" valign="top" width="16.66%"><a href="https://darrenshaw.org"><img src="https://avatars.githubusercontent.com/u/157414?v=4?s=64" width="64px;" alt="Darren Shaw"/><br /><sub><b>Darren Shaw</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=shawdm" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="http://ericrabinowitz.com/"><img src="https://avatars.githubusercontent.com/u/3066943?v=4?s=64" width="64px;" alt="Eric Rabinowitz"/><br /><sub><b>Eric Rabinowitz</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=ericrav" title="Documentation">📖</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="https://github.com/abuharish02"><img src="https://avatars.githubusercontent.com/u/111338069?v=4?s=64" width="64px;" alt="Abu Harish Faridi"/><br /><sub><b>Abu Harish Faridi</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=abuharish02" title="Documentation">📖</a></td>
             </tr>
           </tbody>
         </table>
        
        From c2e31073b3437fbf04aeab98f94b79431f9b0749 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Thu, 31 Jul 2025 18:56:11 +0000
        Subject: [PATCH 250/282] docs: update .all-contributorsrc [skip ci]
        
        ---
         .all-contributorsrc | 9 +++++++++
         1 file changed, 9 insertions(+)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index 94a347b838..90508cee64 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -7046,6 +7046,15 @@
               "contributions": [
                 "doc"
               ]
        +    },
        +    {
        +      "login": "abuharish02",
        +      "name": "Abu Harish Faridi",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/111338069?v=4",
        +      "profile": "https://github.com/abuharish02",
        +      "contributions": [
        +        "doc"
        +      ]
             }
           ],
           "repoType": "github",
        
        From ad887d38abc48d16db74eb499be1055b847b9ccd Mon Sep 17 00:00:00 2001
        From: Amante' Woodley <awood0727@gmail.com>
        Date: Fri, 1 Aug 2025 15:01:17 -0400
        Subject: [PATCH 251/282] Replaced redudant else if statement with else
         statement
        
        Signed-off-by: Amante' Woodley <awood0727@gmail.com>
        
        Co-authored-by: Nia Perez <nia.perez.506@gmail.com>
        Co-authored-by: Kayla Bobo <kay3583@gmail.com>
        Co-authored-by: Silas Morgan <victorsmorgan@gmail.com>
        ---
         src/accessibility/outputs.js | 2 +-
         1 file changed, 1 insertion(+), 1 deletion(-)
        
        diff --git a/src/accessibility/outputs.js b/src/accessibility/outputs.js
        index d712c008bc..9781ffc839 100644
        --- a/src/accessibility/outputs.js
        +++ b/src/accessibility/outputs.js
        @@ -492,7 +492,7 @@ p5.prototype._accsOutput = function(f, args) {
           if (!this.ingredients.shapes[f]) {
             this.ingredients.shapes[f] = [include];
             //if other shapes of this type have been created
        -  } else if (this.ingredients.shapes[f] !== [include]) {
        +  } else{
             //for every shape of this type
             for (let y in this.ingredients.shapes[f]) {
               //compare it with current shape and if it already exists make add false
        
        From 972b601e08332fe45b55509bda61d3c0982d7de8 Mon Sep 17 00:00:00 2001
        From: Perminder Singh <127239756+perminder-17@users.noreply.github.com>
        Date: Sat, 2 Aug 2025 12:40:03 +0530
        Subject: [PATCH 252/282] Update src/accessibility/outputs.js
        
        ---
         src/accessibility/outputs.js | 3 ++-
         1 file changed, 2 insertions(+), 1 deletion(-)
        
        diff --git a/src/accessibility/outputs.js b/src/accessibility/outputs.js
        index 9781ffc839..83b8f4ed91 100644
        --- a/src/accessibility/outputs.js
        +++ b/src/accessibility/outputs.js
        @@ -492,7 +492,8 @@ p5.prototype._accsOutput = function(f, args) {
           if (!this.ingredients.shapes[f]) {
             this.ingredients.shapes[f] = [include];
             //if other shapes of this type have been created
        -  } else{
        +  } else {
        +``
             //for every shape of this type
             for (let y in this.ingredients.shapes[f]) {
               //compare it with current shape and if it already exists make add false
        
        From ffc3f4fd1b161b8ed3df324f5561d8b2572bc40c Mon Sep 17 00:00:00 2001
        From: Perminder Singh <127239756+perminder-17@users.noreply.github.com>
        Date: Sat, 2 Aug 2025 12:41:11 +0530
        Subject: [PATCH 253/282] Update src/accessibility/outputs.js
        
        ---
         src/accessibility/outputs.js | 1 -
         1 file changed, 1 deletion(-)
        
        diff --git a/src/accessibility/outputs.js b/src/accessibility/outputs.js
        index 83b8f4ed91..102d1d7186 100644
        --- a/src/accessibility/outputs.js
        +++ b/src/accessibility/outputs.js
        @@ -493,7 +493,6 @@ p5.prototype._accsOutput = function(f, args) {
             this.ingredients.shapes[f] = [include];
             //if other shapes of this type have been created
           } else {
        -``
             //for every shape of this type
             for (let y in this.ingredients.shapes[f]) {
               //compare it with current shape and if it already exists make add false
        
        From e7752dc6235ba7735f9a39d649b74791122e412a Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Sun, 10 Aug 2025 05:12:09 +0000
        Subject: [PATCH 254/282] docs: update README.md [skip ci]
        
        ---
         README.md | 1 +
         1 file changed, 1 insertion(+)
        
        diff --git a/README.md b/README.md
        index b14010367d..4955e10429 100644
        --- a/README.md
        +++ b/README.md
        @@ -1171,6 +1171,7 @@ We recognize all types of contributions. This project follows the [all-contribut
               <td align="center" valign="top" width="16.66%"><a href="https://darrenshaw.org"><img src="https://avatars.githubusercontent.com/u/157414?v=4?s=64" width="64px;" alt="Darren Shaw"/><br /><sub><b>Darren Shaw</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=shawdm" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="http://ericrabinowitz.com/"><img src="https://avatars.githubusercontent.com/u/3066943?v=4?s=64" width="64px;" alt="Eric Rabinowitz"/><br /><sub><b>Eric Rabinowitz</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=ericrav" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/abuharish02"><img src="https://avatars.githubusercontent.com/u/111338069?v=4?s=64" width="64px;" alt="Abu Harish Faridi"/><br /><sub><b>Abu Harish Faridi</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=abuharish02" title="Documentation">📖</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="https://github.com/vivekbopaliya"><img src="https://avatars.githubusercontent.com/u/122638553?v=4?s=64" width="64px;" alt="Vivek"/><br /><sub><b>Vivek</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=vivekbopaliya" title="Code">💻</a> <a href="#design-vivekbopaliya" title="Design">🎨</a> <a href="#userTesting-vivekbopaliya" title="User Testing">📓</a> <a href="#blog-vivekbopaliya" title="Blogposts">📝</a></td>
             </tr>
           </tbody>
         </table>
        
        From cc4f493bc8fd0d063b806935cb619fffa1392cea Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Sun, 10 Aug 2025 05:12:10 +0000
        Subject: [PATCH 255/282] docs: update .all-contributorsrc [skip ci]
        
        ---
         .all-contributorsrc | 12 ++++++++++++
         1 file changed, 12 insertions(+)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index 90508cee64..2c9c77e4e0 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -7055,6 +7055,18 @@
               "contributions": [
                 "doc"
               ]
        +    },
        +    {
        +      "login": "vivekbopaliya",
        +      "name": "Vivek",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/122638553?v=4",
        +      "profile": "https://github.com/vivekbopaliya",
        +      "contributions": [
        +        "code",
        +        "design",
        +        "userTesting",
        +        "blog"
        +      ]
             }
           ],
           "repoType": "github",
        
        From 4f469fb8f670a170c8e5ac4b012d5fd06b3a84eb Mon Sep 17 00:00:00 2001
        From: kit <1304340+ksen0@users.noreply.github.com>
        Date: Mon, 11 Aug 2025 21:15:48 +0200
        Subject: [PATCH 256/282] Update README.md
        
        ---
         README.md | 2 +-
         1 file changed, 1 insertion(+), 1 deletion(-)
        
        diff --git a/README.md b/README.md
        index 4955e10429..f935a94d7a 100644
        --- a/README.md
        +++ b/README.md
        @@ -112,7 +112,7 @@ Lead/Mentor Alumni
         
         ## Contributors
         
        -We recognize all types of contributions. This project follows the [all-contributors specification](https://github.com/all-contributors/all-contributors) and the [Emoji Key](https://allcontributors.org/docs/en/emoji-key) ✨ for contribution types. Instructions to add yourself or add contribution emojis to your name are [here](https://github.com/processing/p5.js/issues/2309). You can also post an issue or comment on a pull request with the text: `@all-contributors please add @YOUR-USERNAME for THINGS` (where `THINGS` is a comma-separated list of entries from the [list of possible contribution types](https://allcontributors.org/docs/en/emoji-key)) and our nice bot will add you.
        +We recognize all types of contributions. This project follows the [all-contributors specification](https://github.com/all-contributors/all-contributors) and the [Emoji Key](https://github.com/all-contributors/all-contributors/blob/master/docs/emoji-key.md) ✨ for contribution types. Instructions to add yourself or add contribution emojis to your name are [here](https://github.com/processing/p5.js/issues/2309). You can also post an issue or comment on a pull request with the text: `@all-contributors please add @YOUR-USERNAME for THINGS` (where `THINGS` is a comma-separated list of entries from the [list of possible contribution types](https://github.com/all-contributors/all-contributors/blob/master/docs/emoji-key.md)) and our nice bot will add you.
         
         <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
         <!-- prettier-ignore-start -->
        
        From e2a6c1eee5d05878f49098f0f4cb1aca99251dcb Mon Sep 17 00:00:00 2001
        From: ksen0 <kit@processingfoundation.org>
        Date: Mon, 11 Aug 2025 22:59:45 +0200
        Subject: [PATCH 257/282] mouse offscreen behaviors bugfix
        
        ---
         src/accessibility/outputs.js | 16 +++++++---------
         src/events/mouse.js          |  6 ++----
         2 files changed, 9 insertions(+), 13 deletions(-)
        
        diff --git a/src/accessibility/outputs.js b/src/accessibility/outputs.js
        index d712c008bc..bf203ddfd9 100644
        --- a/src/accessibility/outputs.js
        +++ b/src/accessibility/outputs.js
        @@ -579,19 +579,17 @@ p5.prototype._getPos = function (x, y) {
         function _canvasLocator(args, canvasWidth, canvasHeight) {
           const noRows = 10;
           const noCols = 10;
        +
           let x = args[0];
           let y = args[1];
        -  if (x < 0 || x >= canvasWidth || y < 0 || y >= canvasHeight) {
        -    return null;
        -  }
        +
           let locX = Math.floor(x / canvasWidth * noRows);
           let locY = Math.floor(y / canvasHeight * noCols);
        -  if (locX === noRows) {
        -    locX = locX - 1;
        -  }
        -  if (locY === noCols) {
        -    locY = locY - 1;
        -  }
        +
        +  // clamp out of bounds values
        +  locX = Math.min(Math.max(locX, 0), noRows - 1);
        +  locY = Math.min(Math.max(locY, 0), noCols - 1);
        +
           return {
             locX,
             locY
        diff --git a/src/events/mouse.js b/src/events/mouse.js
        index c9a53cbe96..40363a94a6 100644
        --- a/src/events/mouse.js
        +++ b/src/events/mouse.js
        @@ -810,15 +810,13 @@ p5.prototype._updateNextMouseCoords = function(e) {
               e
             );
         
        +    this._setProperty('movedX', e.movementX);
        +    this._setProperty('movedY', e.movementY);
             this._setProperty('mouseX', mousePos.x);
             this._setProperty('mouseY', mousePos.y);
             this._setProperty('winMouseX', mousePos.winX);
             this._setProperty('winMouseY', mousePos.winY);
         
        -    const deltaX = this.mouseX - this.pmouseX;
        -    const deltaY = this.mouseY - this.pmouseY;
        -    this._setProperty('movedX', deltaX);
        -    this._setProperty('movedY', deltaY);
           }
         
           if (!this._hasMouseInteracted) {
        
        From e6cbc1c80cdd2bf96fca76f180905c2518734c9d Mon Sep 17 00:00:00 2001
        From: Perminder Singh <127239756+perminder-17@users.noreply.github.com>
        Date: Mon, 18 Aug 2025 04:23:28 +0530
        Subject: [PATCH 258/282] updating Readme.md
        
        ---
         README.md | 1 +
         1 file changed, 1 insertion(+)
        
        diff --git a/README.md b/README.md
        index f935a94d7a..55ab687116 100644
        --- a/README.md
        +++ b/README.md
        @@ -103,6 +103,7 @@ Lead/Mentor Alumni
         | Graphics (WebGL) | [@RandomGamingDev](https://github.com/RandomGamingDev), [@aferriss](https://github.com/aferriss), [@davepagurek](https://github.com/davepagurek), [@lukeplowden](https://github.com/lukeplowden), [@perminder-17](https://github.com/perminder-17) |
         | i18n (hi) | [@Divyansh013](https://github.com/Divyansh013), [@takshittt](https://github.com/takshittt) |
         | i18n (zh) | [@limzykenneth](https://github.com/limzykenneth), [@lirenjie95](https://github.com/lirenjie95) |
        +| i18n (ko) | [@hana-cho](https://github.com/hana-cho) |
         | Math | [@GregStanton](https://github.com/GregStanton), [@holomorfo](https://github.com/holomorfo) |
         | p5.js-website | [@clairep94](https://github.com/clairep94), [@ksen0](https://github.com/ksen0) |
         | p5.sound.js | [@ogbabydiesal](https://github.com/ogbabydiesal) |
        
        From 8ded98b6d91be00008616af234187f12792cd0ac Mon Sep 17 00:00:00 2001
        From: Perminder Singh <127239756+perminder-17@users.noreply.github.com>
        Date: Mon, 18 Aug 2025 04:25:29 +0530
        Subject: [PATCH 259/282] Update stewards.yml
        
        ---
         stewards.yml | 4 ++++
         1 file changed, 4 insertions(+)
        
        diff --git a/stewards.yml b/stewards.yml
        index 451fee6b88..a4f7502422 100644
        --- a/stewards.yml
        +++ b/stewards.yml
        @@ -85,3 +85,7 @@ clairep94:
         coseeian:
           - Accessibility:
               - p5.js-website
        +
        +hana-cho:
        +  - i18n:
        +      - ko
        
        From c1cd3b99cf4776175dbcdd2a0c2ed14dbf985cef Mon Sep 17 00:00:00 2001
        From: ksen0 <ksen0@users.noreply.github.com>
        Date: Mon, 18 Aug 2025 05:25:21 +0000
        Subject: [PATCH 260/282] Update README table from stewards.yml
        
        ---
         README.md | 2 +-
         1 file changed, 1 insertion(+), 1 deletion(-)
        
        diff --git a/README.md b/README.md
        index 55ab687116..964c128c18 100644
        --- a/README.md
        +++ b/README.md
        @@ -102,8 +102,8 @@ Lead/Mentor Alumni
         | Graphics (p5.strands) | [@lukeplowden](https://github.com/lukeplowden) |
         | Graphics (WebGL) | [@RandomGamingDev](https://github.com/RandomGamingDev), [@aferriss](https://github.com/aferriss), [@davepagurek](https://github.com/davepagurek), [@lukeplowden](https://github.com/lukeplowden), [@perminder-17](https://github.com/perminder-17) |
         | i18n (hi) | [@Divyansh013](https://github.com/Divyansh013), [@takshittt](https://github.com/takshittt) |
        -| i18n (zh) | [@limzykenneth](https://github.com/limzykenneth), [@lirenjie95](https://github.com/lirenjie95) |
         | i18n (ko) | [@hana-cho](https://github.com/hana-cho) |
        +| i18n (zh) | [@limzykenneth](https://github.com/limzykenneth), [@lirenjie95](https://github.com/lirenjie95) |
         | Math | [@GregStanton](https://github.com/GregStanton), [@holomorfo](https://github.com/holomorfo) |
         | p5.js-website | [@clairep94](https://github.com/clairep94), [@ksen0](https://github.com/ksen0) |
         | p5.sound.js | [@ogbabydiesal](https://github.com/ogbabydiesal) |
        
        From b46597c6e2b8abb9f583fc30ed045e2b6373c0bd Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Tue, 19 Aug 2025 14:48:19 +0000
        Subject: [PATCH 261/282] docs: update README.md [skip ci]
        
        ---
         README.md | 1 +
         1 file changed, 1 insertion(+)
        
        diff --git a/README.md b/README.md
        index 964c128c18..3a6d108dd2 100644
        --- a/README.md
        +++ b/README.md
        @@ -1173,6 +1173,7 @@ We recognize all types of contributions. This project follows the [all-contribut
               <td align="center" valign="top" width="16.66%"><a href="http://ericrabinowitz.com/"><img src="https://avatars.githubusercontent.com/u/3066943?v=4?s=64" width="64px;" alt="Eric Rabinowitz"/><br /><sub><b>Eric Rabinowitz</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=ericrav" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/abuharish02"><img src="https://avatars.githubusercontent.com/u/111338069?v=4?s=64" width="64px;" alt="Abu Harish Faridi"/><br /><sub><b>Abu Harish Faridi</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=abuharish02" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/vivekbopaliya"><img src="https://avatars.githubusercontent.com/u/122638553?v=4?s=64" width="64px;" alt="Vivek"/><br /><sub><b>Vivek</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=vivekbopaliya" title="Code">💻</a> <a href="#design-vivekbopaliya" title="Design">🎨</a> <a href="#userTesting-vivekbopaliya" title="User Testing">📓</a> <a href="#blog-vivekbopaliya" title="Blogposts">📝</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="https://github.com/Iron-56"><img src="https://avatars.githubusercontent.com/u/79905912?v=4?s=64" width="64px;" alt="Nandu Krishna"/><br /><sub><b>Nandu Krishna</b></sub></a><br /><a href="https://github.com/processing/p5.js/issues?q=author%3AIron-56" title="Bug reports">🐛</a> <a href="https://github.com/processing/p5.js/commits?author=Iron-56" title="Code">💻</a></td>
             </tr>
           </tbody>
         </table>
        
        From 69169aea1745674ff733eb91f9e890cc7f94626f Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Tue, 19 Aug 2025 14:48:20 +0000
        Subject: [PATCH 262/282] docs: update .all-contributorsrc [skip ci]
        
        ---
         .all-contributorsrc | 10 ++++++++++
         1 file changed, 10 insertions(+)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index 2c9c77e4e0..494d5d11d5 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -7067,6 +7067,16 @@
                 "userTesting",
                 "blog"
               ]
        +    },
        +    {
        +      "login": "Iron-56",
        +      "name": "Nandu Krishna",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/79905912?v=4",
        +      "profile": "https://github.com/Iron-56",
        +      "contributions": [
        +        "bug",
        +        "code"
        +      ]
             }
           ],
           "repoType": "github",
        
        From 8ba480152fdc3142adfb5a0050b8abba13691532 Mon Sep 17 00:00:00 2001
        From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
        Date: Thu, 21 Aug 2025 15:29:05 +0000
        Subject: [PATCH 263/282] Bump sha.js from 2.4.11 to 2.4.12
        
        Bumps [sha.js](https://github.com/crypto-browserify/sha.js) from 2.4.11 to 2.4.12.
        - [Changelog](https://github.com/browserify/sha.js/blob/master/CHANGELOG.md)
        - [Commits](https://github.com/crypto-browserify/sha.js/compare/v2.4.11...v2.4.12)
        
        ---
        updated-dependencies:
        - dependency-name: sha.js
          dependency-version: 2.4.12
          dependency-type: indirect
        ...
        
        Signed-off-by: dependabot[bot] <support@github.com>
        ---
         package-lock.json | 352 +++++++++++++++++++++++++++++++++++++++++-----
         1 file changed, 316 insertions(+), 36 deletions(-)
        
        diff --git a/package-lock.json b/package-lock.json
        index c54f24b5d5..880a87247b 100644
        --- a/package-lock.json
        +++ b/package-lock.json
        @@ -2807,6 +2807,22 @@
               "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
               "dev": true
             },
        +    "node_modules/available-typed-arrays": {
        +      "version": "1.0.7",
        +      "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
        +      "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
        +      "dev": true,
        +      "license": "MIT",
        +      "dependencies": {
        +        "possible-typed-array-names": "^1.0.0"
        +      },
        +      "engines": {
        +        "node": ">= 0.4"
        +      },
        +      "funding": {
        +        "url": "https://github.com/sponsors/ljharb"
        +      }
        +    },
             "node_modules/aws-sign2": {
               "version": "0.5.0",
               "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz",
        @@ -3843,16 +3859,47 @@
               }
             },
             "node_modules/call-bind": {
        -      "version": "1.0.7",
        -      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
        -      "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
        +      "version": "1.0.8",
        +      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
        +      "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
               "dev": true,
        +      "license": "MIT",
               "dependencies": {
        +        "call-bind-apply-helpers": "^1.0.0",
                 "es-define-property": "^1.0.0",
        -        "es-errors": "^1.3.0",
        -        "function-bind": "^1.1.2",
                 "get-intrinsic": "^1.2.4",
        -        "set-function-length": "^1.2.1"
        +        "set-function-length": "^1.2.2"
        +      },
        +      "engines": {
        +        "node": ">= 0.4"
        +      },
        +      "funding": {
        +        "url": "https://github.com/sponsors/ljharb"
        +      }
        +    },
        +    "node_modules/call-bind-apply-helpers": {
        +      "version": "1.0.2",
        +      "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
        +      "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
        +      "dev": true,
        +      "license": "MIT",
        +      "dependencies": {
        +        "es-errors": "^1.3.0",
        +        "function-bind": "^1.1.2"
        +      },
        +      "engines": {
        +        "node": ">= 0.4"
        +      }
        +    },
        +    "node_modules/call-bound": {
        +      "version": "1.0.4",
        +      "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
        +      "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
        +      "dev": true,
        +      "license": "MIT",
        +      "dependencies": {
        +        "call-bind-apply-helpers": "^1.0.2",
        +        "get-intrinsic": "^1.3.0"
               },
               "engines": {
                 "node": ">= 0.4"
        @@ -5318,6 +5365,21 @@
                 "url": "https://github.com/sponsors/sindresorhus"
               }
             },
        +    "node_modules/dunder-proto": {
        +      "version": "1.0.1",
        +      "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
        +      "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
        +      "dev": true,
        +      "license": "MIT",
        +      "dependencies": {
        +        "call-bind-apply-helpers": "^1.0.1",
        +        "es-errors": "^1.3.0",
        +        "gopd": "^1.2.0"
        +      },
        +      "engines": {
        +        "node": ">= 0.4"
        +      }
        +    },
             "node_modules/duplexer": {
               "version": "0.1.1",
               "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
        @@ -5444,13 +5506,11 @@
               }
             },
             "node_modules/es-define-property": {
        -      "version": "1.0.0",
        -      "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
        -      "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
        +      "version": "1.0.1",
        +      "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
        +      "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
               "dev": true,
        -      "dependencies": {
        -        "get-intrinsic": "^1.2.4"
        -      },
        +      "license": "MIT",
               "engines": {
                 "node": ">= 0.4"
               }
        @@ -5464,6 +5524,19 @@
                 "node": ">= 0.4"
               }
             },
        +    "node_modules/es-object-atoms": {
        +      "version": "1.1.1",
        +      "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
        +      "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
        +      "dev": true,
        +      "license": "MIT",
        +      "dependencies": {
        +        "es-errors": "^1.3.0"
        +      },
        +      "engines": {
        +        "node": ">= 0.4"
        +      }
        +    },
             "node_modules/es5-ext": {
               "version": "0.10.37",
               "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.37.tgz",
        @@ -6893,6 +6966,22 @@
               "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
               "dev": true
             },
        +    "node_modules/for-each": {
        +      "version": "0.3.5",
        +      "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
        +      "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
        +      "dev": true,
        +      "license": "MIT",
        +      "dependencies": {
        +        "is-callable": "^1.2.7"
        +      },
        +      "engines": {
        +        "node": ">= 0.4"
        +      },
        +      "funding": {
        +        "url": "https://github.com/sponsors/ljharb"
        +      }
        +    },
             "node_modules/for-in": {
               "version": "1.0.2",
               "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
        @@ -7062,16 +7151,22 @@
               }
             },
             "node_modules/get-intrinsic": {
        -      "version": "1.2.4",
        -      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
        -      "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
        +      "version": "1.3.0",
        +      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
        +      "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
               "dev": true,
        +      "license": "MIT",
               "dependencies": {
        +        "call-bind-apply-helpers": "^1.0.2",
        +        "es-define-property": "^1.0.1",
                 "es-errors": "^1.3.0",
        +        "es-object-atoms": "^1.1.1",
                 "function-bind": "^1.1.2",
        -        "has-proto": "^1.0.1",
        -        "has-symbols": "^1.0.3",
        -        "hasown": "^2.0.0"
        +        "get-proto": "^1.0.1",
        +        "gopd": "^1.2.0",
        +        "has-symbols": "^1.1.0",
        +        "hasown": "^2.0.2",
        +        "math-intrinsics": "^1.1.0"
               },
               "engines": {
                 "node": ">= 0.4"
        @@ -7086,6 +7181,20 @@
               "integrity": "sha512-TtY/sbOemiMKPRUDDanGCSgBYe7Mf0vbRsWnBZ+9yghpZ1MvcpSpuZFjHdEeY/LZjZy0vdLjS77L6HosisFiug==",
               "dev": true
             },
        +    "node_modules/get-proto": {
        +      "version": "1.0.1",
        +      "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
        +      "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
        +      "dev": true,
        +      "license": "MIT",
        +      "dependencies": {
        +        "dunder-proto": "^1.0.1",
        +        "es-object-atoms": "^1.0.0"
        +      },
        +      "engines": {
        +        "node": ">= 0.4"
        +      }
        +    },
             "node_modules/get-stream": {
               "version": "3.0.0",
               "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
        @@ -7246,12 +7355,13 @@
               }
             },
             "node_modules/gopd": {
        -      "version": "1.0.1",
        -      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
        -      "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
        +      "version": "1.2.0",
        +      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
        +      "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
               "dev": true,
        -      "dependencies": {
        -        "get-intrinsic": "^1.1.3"
        +      "license": "MIT",
        +      "engines": {
        +        "node": ">= 0.4"
               },
               "funding": {
                 "url": "https://github.com/sponsors/ljharb"
        @@ -7946,11 +8056,12 @@
                 "url": "https://github.com/sponsors/ljharb"
               }
             },
        -    "node_modules/has-proto": {
        -      "version": "1.0.3",
        -      "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
        -      "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
        +    "node_modules/has-symbols": {
        +      "version": "1.1.0",
        +      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
        +      "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
               "dev": true,
        +      "license": "MIT",
               "engines": {
                 "node": ">= 0.4"
               },
        @@ -7958,11 +8069,15 @@
                 "url": "https://github.com/sponsors/ljharb"
               }
             },
        -    "node_modules/has-symbols": {
        -      "version": "1.0.3",
        -      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
        -      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
        +    "node_modules/has-tostringtag": {
        +      "version": "1.0.2",
        +      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
        +      "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
               "dev": true,
        +      "license": "MIT",
        +      "dependencies": {
        +        "has-symbols": "^1.0.3"
        +      },
               "engines": {
                 "node": ">= 0.4"
               },
        @@ -9124,6 +9239,19 @@
                 "node": ">=0.10.0"
               }
             },
        +    "node_modules/is-callable": {
        +      "version": "1.2.7",
        +      "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
        +      "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
        +      "dev": true,
        +      "license": "MIT",
        +      "engines": {
        +        "node": ">= 0.4"
        +      },
        +      "funding": {
        +        "url": "https://github.com/sponsors/ljharb"
        +      }
        +    },
             "node_modules/is-ci": {
               "version": "3.0.1",
               "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz",
        @@ -9454,6 +9582,22 @@
                 "node": ">=0.10.0"
               }
             },
        +    "node_modules/is-typed-array": {
        +      "version": "1.1.15",
        +      "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
        +      "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
        +      "dev": true,
        +      "license": "MIT",
        +      "dependencies": {
        +        "which-typed-array": "^1.1.16"
        +      },
        +      "engines": {
        +        "node": ">= 0.4"
        +      },
        +      "funding": {
        +        "url": "https://github.com/sponsors/ljharb"
        +      }
        +    },
             "node_modules/is-typedarray": {
               "version": "1.0.0",
               "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
        @@ -10682,6 +10826,16 @@
                 "node": ">= 12"
               }
             },
        +    "node_modules/math-intrinsics": {
        +      "version": "1.1.0",
        +      "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
        +      "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
        +      "dev": true,
        +      "license": "MIT",
        +      "engines": {
        +        "node": ">= 0.4"
        +      }
        +    },
             "node_modules/maxmin": {
               "version": "2.1.0",
               "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-2.1.0.tgz",
        @@ -14346,6 +14500,16 @@
                 "npm": ">=1.0.0"
               }
             },
        +    "node_modules/possible-typed-array-names": {
        +      "version": "1.1.0",
        +      "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
        +      "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
        +      "dev": true,
        +      "license": "MIT",
        +      "engines": {
        +        "node": ">= 0.4"
        +      }
        +    },
             "node_modules/prelude-ls": {
               "version": "1.2.1",
               "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
        @@ -15870,18 +16034,54 @@
               "dev": true
             },
             "node_modules/sha.js": {
        -      "version": "2.4.11",
        -      "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
        -      "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
        +      "version": "2.4.12",
        +      "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz",
        +      "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==",
               "dev": true,
        +      "license": "(MIT AND BSD-3-Clause)",
               "dependencies": {
        -        "inherits": "^2.0.1",
        -        "safe-buffer": "^5.0.1"
        +        "inherits": "^2.0.4",
        +        "safe-buffer": "^5.2.1",
        +        "to-buffer": "^1.2.0"
               },
               "bin": {
                 "sha.js": "bin.js"
        +      },
        +      "engines": {
        +        "node": ">= 0.10"
        +      },
        +      "funding": {
        +        "url": "https://github.com/sponsors/ljharb"
               }
             },
        +    "node_modules/sha.js/node_modules/inherits": {
        +      "version": "2.0.4",
        +      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
        +      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
        +      "dev": true,
        +      "license": "ISC"
        +    },
        +    "node_modules/sha.js/node_modules/safe-buffer": {
        +      "version": "5.2.1",
        +      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
        +      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
        +      "dev": true,
        +      "funding": [
        +        {
        +          "type": "github",
        +          "url": "https://github.com/sponsors/feross"
        +        },
        +        {
        +          "type": "patreon",
        +          "url": "https://www.patreon.com/feross"
        +        },
        +        {
        +          "type": "consulting",
        +          "url": "https://feross.org/support"
        +        }
        +      ],
        +      "license": "MIT"
        +    },
             "node_modules/shasum": {
               "version": "1.0.2",
               "resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz",
        @@ -16781,6 +16981,49 @@
                 "node": ">=0.6.0"
               }
             },
        +    "node_modules/to-buffer": {
        +      "version": "1.2.1",
        +      "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.1.tgz",
        +      "integrity": "sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==",
        +      "dev": true,
        +      "license": "MIT",
        +      "dependencies": {
        +        "isarray": "^2.0.5",
        +        "safe-buffer": "^5.2.1",
        +        "typed-array-buffer": "^1.0.3"
        +      },
        +      "engines": {
        +        "node": ">= 0.4"
        +      }
        +    },
        +    "node_modules/to-buffer/node_modules/isarray": {
        +      "version": "2.0.5",
        +      "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
        +      "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
        +      "dev": true,
        +      "license": "MIT"
        +    },
        +    "node_modules/to-buffer/node_modules/safe-buffer": {
        +      "version": "5.2.1",
        +      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
        +      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
        +      "dev": true,
        +      "funding": [
        +        {
        +          "type": "github",
        +          "url": "https://github.com/sponsors/feross"
        +        },
        +        {
        +          "type": "patreon",
        +          "url": "https://www.patreon.com/feross"
        +        },
        +        {
        +          "type": "consulting",
        +          "url": "https://feross.org/support"
        +        }
        +      ],
        +      "license": "MIT"
        +    },
             "node_modules/to-fast-properties": {
               "version": "2.0.0",
               "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
        @@ -16923,6 +17166,21 @@
                 "node": ">= 0.6"
               }
             },
        +    "node_modules/typed-array-buffer": {
        +      "version": "1.0.3",
        +      "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
        +      "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
        +      "dev": true,
        +      "license": "MIT",
        +      "dependencies": {
        +        "call-bound": "^1.0.3",
        +        "es-errors": "^1.3.0",
        +        "is-typed-array": "^1.1.14"
        +      },
        +      "engines": {
        +        "node": ">= 0.4"
        +      }
        +    },
             "node_modules/typedarray": {
               "version": "0.0.6",
               "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
        @@ -17438,6 +17696,28 @@
               "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=",
               "dev": true
             },
        +    "node_modules/which-typed-array": {
        +      "version": "1.1.19",
        +      "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz",
        +      "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==",
        +      "dev": true,
        +      "license": "MIT",
        +      "dependencies": {
        +        "available-typed-arrays": "^1.0.7",
        +        "call-bind": "^1.0.8",
        +        "call-bound": "^1.0.4",
        +        "for-each": "^0.3.5",
        +        "get-proto": "^1.0.1",
        +        "gopd": "^1.2.0",
        +        "has-tostringtag": "^1.0.2"
        +      },
        +      "engines": {
        +        "node": ">= 0.4"
        +      },
        +      "funding": {
        +        "url": "https://github.com/sponsors/ljharb"
        +      }
        +    },
             "node_modules/widest-line": {
               "version": "4.0.1",
               "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz",
        
        From b6e748bcfafd65b415817df0deb445b39c26a4c5 Mon Sep 17 00:00:00 2001
        From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
        Date: Thu, 21 Aug 2025 15:44:31 +0000
        Subject: [PATCH 264/282] Bump cipher-base from 1.0.4 to 1.0.6
        
        Bumps [cipher-base](https://github.com/crypto-browserify/cipher-base) from 1.0.4 to 1.0.6.
        - [Changelog](https://github.com/browserify/cipher-base/blob/master/CHANGELOG.md)
        - [Commits](https://github.com/crypto-browserify/cipher-base/compare/v1.0.4...v1.0.6)
        
        ---
        updated-dependencies:
        - dependency-name: cipher-base
          dependency-version: 1.0.6
          dependency-type: indirect
        ...
        
        Signed-off-by: dependabot[bot] <support@github.com>
        ---
         package-lock.json | 42 +++++++++++++++++++++++++++++++++++++-----
         1 file changed, 37 insertions(+), 5 deletions(-)
        
        diff --git a/package-lock.json b/package-lock.json
        index c54f24b5d5..d525a71cdf 100644
        --- a/package-lock.json
        +++ b/package-lock.json
        @@ -4027,15 +4027,47 @@
               "dev": true
             },
             "node_modules/cipher-base": {
        -      "version": "1.0.4",
        -      "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
        -      "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
        +      "version": "1.0.6",
        +      "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz",
        +      "integrity": "sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==",
               "dev": true,
        +      "license": "MIT",
               "dependencies": {
        -        "inherits": "^2.0.1",
        -        "safe-buffer": "^5.0.1"
        +        "inherits": "^2.0.4",
        +        "safe-buffer": "^5.2.1"
        +      },
        +      "engines": {
        +        "node": ">= 0.10"
               }
             },
        +    "node_modules/cipher-base/node_modules/inherits": {
        +      "version": "2.0.4",
        +      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
        +      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
        +      "dev": true,
        +      "license": "ISC"
        +    },
        +    "node_modules/cipher-base/node_modules/safe-buffer": {
        +      "version": "5.2.1",
        +      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
        +      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
        +      "dev": true,
        +      "funding": [
        +        {
        +          "type": "github",
        +          "url": "https://github.com/sponsors/feross"
        +        },
        +        {
        +          "type": "patreon",
        +          "url": "https://www.patreon.com/feross"
        +        },
        +        {
        +          "type": "consulting",
        +          "url": "https://feross.org/support"
        +        }
        +      ],
        +      "license": "MIT"
        +    },
             "node_modules/clean-stack": {
               "version": "4.2.0",
               "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz",
        
        From c0b5418a940333d8633e28980e8ea273a2affaf2 Mon Sep 17 00:00:00 2001
        From: ksen0 <kit@processingfoundation.org>
        Date: Thu, 21 Aug 2025 08:28:11 +0200
        Subject: [PATCH 265/282] Calculate mouse movement delta depending on pointer
         lock
        
        ---
         src/events/mouse.js | 27 +++++++++++++++++++++++++--
         1 file changed, 25 insertions(+), 2 deletions(-)
        
        diff --git a/src/events/mouse.js b/src/events/mouse.js
        index 40363a94a6..a4c604aaa3 100644
        --- a/src/events/mouse.js
        +++ b/src/events/mouse.js
        @@ -19,6 +19,11 @@ import * as constants from '../core/constants';
          *
          * Note: `movedX` continues updating even when
          * <a href="#/p5/requestPointerLock">requestPointerLock()</a> is active.
        + * But keep in mind that during an active pointer lock, mouseX and pmouseX
        + * are not locked, so `movedX` is based on
        + * <a href="https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/movementX">the MouseEvent's movementX</a>
        + * value. This value may behave different in different browsers when the user
        + * is zoomed in or out.
          *
          * @property {Number} movedX
          * @readOnly
        @@ -810,13 +815,31 @@ p5.prototype._updateNextMouseCoords = function(e) {
               e
             );
         
        -    this._setProperty('movedX', e.movementX);
        -    this._setProperty('movedY', e.movementY);
        +
             this._setProperty('mouseX', mousePos.x);
             this._setProperty('mouseY', mousePos.y);
             this._setProperty('winMouseX', mousePos.winX);
             this._setProperty('winMouseY', mousePos.winY);
         
        +    if (document.pointerLockElement === null) {
        +      // https://developer.mozilla.org/en-US/docs/Web/API/Document/pointerLockElement
        +      // "The pointerLockElement ... is null if lock is pending, pointer is unlocked,
        +      // or the target is in another document."
        +      // In this case, we use mouseX/Y and pmousX/Y to calculate the distance,
        +      // which allows movedX/Y to look consistent at different zoom levels acorss
        +      // browsers.
        +      const deltaX = this.mouseX - this.pmouseX;
        +      const deltaY = this.mouseY - this.pmouseY;
        +      this._setProperty('movedX', deltaX);
        +      this._setProperty('movedY', deltaY);
        +    }
        +    else {
        +      // Because mouseX/Y and pmouseX/Y are locked, the elements movementX/Y
        +      // is used for movedX/Y - this maz behave differently on different
        +      // browsers at different zoom levels.
        +      this._setProperty('movedX', e.movementX);
        +      this._setProperty('movedY', e.movementY);
        +    }
           }
         
           if (!this._hasMouseInteracted) {
        
        From 36668ba7158ad8a196b6f3da1d0fea15cab0ce25 Mon Sep 17 00:00:00 2001
        From: ksen0 <kit@processingfoundation.org>
        Date: Thu, 21 Aug 2025 17:59:13 +0200
        Subject: [PATCH 266/282] Added manual test for movedX/Y and requestPointerLock
        
        ---
         src/events/mouse.js                           |  8 ++---
         .../pointer-lock-movedx/index.html            | 16 ++++++++++
         .../pointer-lock-movedx/sketch.js             | 31 +++++++++++++++++++
         3 files changed, 51 insertions(+), 4 deletions(-)
         create mode 100644 test/manual-test-examples/mouse-events/pointer-lock-movedx/index.html
         create mode 100644 test/manual-test-examples/mouse-events/pointer-lock-movedx/sketch.js
        
        diff --git a/src/events/mouse.js b/src/events/mouse.js
        index a4c604aaa3..a4937066b3 100644
        --- a/src/events/mouse.js
        +++ b/src/events/mouse.js
        @@ -21,9 +21,9 @@ import * as constants from '../core/constants';
          * <a href="#/p5/requestPointerLock">requestPointerLock()</a> is active.
          * But keep in mind that during an active pointer lock, mouseX and pmouseX
          * are not locked, so `movedX` is based on
        - * <a href="https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/movementX">the MouseEvent's movementX</a>
        - * value. This value may behave different in different browsers when the user
        - * is zoomed in or out.
        + * <a href="https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/movementX">the MouseEvent's movementX value</a>
        + * (which may behave differently in different browsers when the user
        + * is zoomed in or out).
          *
          * @property {Number} movedX
          * @readOnly
        @@ -835,7 +835,7 @@ p5.prototype._updateNextMouseCoords = function(e) {
             }
             else {
               // Because mouseX/Y and pmouseX/Y are locked, the elements movementX/Y
        -      // is used for movedX/Y - this maz behave differently on different
        +      // is used for movedX/Y - this may behave differently on different
               // browsers at different zoom levels.
               this._setProperty('movedX', e.movementX);
               this._setProperty('movedY', e.movementY);
        diff --git a/test/manual-test-examples/mouse-events/pointer-lock-movedx/index.html b/test/manual-test-examples/mouse-events/pointer-lock-movedx/index.html
        new file mode 100644
        index 0000000000..202329a285
        --- /dev/null
        +++ b/test/manual-test-examples/mouse-events/pointer-lock-movedx/index.html
        @@ -0,0 +1,16 @@
        +<!DOCTYPE html>
        +<html>
        +  <head>
        +  <script language="javascript" type="text/javascript" src="../../../../lib/p5.js"></script>
        +  </head>
        +
        +  <body>
        +    <h1>Manual test for movedX/Y with/without zoom and with/without pointer lock</h1>
        +    <ul>
        +      <li>If you move the mouse around, you should see 1 moving circle and 1 still. While <strong>dragging mouse</strong>, they should move at the same rate.</li>
        +      <li>After zooming in/out, on all browsers, the circles should still move visually a constant distance relative to each other.</li>
        +      <li>Press any key to request pointer lock. Background will be pink if and only if pointer is locked. Now, if you <strong>drag the mouse</strong>, the small circle should be static (because mouseX/Y are locked) and the big circle should move unsurprisingly.</li>
        +    </ul>
        +      <script language="javascript" type="text/javascript" src="sketch.js"></script>
        +  </body>
        +</html>
        diff --git a/test/manual-test-examples/mouse-events/pointer-lock-movedx/sketch.js b/test/manual-test-examples/mouse-events/pointer-lock-movedx/sketch.js
        new file mode 100644
        index 0000000000..05a02a1b00
        --- /dev/null
        +++ b/test/manual-test-examples/mouse-events/pointer-lock-movedx/sketch.js
        @@ -0,0 +1,31 @@
        +function setup() {
        +  createCanvas(400, 400);
        +}
        +
        +let x = 200;
        +let y = 200;
        +function draw() {
        +  if (document.pointerLockElement === null){
        +    background(220);
        +  } else{
        +    background(200,0,200);
        +  }
        +
        +  text(movedX, 20, 20);
        +  text(movedY, 20, 40);
        +  text(mouseX, 50, 20);
        +  text(mouseY, 50, 40);
        +  circle(mouseX, mouseY, 30);
        +
        +  //https://editor.p5js.org/SableRaf/sketches/zAXl3tNm5
        +  if(mouseIsPressed){
        +    x += movedX;
        +    y += movedY;
        +  }
        +
        +  circle(x, y, 50);
        +
        +}
        +function keyPressed() {
        +  requestPointerLock();
        +}
        \ No newline at end of file
        
        From f6a6bca6bd8dc874da999c5463179e968c6a16f9 Mon Sep 17 00:00:00 2001
        From: kit <1304340+ksen0@users.noreply.github.com>
        Date: Thu, 21 Aug 2025 21:05:43 +0200
        Subject: [PATCH 267/282] Update src/events/mouse.js
        
        Co-authored-by: Perminder Singh <127239756+perminder-17@users.noreply.github.com>
        ---
         src/events/mouse.js | 2 +-
         1 file changed, 1 insertion(+), 1 deletion(-)
        
        diff --git a/src/events/mouse.js b/src/events/mouse.js
        index a4937066b3..7dc7d6081d 100644
        --- a/src/events/mouse.js
        +++ b/src/events/mouse.js
        @@ -825,7 +825,7 @@ p5.prototype._updateNextMouseCoords = function(e) {
               // https://developer.mozilla.org/en-US/docs/Web/API/Document/pointerLockElement
               // "The pointerLockElement ... is null if lock is pending, pointer is unlocked,
               // or the target is in another document."
        -      // In this case, we use mouseX/Y and pmousX/Y to calculate the distance,
        +      // In this case, we use mouseX/Y and pmouseX/Y to calculate the distance,
               // which allows movedX/Y to look consistent at different zoom levels acorss
               // browsers.
               const deltaX = this.mouseX - this.pmouseX;
        
        From 4c24f730a9e0e0661c208d410505bb0b2888b7b7 Mon Sep 17 00:00:00 2001
        From: kit <1304340+ksen0@users.noreply.github.com>
        Date: Thu, 21 Aug 2025 21:05:48 +0200
        Subject: [PATCH 268/282] Update src/events/mouse.js
        
        Co-authored-by: Perminder Singh <127239756+perminder-17@users.noreply.github.com>
        ---
         src/events/mouse.js | 2 +-
         1 file changed, 1 insertion(+), 1 deletion(-)
        
        diff --git a/src/events/mouse.js b/src/events/mouse.js
        index 7dc7d6081d..52d2fc7f28 100644
        --- a/src/events/mouse.js
        +++ b/src/events/mouse.js
        @@ -826,7 +826,7 @@ p5.prototype._updateNextMouseCoords = function(e) {
               // "The pointerLockElement ... is null if lock is pending, pointer is unlocked,
               // or the target is in another document."
               // In this case, we use mouseX/Y and pmouseX/Y to calculate the distance,
        -      // which allows movedX/Y to look consistent at different zoom levels acorss
        +      // which allows movedX/Y to look consistent at different zoom levels across
               // browsers.
               const deltaX = this.mouseX - this.pmouseX;
               const deltaY = this.mouseY - this.pmouseY;
        
        From 852162bb90b53d2e55f285bf3c6fe10dea4f05c9 Mon Sep 17 00:00:00 2001
        From: ksen0 <kit@processingfoundation.org>
        Date: Thu, 21 Aug 2025 22:36:42 +0200
        Subject: [PATCH 269/282] Update movedX/Y documentation
        
        ---
         src/events/mouse.js | 7 ++++++-
         1 file changed, 6 insertions(+), 1 deletion(-)
        
        diff --git a/src/events/mouse.js b/src/events/mouse.js
        index 52d2fc7f28..7d83626962 100644
        --- a/src/events/mouse.js
        +++ b/src/events/mouse.js
        @@ -20,7 +20,7 @@ import * as constants from '../core/constants';
          * Note: `movedX` continues updating even when
          * <a href="#/p5/requestPointerLock">requestPointerLock()</a> is active.
          * But keep in mind that during an active pointer lock, mouseX and pmouseX
        - * are not locked, so `movedX` is based on
        + * are locked, so `movedX` is based on
          * <a href="https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/movementX">the MouseEvent's movementX value</a>
          * (which may behave differently in different browsers when the user
          * is zoomed in or out).
        @@ -69,6 +69,11 @@ p5.prototype.movedX = 0;
          *
          * Note: `movedY` continues updating even when
          * <a href="#/p5/requestPointerLock">requestPointerLock()</a> is active.
        + * But keep in mind that during an active pointer lock, mouseX and pmouseX
        + * are locked, so `movedX` is based on
        + * <a href="https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/movementX">the MouseEvent's movementX value</a>
        + * (which may behave differently in different browsers when the user
        + * is zoomed in or out).
          *
          * @property {Number} movedY
          * @readOnly
        
        From d8155c0551054a4a1078e70b89ac010c362460e3 Mon Sep 17 00:00:00 2001
        From: ksen0 <kit@processingfoundation.org>
        Date: Fri, 22 Aug 2025 00:07:18 +0200
        Subject: [PATCH 270/282] 1.11.10-rc.1
        
        ---
         package-lock.json | 4 ++--
         package.json      | 2 +-
         2 files changed, 3 insertions(+), 3 deletions(-)
        
        diff --git a/package-lock.json b/package-lock.json
        index c54f24b5d5..66f64ad1fb 100644
        --- a/package-lock.json
        +++ b/package-lock.json
        @@ -1,12 +1,12 @@
         {
           "name": "p5",
        -  "version": "1.11.10-rc.0",
        +  "version": "1.11.10-rc.1",
           "lockfileVersion": 3,
           "requires": true,
           "packages": {
             "": {
               "name": "p5",
        -      "version": "1.11.10-rc.0",
        +      "version": "1.11.10-rc.1",
               "license": "LGPL-2.1",
               "devDependencies": {
                 "@babel/core": "^7.7.7",
        diff --git a/package.json b/package.json
        index fb45416be1..a8601f6833 100644
        --- a/package.json
        +++ b/package.json
        @@ -24,7 +24,7 @@
               "node --require @babel/register ./utils/sample-linter.js"
             ]
           },
        -  "version": "1.11.10-rc.0",
        +  "version": "1.11.10-rc.1",
           "devDependencies": {
             "@babel/core": "^7.7.7",
             "@babel/preset-env": "^7.10.2",
        
        From 193e1d7a3b98470525da838588a9f2b54b6a79fa Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Fri, 22 Aug 2025 06:13:20 +0000
        Subject: [PATCH 271/282] docs: update README.md [skip ci]
        
        ---
         README.md | 1 +
         1 file changed, 1 insertion(+)
        
        diff --git a/README.md b/README.md
        index 3a6d108dd2..b8562f168e 100644
        --- a/README.md
        +++ b/README.md
        @@ -1174,6 +1174,7 @@ We recognize all types of contributions. This project follows the [all-contribut
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/abuharish02"><img src="https://avatars.githubusercontent.com/u/111338069?v=4?s=64" width="64px;" alt="Abu Harish Faridi"/><br /><sub><b>Abu Harish Faridi</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=abuharish02" title="Documentation">📖</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/vivekbopaliya"><img src="https://avatars.githubusercontent.com/u/122638553?v=4?s=64" width="64px;" alt="Vivek"/><br /><sub><b>Vivek</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=vivekbopaliya" title="Code">💻</a> <a href="#design-vivekbopaliya" title="Design">🎨</a> <a href="#userTesting-vivekbopaliya" title="User Testing">📓</a> <a href="#blog-vivekbopaliya" title="Blogposts">📝</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/Iron-56"><img src="https://avatars.githubusercontent.com/u/79905912?v=4?s=64" width="64px;" alt="Nandu Krishna"/><br /><sub><b>Nandu Krishna</b></sub></a><br /><a href="https://github.com/processing/p5.js/issues?q=author%3AIron-56" title="Bug reports">🐛</a> <a href="https://github.com/processing/p5.js/commits?author=Iron-56" title="Code">💻</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="https://dorinetipo.vercel.app/"><img src="https://avatars.githubusercontent.com/u/105214329?v=4?s=64" width="64px;" alt="Dorine Tipo "/><br /><sub><b>Dorine Tipo </b></sub></a><br /><a href="#blog-MissTipo" title="Blogposts">📝</a> <a href="https://github.com/processing/p5.js/commits?author=MissTipo" title="Code">💻</a> <a href="#eventOrganizing-MissTipo" title="Event Organizing">📋</a> <a href="#research-MissTipo" title="Research">🔬</a> <a href="#promotion-MissTipo" title="Promotion">📣</a> <a href="#tutorial-MissTipo" title="Tutorials">✅</a></td>
             </tr>
           </tbody>
         </table>
        
        From 7049785f001be755dc850edb9a17de4bd7a554bb Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Fri, 22 Aug 2025 06:13:21 +0000
        Subject: [PATCH 272/282] docs: update .all-contributorsrc [skip ci]
        
        ---
         .all-contributorsrc | 14 ++++++++++++++
         1 file changed, 14 insertions(+)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index 494d5d11d5..03fa68e0cd 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -7077,6 +7077,20 @@
                 "bug",
                 "code"
               ]
        +    },
        +    {
        +      "login": "MissTipo",
        +      "name": "Dorine Tipo ",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/105214329?v=4",
        +      "profile": "https://dorinetipo.vercel.app/",
        +      "contributions": [
        +        "blog",
        +        "code",
        +        "eventOrganizing",
        +        "research",
        +        "promotion",
        +        "tutorial"
        +      ]
             }
           ],
           "repoType": "github",
        
        From a82b80253d2b122e0769857ca68b9c47ed70826a Mon Sep 17 00:00:00 2001
        From: ksen0 <kit@processingfoundation.org>
        Date: Sat, 23 Aug 2025 10:44:10 +0200
        Subject: [PATCH 273/282] 1.11.10
        
        ---
         package-lock.json | 4 ++--
         package.json      | 2 +-
         2 files changed, 3 insertions(+), 3 deletions(-)
        
        diff --git a/package-lock.json b/package-lock.json
        index 66f64ad1fb..60127284b1 100644
        --- a/package-lock.json
        +++ b/package-lock.json
        @@ -1,12 +1,12 @@
         {
           "name": "p5",
        -  "version": "1.11.10-rc.1",
        +  "version": "1.11.10",
           "lockfileVersion": 3,
           "requires": true,
           "packages": {
             "": {
               "name": "p5",
        -      "version": "1.11.10-rc.1",
        +      "version": "1.11.10",
               "license": "LGPL-2.1",
               "devDependencies": {
                 "@babel/core": "^7.7.7",
        diff --git a/package.json b/package.json
        index a8601f6833..70c6d2fd1e 100644
        --- a/package.json
        +++ b/package.json
        @@ -24,7 +24,7 @@
               "node --require @babel/register ./utils/sample-linter.js"
             ]
           },
        -  "version": "1.11.10-rc.1",
        +  "version": "1.11.10",
           "devDependencies": {
             "@babel/core": "^7.7.7",
             "@babel/preset-env": "^7.10.2",
        
        From 145c222af7e7cc92d40d07cae885ad213de7ca52 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Mon, 25 Aug 2025 20:42:07 +0000
        Subject: [PATCH 274/282] docs: update README.md [skip ci]
        
        ---
         README.md | 3 +++
         1 file changed, 3 insertions(+)
        
        diff --git a/README.md b/README.md
        index b8562f168e..3aa7c10ce8 100644
        --- a/README.md
        +++ b/README.md
        @@ -1176,6 +1176,9 @@ We recognize all types of contributions. This project follows the [all-contribut
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/Iron-56"><img src="https://avatars.githubusercontent.com/u/79905912?v=4?s=64" width="64px;" alt="Nandu Krishna"/><br /><sub><b>Nandu Krishna</b></sub></a><br /><a href="https://github.com/processing/p5.js/issues?q=author%3AIron-56" title="Bug reports">🐛</a> <a href="https://github.com/processing/p5.js/commits?author=Iron-56" title="Code">💻</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://dorinetipo.vercel.app/"><img src="https://avatars.githubusercontent.com/u/105214329?v=4?s=64" width="64px;" alt="Dorine Tipo "/><br /><sub><b>Dorine Tipo </b></sub></a><br /><a href="#blog-MissTipo" title="Blogposts">📝</a> <a href="https://github.com/processing/p5.js/commits?author=MissTipo" title="Code">💻</a> <a href="#eventOrganizing-MissTipo" title="Event Organizing">📋</a> <a href="#research-MissTipo" title="Research">🔬</a> <a href="#promotion-MissTipo" title="Promotion">📣</a> <a href="#tutorial-MissTipo" title="Tutorials">✅</a></td>
             </tr>
        +    <tr>
        +      <td align="center" valign="top" width="16.66%"><a href="https://kangjung.github.io/game/index.html"><img src="https://avatars.githubusercontent.com/u/28768760?v=4?s=64" width="64px;" alt="JUNGMIN KANG"/><br /><sub><b>JUNGMIN KANG</b></sub></a><br /><a href="#translation-kangjung" title="Translation">🌍</a></td>
        +    </tr>
           </tbody>
         </table>
         
        
        From ce65c8eddf32210fe3432cd23120bf29c629b016 Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Mon, 25 Aug 2025 20:42:08 +0000
        Subject: [PATCH 275/282] docs: update .all-contributorsrc [skip ci]
        
        ---
         .all-contributorsrc | 9 +++++++++
         1 file changed, 9 insertions(+)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index 03fa68e0cd..5fe48515c4 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -7091,6 +7091,15 @@
                 "promotion",
                 "tutorial"
               ]
        +    },
        +    {
        +      "login": "kangjung",
        +      "name": "JUNGMIN KANG",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/28768760?v=4",
        +      "profile": "https://kangjung.github.io/game/index.html",
        +      "contributions": [
        +        "translation"
        +      ]
             }
           ],
           "repoType": "github",
        
        From 3a20a57297180062fd92150d9b8d30d842df70de Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Mon, 25 Aug 2025 20:42:22 +0000
        Subject: [PATCH 276/282] docs: update README.md [skip ci]
        
        ---
         README.md | 3 +++
         1 file changed, 3 insertions(+)
        
        diff --git a/README.md b/README.md
        index b8562f168e..b9b0ac708c 100644
        --- a/README.md
        +++ b/README.md
        @@ -1176,6 +1176,9 @@ We recognize all types of contributions. This project follows the [all-contribut
               <td align="center" valign="top" width="16.66%"><a href="https://github.com/Iron-56"><img src="https://avatars.githubusercontent.com/u/79905912?v=4?s=64" width="64px;" alt="Nandu Krishna"/><br /><sub><b>Nandu Krishna</b></sub></a><br /><a href="https://github.com/processing/p5.js/issues?q=author%3AIron-56" title="Bug reports">🐛</a> <a href="https://github.com/processing/p5.js/commits?author=Iron-56" title="Code">💻</a></td>
               <td align="center" valign="top" width="16.66%"><a href="https://dorinetipo.vercel.app/"><img src="https://avatars.githubusercontent.com/u/105214329?v=4?s=64" width="64px;" alt="Dorine Tipo "/><br /><sub><b>Dorine Tipo </b></sub></a><br /><a href="#blog-MissTipo" title="Blogposts">📝</a> <a href="https://github.com/processing/p5.js/commits?author=MissTipo" title="Code">💻</a> <a href="#eventOrganizing-MissTipo" title="Event Organizing">📋</a> <a href="#research-MissTipo" title="Research">🔬</a> <a href="#promotion-MissTipo" title="Promotion">📣</a> <a href="#tutorial-MissTipo" title="Tutorials">✅</a></td>
             </tr>
        +    <tr>
        +      <td align="center" valign="top" width="16.66%"><a href="https://github.com/hana-cho"><img src="https://avatars.githubusercontent.com/u/51312538?v=4?s=64" width="64px;" alt="Hana Cho"/><br /><sub><b>Hana Cho</b></sub></a><br /><a href="#translation-hana-cho" title="Translation">🌍</a></td>
        +    </tr>
           </tbody>
         </table>
         
        
        From e9c9c11c5ac9a37a25a5e10fbefdbeea02a54a9e Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Mon, 25 Aug 2025 20:42:23 +0000
        Subject: [PATCH 277/282] docs: update .all-contributorsrc [skip ci]
        
        ---
         .all-contributorsrc | 9 +++++++++
         1 file changed, 9 insertions(+)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index 03fa68e0cd..3257e3a711 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -7091,6 +7091,15 @@
                 "promotion",
                 "tutorial"
               ]
        +    },
        +    {
        +      "login": "hana-cho",
        +      "name": "Hana Cho",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/51312538?v=4",
        +      "profile": "https://github.com/hana-cho",
        +      "contributions": [
        +        "translation"
        +      ]
             }
           ],
           "repoType": "github",
        
        From e102815685b0d01e4b1be01060d683d7deec6b35 Mon Sep 17 00:00:00 2001
        From: AlzaAlzaki76 <aallzaakii@gmail.com>
        Date: Wed, 27 Aug 2025 16:28:11 +0800
        Subject: [PATCH 278/282] Fix misspellings in comment
        
        ---
         src/core/friendly_errors/sketch_reader.js | 2 +-
         src/core/friendly_errors/stacktrace.js    | 2 +-
         2 files changed, 2 insertions(+), 2 deletions(-)
        
        diff --git a/src/core/friendly_errors/sketch_reader.js b/src/core/friendly_errors/sketch_reader.js
        index b70e86bf96..145f285958 100644
        --- a/src/core/friendly_errors/sketch_reader.js
        +++ b/src/core/friendly_errors/sketch_reader.js
        @@ -380,7 +380,7 @@ if (typeof IS_MINIFIED !== 'undefined') {
           const fesCodeReader = () => {
             //moveAhead will determine if a match is found outside
             //the setup and draw function. If a match is found then
        -    //to prevent further potential reporting we will exit immidiately
        +    //to prevent further potential reporting we will exit immediately
             let moveAhead = globalConstFuncCheck();
             if (moveAhead) return;
             let code = '';
        diff --git a/src/core/friendly_errors/stacktrace.js b/src/core/friendly_errors/stacktrace.js
        index fe6a1b5722..c4e079ac4b 100644
        --- a/src/core/friendly_errors/stacktrace.js
        +++ b/src/core/friendly_errors/stacktrace.js
        @@ -78,7 +78,7 @@ function ErrorStackParser() {
                   .replace(/^\s+/, '')
                   .replace(/\(eval code/g, '(');
         
        -        // capture and preseve the parenthesized location "(/foo/my bar.js:12:87)" in
        +        // capture and preserve the parenthesized location "(/foo/my bar.js:12:87)" in
                 // case it has spaces in it, as the string is split on \s+ later on
                 let location = sanitizedLine.match(/ (\((.+):(\d+):(\d+)\)$)/);
         
        
        From a8be432b4edc8467f38de4c5d955e4271f857bec Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Wed, 27 Aug 2025 17:58:20 +0000
        Subject: [PATCH 279/282] docs: update README.md [skip ci]
        
        ---
         README.md | 1 +
         1 file changed, 1 insertion(+)
        
        diff --git a/README.md b/README.md
        index 3aa7c10ce8..e29236f926 100644
        --- a/README.md
        +++ b/README.md
        @@ -1178,6 +1178,7 @@ We recognize all types of contributions. This project follows the [all-contribut
             </tr>
             <tr>
               <td align="center" valign="top" width="16.66%"><a href="https://kangjung.github.io/game/index.html"><img src="https://avatars.githubusercontent.com/u/28768760?v=4?s=64" width="64px;" alt="JUNGMIN KANG"/><br /><sub><b>JUNGMIN KANG</b></sub></a><br /><a href="#translation-kangjung" title="Translation">🌍</a></td>
        +      <td align="center" valign="top" width="16.66%"><a href="https://github.com/AlzaAlzaki76"><img src="https://avatars.githubusercontent.com/u/202525131?v=4?s=64" width="64px;" alt="Alza Alzaki"/><br /><sub><b>Alza Alzaki</b></sub></a><br /><a href="https://github.com/processing/p5.js/commits?author=AlzaAlzaki76" title="Documentation">📖</a></td>
             </tr>
           </tbody>
         </table>
        
        From 8f031ca90c449f9077ab81f717de1000974e841b Mon Sep 17 00:00:00 2001
        From: "allcontributors[bot]"
         <46447321+allcontributors[bot]@users.noreply.github.com>
        Date: Wed, 27 Aug 2025 17:58:21 +0000
        Subject: [PATCH 280/282] docs: update .all-contributorsrc [skip ci]
        
        ---
         .all-contributorsrc | 9 +++++++++
         1 file changed, 9 insertions(+)
        
        diff --git a/.all-contributorsrc b/.all-contributorsrc
        index 5fe48515c4..a8a6210a2f 100644
        --- a/.all-contributorsrc
        +++ b/.all-contributorsrc
        @@ -7100,6 +7100,15 @@
               "contributions": [
                 "translation"
               ]
        +    },
        +    {
        +      "login": "AlzaAlzaki76",
        +      "name": "Alza Alzaki",
        +      "avatar_url": "https://avatars.githubusercontent.com/u/202525131?v=4",
        +      "profile": "https://github.com/AlzaAlzaki76",
        +      "contributions": [
        +        "doc"
        +      ]
             }
           ],
           "repoType": "github",
        
        From 58c706834f68a339cca893e34455e5b0492f4a64 Mon Sep 17 00:00:00 2001
        From: kit <1304340+ksen0@users.noreply.github.com>
        Date: Thu, 21 Aug 2025 22:30:55 +0200
        Subject: [PATCH 281/282] Update contributor_guidelines.md
        
        ---
         contributor_docs/contributor_guidelines.md | 9 ++++++---
         1 file changed, 6 insertions(+), 3 deletions(-)
        
        diff --git a/contributor_docs/contributor_guidelines.md b/contributor_docs/contributor_guidelines.md
        index 84685141db..9056d27e88 100644
        --- a/contributor_docs/contributor_guidelines.md
        +++ b/contributor_docs/contributor_guidelines.md
        @@ -203,12 +203,14 @@ Now that your issue has been discussed, an implementation approved, and you are
         
         Similarly, if you have come across an issue or joined in discussions of an issue and an implementation has been approved by stewards, but neither the original issue author nor other members of the community have indicated they are willing to work on the issue, you may volunteer for submit a contribution here and have the stewards assign the issue to you.
         
        -**You should not "jump the queue"** by filing a PR for an issue that either someone else has indicated willingness to submit a contribution or has already been assigned to someone else. We will always prioritize the "first assigned, first serve" order for accepting code contributions for an issue. 
        +You should not "jump the queue" by filing a PR for an issue that either someone else has indicated willingness to submit a contribution or has already been assigned to someone else. We will always prioritize the "first assigned, first serve" order for accepting code contributions for an issue. **If you file a PR for an issue while someone else is still working on the same issue, your PR will likely be closed.**
         
        -If you file a PR for an issue while someone else is still working on the same issue, your PR will be closed. If you see that it has been a few months since the last activity on an issue with an assigned individual, you can check in with them by leaving a polite comment on the issue asking for progress and if they need help with the implementation. We generally allow for a reasonably long time frame for people to work on their contributions as we understand that most people will often be working on a volunteer basis, or it simply takes more time for them to work on the feature. 
        +If you see that it has been a few weeks since the last activity on an issue with an assigned individual, you can leave a polite comment on the issue asking for progress and if they need help with the implementation. We generally allow for people to work on their contributions at their own pace, as we understand that most people will often be working on a volunteer basis, or it simply takes more time for them to work on the feature.
         
        -Similarly, you should work at your own pace and be confident that there is no hard time limit on how long you can spend working on something. That being said, if you are having trouble with any aspect of your code contribution, do not hesitate to ask for help in the issue, the stewards and maintainers, as well as members of our community, will do our best to guide you!
         
        +In some cases, issues may be time sensitive - so either maintainers will work on these directly, or explain any important deadlines. If the issue has a deadline, and a contributor isn't able to finish on time, it may be reassigned. This is an exception, though, and not the rule. Generally, you should work at your own pace and be confident that there is no hard time limit on how long you can spend working on something. If you are having trouble with any aspect of your code contribution, do not hesitate to ask for help in the issue, the stewards and maintainers, as well as members of our community, will do our best to guide you!
        +
        +If you've been assigned to an issue and are working on it, the p5.js maintainers (you can check who in the README!) might comment and tag you in that comment to check in. Please reply **within 1 week** with any questions or updates; if you don't respond in a week, we may reassign the issue. This doesn't mean you need to finish the work in 1 week: only to confirm you're still on it.
         
         ## Quick Get Started For Developers
         
        @@ -484,6 +486,7 @@ In the template, there is this line `Resolves #[Add issue number here]`, which y
         
         You should clearly describe the changes you have made in this PR. Include any implementation details and decisions you made here that are relevant to whoever will review it.
         
        +**Important:** any PR that changes more than ~10 files or more than ~100 lines may be closed, unless this is specifically required by the issue and previously approved. Be sure to click the "Files Changed" tab in your PR to review changes. Unless required by the issue and approved, your PR should not make changes to `package.json` or `package-lock.json`; formatting changes; or changes not related to the issue.
         
         ### Screenshots of the change
         
        
        From f1a6c720c4a40d6d9db6f4ae62e155ec46cccfe1 Mon Sep 17 00:00:00 2001
        From: Nitin2332 <nitinrajpoot2332@gmail.com>
        Date: Wed, 3 Sep 2025 10:58:25 +0530
        Subject: [PATCH 282/282] changes
        
        ---
         src/typography/attributes.js       | 42 ++++++++++++++++++++++++++++++
         test/unit/typography/attributes.js |  4 +++
         2 files changed, 46 insertions(+)
        
        diff --git a/src/typography/attributes.js b/src/typography/attributes.js
        index d6a5eb8d5e..8c771ca2b0 100644
        --- a/src/typography/attributes.js
        +++ b/src/typography/attributes.js
        @@ -254,6 +254,9 @@ p5.prototype.textStyle = function(theStyle) {
          * Calculates the maximum width of a string of text drawn when
          * <a href="#/p5/text">text()</a> is called.
          *
        + * <strong>Note:</strong> In p5.js 2.0+, leading and trailing spaces are ignored.
        + * <code>textWidth("  Hello  ")</code> returns the same width as <code>textWidth("Hello")</code>.
        + *
          * @method textWidth
          * @param {String} str string of text to measure.
          * @return {Number} width measured in units of pixels.
        @@ -310,6 +313,45 @@ p5.prototype.textStyle = function(theStyle) {
          * }
          * </code>
          * </div>
        + *
        + * <div>
        + * <code>
        + * function setup() {
        + *   createCanvas(100, 100);
        + *   background(200);
        + *   textSize(16);
        + *
        + *   // Demonstrate that leading/trailing spaces are ignored
        + *   let text1 = 'Hello';
        + *   let text2 = '  Hello  ';
        + *   let text3 = '    Hello    ';
        + *
        + *   // All three texts have the same width
        + *   let w1 = textWidth(text1);
        + *   let w2 = textWidth(text2);
        + *   let w3 = textWidth(text3);
        + *
        + *   textAlign(LEFT, TOP);
        + *   text(text1, 20, 20);
        + *   text(text2, 20, 50);
        + *   text(text3, 20, 80);
        + *
        + *   // Show the widths (they should be the same)
        + *   text(`Width: ${w1}`, 150, 30);
        + *   text(`Width: ${w1}`, 150, 60);
        + *   text(`Width: ${w1}`, 150, 90);
        + *
        + *   // Draw rectangles around each text to show the tight bounding box
        + *   noFill();
        + *   stroke(255, 0, 0);
        + *   rect(20, 15, w1, 20);
        + *   rect(20, 45, w2, 20);
        + *   rect(20, 75, w3, 20);
        + *
        + *   describe('Three versions of "Hello" with different amounts of leading/trailing spaces, all showing the same width measurement.');
        + * }
        + * </code>
        + * </div>
          */
         p5.prototype.textWidth = function (...args) {
           args[0] += '';
        diff --git a/test/unit/typography/attributes.js b/test/unit/typography/attributes.js
        index ebfa6b552f..3a8556ffdc 100644
        --- a/test/unit/typography/attributes.js
        +++ b/test/unit/typography/attributes.js
        @@ -98,6 +98,10 @@ suite('Typography Attributes', function() {
             test('should return a number for number input', function() {
               assert.isNumber(myp5.textWidth('p5.js'));
             });
        +    test('should ignore leading and trailing spaces', function() {
        +      assert.strictEqual(myp5.textWidth('  Hello  '), myp5.textWidth('Hello'));
        +      assert.strictEqual(myp5.textWidth('    Hello    '), myp5.textWidth('Hello'));
        +    });
           });
         
           suite('p5.prototype.textAscent', function() {