This is an automated email from the ASF dual-hosted git repository.

delei pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fesod.git


The following commit(s) were added to refs/heads/main by this push:
     new 3513ff68 docs: replace the avatar with a base64 image (#652)
3513ff68 is described below

commit 3513ff68b82678ffa421b255c62ef8d739afd309
Author: DeleiGuo <[email protected]>
AuthorDate: Mon Oct 20 00:02:57 2025 +0800

    docs: replace the avatar with a base64 image (#652)
---
 website/README.md                              |  25 +++-
 website/blog/authors.json                      |  82 +++++++++++
 website/blog/authors.yml                       |  53 -------
 website/docusaurus.config.js                   |   5 +-
 website/github-avatar.js                       | 184 +++++++++++++++++++++++++
 website/package.json                           |   3 +-
 website/src/pages/team/data/github-avatar.json |  42 ++++++
 website/src/pages/team/{ => data}/team.json    |   0
 website/src/pages/team/index.css               |  98 ++++++-------
 website/src/pages/team/index.jsx               |  45 +++---
 website/static/img/team/10711694.png           | Bin 39205 -> 0 bytes
 website/static/img/team/11783444.png           | Bin 84486 -> 0 bytes
 website/static/img/team/13284744.png           | Bin 54609 -> 0 bytes
 website/static/img/team/17263766.png           | Bin 24563 -> 0 bytes
 website/static/img/team/18475586.png           | Bin 55930 -> 0 bytes
 website/static/img/team/18818196.png           | Bin 52576 -> 0 bytes
 website/static/img/team/198714007.png          | Bin 1388 -> 0 bytes
 website/static/img/team/29803617.png           | Bin 72638 -> 0 bytes
 website/static/img/team/3264250.png            | Bin 52119 -> 0 bytes
 website/static/img/team/5753992.png            | Bin 22582 -> 0 bytes
 20 files changed, 408 insertions(+), 129 deletions(-)

diff --git a/website/README.md b/website/README.md
index 97f993da..39065c91 100644
--- a/website/README.md
+++ b/website/README.md
@@ -4,7 +4,8 @@ This website is built using 
[Docusaurus](https://docusaurus.io/), a modern stati
 
 ## Requirements
 
-- [Node.js](https://nodejs.org/en/download/) version 20.0 or above (which can 
be checked by running `node -v`). You can use 
[nvm](https://github.com/nvm-sh/nvm) for managing multiple Node versions on a 
single machine installed.
+- [Node.js](https://nodejs.org/en/download/) version 20.0 or above (which can 
be checked by running `node -v`). You can
+  use [nvm](https://github.com/nvm-sh/nvm) for managing multiple Node versions 
on a single machine installed.
 - When installing Node.js, you are recommended to check all checkboxes related 
to dependencies.
 
 ## Installation
@@ -27,7 +28,24 @@ Preview the Chinese website locally:
 pnpm start --locale zh-cn
 ```
 
-This command starts a local development server and opens up a browser window. 
Most changes are reflected live without having to restart the server.
+This command starts a local development server and opens up a browser window. 
Most changes are reflected live without
+having to restart the server.
+
+## Team Page
+
+### Member
+
+Update the member information in `src/pages/team/data/member.json` File.
+
+### Avatar
+
+```console
+pnpm github-avatar
+```
+
+This command will fetch the base64 string of the GitHub avatar from file
+`src/pages/team/data/member.json`, and store the result in the 
`src/pages/team/data/` directory. The operation might
+take a little while.
 
 ## Internationalization
 
@@ -49,7 +67,8 @@ pnpm write-translations --locale en
 pnpm build
 ```
 
-This command generates static content into the `build` directory and can be 
served using any static contents hosting service.
+This command generates static content into the `build` directory and can be 
served using any static contents hosting
+service.
 
 ## Directory Structure
 
diff --git a/website/blog/authors.json b/website/blog/authors.json
new file mode 100644
index 00000000..113d7126
--- /dev/null
+++ b/website/blog/authors.json
@@ -0,0 +1,82 @@
+{
+  "dave2wave": {
+    "name": "Dave Fisher",
+    "url": "https://github.com/dave2wave";,
+    "image_url": 
"data:image/png;base64,/9j/2wCEAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDIBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAGQAZAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS
 [...]
+    "socials": {
+      "github": "dave2wave"
+    }
+  },
+  "wolfboys": {
+    "name": "Huajie Wang",
+    "url": "https://github.com/wolfboys";,
+    "image_url": 
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAA5eElEQVR4nHy9W8xtyXEeVlXdvdbat/927ufMhRwOqZFJKiRlXahIsaQglqMkCPLgwEkQIM95SYAAyUMAAQbyYr8EAWIgiZzEiB0EcWLLESUzthTdKEuKZFoyNeSQmuFwZs7MuZ//uvdel+6uCrq619r7jBT/c+acf///3mv3qq7LV1Vf9baPzx4DgAiwMOh3AvlLH0v+GQCg/kpEhPUxC+bfISK+8Lq97/URAuYX7l8v/bB8xfy09LP0LqAX57IWMaDP1Eecr5kvmJ8JOL4PyHgdvQJzemF5Bega8z/ILPniZUkipFdBLEvi6WW7+0q/srubGheS7q4sHTCJCPSNcPo1pZ8J5VflNQjkJ41PGa84faO/Hh8RZvGnlQMKqewZgMrdIhCQTDc/ih7Ht8iC
 [...]
+    "socials": {
+      "github": "wolfboys"
+    }
+  },
+  "pjfanning": {
+    "name": "PJ Fanning",
+    "url": "https://github.com/pjfanning";,
+    "image_url": 
"data:image/png;base64,/9j/2wCEAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDIBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAGQAZAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS
 [...]
+    "socials": {
+      "github": "pjfanning"
+    }
+  },
+  "tisonkun": {
+    "name": "Zili Chen",
+    "url": "https://github.com/tisonkun";,
+    "image_url": 
"data:image/png;base64,/9j/2wCEAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDIBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAGQAZAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS
 [...]
+    "socials": {
+      "github": "tisonkun"
+    }
+  },
+  "zhuangjiaju": {
+    "name": "Jiaju Zhuang",
+    "url": "https://github.com/zhuangjiaju";,
+    "image_url": 
"data:image/png;base64,/9j/2wCEAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDIBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAGQAZAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS
 [...]
+    "socials": {
+      "github": "zhuangjiaju"
+    }
+  },
+  "jipengfei-jpf": {
+    "name": "Pengfei Ji",
+    "url": "https://github.com/jipengfei-jpf";,
+    "image_url": 
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAaQAAAGkCAIAAADxLsZiAAAF40lEQVR4nOzX0c2bMABG0aZiAIZjDMZhDIbzCH2IlNdKbYJ/cs9ZwJ8EucHLGOMXwLf7PXsAwBXEDkgQOyBB7IAEsQMSxA5IEDsgQeyABLEDEsQOSBA7IEHsgASxAxLEDkgQOyBB7IAEsQMSxA5IEDsgQeyABLEDEsQOSBA7IEHsgASxAxLEDkgQOyBB7IAEsQMSxA5IEDsgQeyABLEDEsQOSFhmD7ix8xizJ1C07evsCbfkyw5IEDsgQeyABLEDEsQOSBA7IEHsgASxAxLEDkgQOyBB7IAEsQMSxA5IEDsgQeyABLEDEsQOSBA7IEHsgASxAxLEDkgQOyBB7IAEsQMSxA5IEDsgQeyABLEDEsQOSBA7IEHsgASxAxLEDkgQOyBB7IAEsQMSxA5IEDsg
 [...]
+    "socials": {
+      "github": "jipengfei-jpf"
+    }
+  },
+  "psxjoy": {
+    "name": "Shuxin Pan",
+    "url": "https://github.com/psxjoy";,
+    "image_url": 
"data:image/png;base64,/9j/2wCEAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDIBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAGQAZAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS
 [...]
+    "socials": {
+      "github": "psxjoy"
+    }
+  },
+  "tmlx1990": {
+    "name": "Xin Yan",
+    "url": "https://github.com/tmlx1990";,
+    "image_url": 
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAApnElEQVR4nNx9CXhTZdr2fZI0aZKmbZImTUsXmqYsDfumbINLsUVRUWndxhEF91Hk05nB0U9BHdcZQQUVF0TFraDiAEMrRSsqAyLKlrKlKS0t3Zu2Sdo0aXL+63mz2EILbUnQ/7uvK5A0J+8557nfZ32XI5p9zyL83pCZrocxQ8+xDzx4cOD8X/EcIOYBFXjIwUEKHsLgtz64waMdHOwAmsDDy3HgeF9LwbZMZgtfYrac/5s7C0S/9QXAT8CIDL2A5+ElgRkNerHJbEkBj2F5OVnjAYwAkA5AAyAGQBQA71maJcG3+F81AEoB7MsvKNoDDoeN6fpao0HvCRz8eyGI+601ZN3y5wT5W4r4dYVFfF5Oljw3O+sOAA8BSOpymIfpik/I9BL0sXmv/3e8/zdd
 [...]
+    "socials": {
+      "github": "tmlx1990"
+    }
+  },
+  "alaahong": {
+    "name": "Zhe Zhang",
+    "url": "https://github.com/alaahong";,
+    "image_url": 
"data:image/png;base64,/9j/2wCEAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDIBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAGQAZAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS
 [...]
+    "socials": {
+      "github": "alaahong"
+    }
+  },
+  "delei": {
+    "name": "Ziqiu Guo",
+    "url": "https://github.com/delei";,
+    "image_url": 
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAdPUlEQVR4nOxcB3gVxfafmd29vSQ3heSmF1IooSYhwIMIoST05qNJUUEpAgLyHlJFERUQGzakSS8qIQooICAISDUJAVJJQkjvuf3u7vy/3b0J6PMpgbvx/b+P8yV8l83OzJ7fPefMmd+ZWXLccjN4Ig8n6O9+gP9P8gSsZsgTsJohT8BqhjwBqxnyBKxmyBOwmiFPwGqGPAGrGfIErGbIE7CaIU/AaoY8AasZ8r8GFn6Ym1jaJP6T/IH8T4CFMa4rvYIxNtcXVN09J1y0m8sBAIbqzN/dXFty2W6p/jse838DLAhh0e3kn/ePtJqqc658XJC6GWCcc3VzQ0XajRNzWcZiMRQBABi7If3HV411hRKl99/ynOTfMmqTmKqu56R+RZBSudIlLfNYUdb3Gp1f
 [...]
+    "socials": {
+      "github": "delei"
+    }
+  }
+}
\ No newline at end of file
diff --git a/website/blog/authors.yml b/website/blog/authors.yml
deleted file mode 100644
index 87044aea..00000000
--- a/website/blog/authors.yml
+++ /dev/null
@@ -1,53 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-jipengfei:
-  name: jipengfei
-  url: https://github.com/jipengfei-jpf
-  image_url: /img/team/198714007.png
-  socials:
-    github: jipengfei-jpf
-zhuangjiaju:
-  name: zhuangjiaju
-  url: https://github.com/zhuangjiaju
-  image_url: /img/team/18475586.png
-  socials:
-    github: zhuangjiaju
-psxjoy:
-  name: psxjoy
-  url: https://github.com/psxjoy
-  image_url: /img/team/10711694.png
-  socials:
-    github: psxjoy
-delei:
-  name: delei
-  url: https://github.com/delei
-  image_url: /img/team/17263766.png
-  socials:
-    github: delei
-alaahong:
-  name: alaahong
-  url: https://github.com/alaahong
-  image_url: /img/team/3264250.png
-  socials:
-    github: alaahong
-tmlx1990:
-  name: tmlx1990
-  url: https://github.com/tmlx1990
-  image_url: /img/team/5753992.png
-  socials:
-    github: tmlx1990
\ No newline at end of file
diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js
index 0ee421cc..8b1a614d 100644
--- a/website/docusaurus.config.js
+++ b/website/docusaurus.config.js
@@ -61,13 +61,14 @@ const config = {
                 },
                 blog: {
                     showReadingTime: false,
-                    postsPerPage: 5,
+                    postsPerPage: 15,
                     feedOptions: {
                         type: 'all',
                     },
                     editUrl: `${repoUrl}/edit/${branch}/website/`,
                     editLocalizedFiles: true,
-                    blogSidebarCount: 'ALL'
+                    blogSidebarCount: 'ALL',
+                    authorsMapPath: "authors.json"
                 },
                 theme: {
                     customCss: './src/css/custom.css'
diff --git a/website/github-avatar.js b/website/github-avatar.js
new file mode 100644
index 00000000..40af035c
--- /dev/null
+++ b/website/github-avatar.js
@@ -0,0 +1,184 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+const fs = require("fs");
+const https = require("https");
+
+const teamSrc = "src/pages/team/data/team.json";
+const avatarFile = "src/pages/team/data/github-avatar.json";
+const avatarSize = 100;
+const authorsFile = "blog/authors.json";
+
+/**
+ * Generates a random delay between min and max milliseconds
+ * @param {number} min - Minimum delay in milliseconds
+ * @param {number} max - Maximum delay in milliseconds
+ * @returns {number} Random delay in milliseconds
+ */
+function getRandomDelay(min, max) {
+    return Math.floor(Math.random() * (max - min + 1)) + min;
+}
+
+/**
+ * Fetches avatar image from GitHub and converts it to base64
+ * @param {string} githubId - GitHub ID
+ * @returns {Promise<string>} Base64 encoded avatar image
+ */
+function fetchAvatarAsBase64(githubId) {
+    return new Promise((resolve, reject) => {
+        const avatarUrl = 
`https://avatars.githubusercontent.com/u/${githubId}?v=4&s=${avatarSize}`;
+
+        https
+            .get(avatarUrl, (response) => {
+                // Check if request was successful
+                if (response.statusCode !== 200) {
+                    reject(new Error(`Failed to fetch avatar from 
${avatarUrl}: ${response.statusCode}`));
+                    return;
+                }
+
+                const chunks = [];
+
+                // Collect data chunks
+                response.on("data", (chunk) => {
+                    chunks.push(chunk);
+                });
+
+                // Convert to base64 when complete
+                response.on("end", () => {
+                    const buffer = Buffer.concat(chunks);
+                    const base64 = buffer.toString("base64");
+                    resolve(base64);
+                });
+            })
+            .setTimeout(10000, () => {
+                reject(new Error(`Failed to fetch avatar ${avatarUrl}: timed 
out`));
+            })
+            .on("error", (error) => {
+                reject(error);
+            });
+    });
+}
+
+/**
+ * Get GitHub name from URL
+ * @param {string} url - GitHub URL
+ * @returns {string} GitHub name
+ */
+function getGitName(url) {
+    return url.replace('https://github.com/', '');
+}
+
+/**
+ * Processes a list of githubIds and adds avatar_base64 property
+ * @param {Array} ids - Array of id
+ * @returns {Promise<Array>} Array of avatar_base64
+ */
+async function processAvatars(ids) {
+    const processedArray = [];
+
+    for (let i = 0; i < ids.length; i++) {
+        const _id = ids[i];
+
+        try {
+            console.log(`-- Fetching avatar for ${_id} ... [${i + 
1}/${ids.length}]`);
+
+            // Fetch avatar and convert to base64
+            const avatarBase64 = await fetchAvatarAsBase64(_id);
+
+            processedArray.push({
+                id: _id,
+                avatar_base64: avatarBase64
+            });
+            console.log(`āœ“ Successfully processed ${_id}`);
+        } catch (error) {
+            console.error(`āœ— Error processing ${_id}: ${error.message}`);
+        }
+
+        // Add random delay between 100-2000 millisecond before next request 
(except for the last member)
+        if (i < ids.length - 1) {
+            await new Promise((resolve) => setTimeout(resolve, 
getRandomDelay(100, 2000)));
+        }
+    }
+    return processedArray;
+}
+
+/**
+ * Processes blog authors data and adds avatar_base64 property
+ * @param {Object} teamData - Team data
+ * @param {Array} avatars - Array of avatars
+ * @returns {Promise<Object>} Blog authors data
+ */
+async function processBlogAuthors(teamData, avatars) {
+    const blogAuthorsMapPath = {};
+    (teamData.pmc.concat(teamData.committer) || []).forEach((m) => {
+        const gitName = getGitName(m.gitUrl);
+        const avatarObj = avatars.find((item) => item.id === m.githubId);
+        blogAuthorsMapPath[gitName] = {
+            "name": m.name,
+            "url": m.gitUrl,
+            "image_url": "data:image/png;base64," + avatarObj.avatar_base64,
+            "socials": {
+                "github": gitName
+            }
+        }
+    });
+
+    return blogAuthorsMapPath;
+}
+
+/**
+ * Main function
+ */
+async function main() {
+    try {
+        const uniqueGithubIdsSet = new Set();
+
+        // 1. Read and parse team
+        console.log(`==> Reading ${teamSrc} file`);
+        const teamSrcData = JSON.parse(fs.readFileSync(teamSrc, "utf8"));
+
+        // PMC && Committer
+        (teamSrcData.pmc.concat(teamSrcData.committer) || []).forEach((d) => {
+            if (d.githubId) {
+                uniqueGithubIdsSet.add(d.githubId);
+            }
+        });
+
+        const uniqueGithubArray = Array.from(uniqueGithubIdsSet);
+
+        console.log("\n==> Processing avatars");
+        const avatarsArray = await processAvatars(uniqueGithubArray);
+
+        // 2. Write files
+        console.log(`\n==> Write to ${avatarFile}`);
+        fs.writeFileSync(avatarFile, JSON.stringify(avatarsArray, null, 2));
+
+        // 3. Blog authors
+        const blogAuthorsMapPaths = await processBlogAuthors(teamSrcData, 
avatarsArray);
+        console.log(`\n==> Write to ${authorsFile}`);
+        fs.writeFileSync(authorsFile, JSON.stringify(blogAuthorsMapPaths, 
null, 2));
+
+        console.log("\nāœ“ Done!");
+    } catch (error) {
+        console.error("Error:", error.message);
+        process.exit(1);
+    }
+}
+
+main();
\ No newline at end of file
diff --git a/website/package.json b/website/package.json
index 35f1099f..06a1e294 100644
--- a/website/package.json
+++ b/website/package.json
@@ -15,7 +15,8 @@
     "write-translations": "docusaurus write-translations",
     "write-heading-ids": "docusaurus write-heading-ids",
     "md-lint": "markdownlint-cli2 --config ./.markdownlint-cli2.jsonc 
\"./**/*.md\" \"#node_modules\"",
-    "md-lint-fix": "yarn md-lint --fix"
+    "md-lint-fix": "pnpm md-lint --fix",
+    "github-avatar": "node github-avatar.js"
   },
   "dependencies": {
     "@docusaurus/core": "^3.9.1",
diff --git a/website/src/pages/team/data/github-avatar.json 
b/website/src/pages/team/data/github-avatar.json
new file mode 100644
index 00000000..67834ef0
--- /dev/null
+++ b/website/src/pages/team/data/github-avatar.json
@@ -0,0 +1,42 @@
+[
+  {
+    "id": "29803617",
+    "avatar_base64": 
"/9j/2wCEAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDIBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAGQAZAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5e
 [...]
+  },
+  {
+    "id": "13284744",
+    "avatar_base64": 
"iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAA5eElEQVR4nHy9W8xtyXEeVlXdvdbat/927ufMhRwOqZFJKiRlXahIsaQglqMkCPLgwEkQIM95SYAAyUMAAQbyYr8EAWIgiZzEiB0EcWLLESUzthTdKEuKZFoyNeSQmuFwZs7MuZ//uvdel+6uCrq619r7jBT/c+acf///3mv3qq7LV1Vf9baPzx4DgAiwMOh3AvlLH0v+GQCg/kpEhPUxC+bfISK+8Lq97/URAuYX7l8v/bB8xfy09LP0LqAX57IWMaDP1Eecr5kvmJ8JOL4PyHgdvQJzemF5Bega8z/ILPniZUkipFdBLEvi6WW7+0q/srubGheS7q4sHTCJCPSNcPo1pZ8J5VflNQjkJ41PGa84faO/Hh8RZvGnlQMKqewZgMrdIhCQTDc/ih7Ht8iCRkKQ/dXLJCkEJCL9F6
 [...]
+  },
+  {
+    "id": "11783444",
+    "avatar_base64": 
"/9j/2wCEAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDIBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAGQAZAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5e
 [...]
+  },
+  {
+    "id": "18818196",
+    "avatar_base64": 
"/9j/2wCEAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDIBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAGQAZAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5e
 [...]
+  },
+  {
+    "id": "18475586",
+    "avatar_base64": 
"/9j/2wCEAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDIBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAGQAZAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5e
 [...]
+  },
+  {
+    "id": "198714007",
+    "avatar_base64": 
"iVBORw0KGgoAAAANSUhEUgAAAaQAAAGkCAIAAADxLsZiAAAF40lEQVR4nOzX0c2bMABG0aZiAIZjDMZhDIbzCH2IlNdKbYJ/cs9ZwJ8EucHLGOMXwLf7PXsAwBXEDkgQOyBB7IAEsQMSxA5IEDsgQeyABLEDEsQOSBA7IEHsgASxAxLEDkgQOyBB7IAEsQMSxA5IEDsgQeyABLEDEsQOSBA7IEHsgASxAxLEDkgQOyBB7IAEsQMSxA5IEDsgQeyABLEDEsQOSFhmD7ix8xizJ1C07evsCbfkyw5IEDsgQeyABLEDEsQOSBA7IEHsgASxAxLEDkgQOyBB7IAEsQMSxA5IEDsgQeyABLEDEsQOSBA7IEHsgASxAxLEDkgQOyBB7IAEsQMSxA5IEDsgQeyABLEDEsQOSBA7IEHsgASxAxLEDkgQOyBB7IAEsQMSxA5IEDsgQeyABLEDEsQOSBA7IE
 [...]
+  },
+  {
+    "id": "10711694",
+    "avatar_base64": 
"/9j/2wCEAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDIBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAGQAZAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5e
 [...]
+  },
+  {
+    "id": "5753992",
+    "avatar_base64": 
"iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAApnElEQVR4nNx9CXhTZdr2fZI0aZKmbZImTUsXmqYsDfumbINLsUVRUWndxhEF91Hk05nB0U9BHdcZQQUVF0TFraDiAEMrRSsqAyLKlrKlKS0t3Zu2Sdo0aXL+63mz2EILbUnQ/7uvK5A0J+8557nfZ32XI5p9zyL83pCZrocxQ8+xDzx4cOD8X/EcIOYBFXjIwUEKHsLgtz64waMdHOwAmsDDy3HgeF9LwbZMZgtfYrac/5s7C0S/9QXAT8CIDL2A5+ElgRkNerHJbEkBj2F5OVnjAYwAkA5AAyAGQBQA71maJcG3+F81AEoB7MsvKNoDDoeN6fpao0HvCRz8eyGI+601ZN3y5wT5W4r4dYVFfF5Oljw3O+sOAA8BSOpymIfpik/I9BL0sXmv/3e8/zddf7cPwNPrCou+yC8o8u
 [...]
+  },
+  {
+    "id": "3264250",
+    "avatar_base64": 
"/9j/2wCEAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDIBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAGQAZAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5e
 [...]
+  },
+  {
+    "id": "17263766",
+    "avatar_base64": 
"iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAdPUlEQVR4nOxcB3gVxfafmd29vSQ3heSmF1IooSYhwIMIoST05qNJUUEpAgLyHlJFERUQGzakSS8qIQooICAISDUJAVJJQkjvuf3u7vy/3b0J6PMpgbvx/b+P8yV8l83OzJ7fPefMmd+ZWXLccjN4Ig8n6O9+gP9P8gSsZsgTsJohT8BqhjwBqxnyBKxmyBOwmiFPwGqGPAGrGfIErGbIE7CaIU/AaoY8AasZ8r8GFn6Ym1jaJP6T/IH8T4CFMa4rvYIxNtcXVN09J1y0m8sBAIbqzN/dXFty2W6p/jse838DLAhh0e3kn/ePtJqqc658XJC6GWCcc3VzQ0XajRNzWcZiMRQBABi7If3HV411hRKl99/ynOTfMmqTmKqu56R+RZBSudIlLfNYUdb3Gp1f3o1DhtqC6uK0O9c3Nd
 [...]
+  }
+]
\ No newline at end of file
diff --git a/website/src/pages/team/team.json 
b/website/src/pages/team/data/team.json
similarity index 100%
rename from website/src/pages/team/team.json
rename to website/src/pages/team/data/team.json
diff --git a/website/src/pages/team/index.css b/website/src/pages/team/index.css
index 4467a013..4ed1fdac 100644
--- a/website/src/pages/team/index.css
+++ b/website/src/pages/team/index.css
@@ -19,101 +19,101 @@
 
 /* Derived from 
https://github.com/apache/streampark-website/tree/dev/src/pages/team */
 .team_page {
-  margin-top: 50px !important;
+    margin: 3rem auto;
 }
 
 .team_page h1:first-child {
-  font-size: 3rem;
+    font-size: 3rem;
 }
 
 .team_page a {
-  text-decoration: none;
+    text-decoration: none;
 }
 
 .team_page .team_title {
-  margin-top: 40px;
+    margin-top: 40px;
 }
 
 .team_page .team_desc {
-  margin-bottom: 40px;
+    margin-bottom: 40px;
 }
 
 .team_page .team_indent {
-  line-height: 40px;
+    line-height: 40px;
 }
 
 .team_page .desc {
-  font-size: 1rem;
-  margin-left: 0.5rem;
+    font-size: 1rem;
+    margin-left: 0.5rem;
 }
 
 .team-row {
-  --bs-gutter-x: 1.5rem;
-  --bs-gutter-y: 0;
-  display: -ms-flexbox;
-  display: flex;
-  -ms-flex-wrap: wrap;
-  flex-wrap: wrap;
-  margin-top: calc(-1 * var(--bs-gutter-y));
-  margin-right: calc(-0.5 * var(--bs-gutter-x));
-  margin-left: calc(-0.5 * var(--bs-gutter-x));
+    --bs-gutter-x: 1.5rem;
+    --bs-gutter-y: 0;
+    display: -ms-flexbox;
+    display: flex;
+    -ms-flex-wrap: wrap;
+    flex-wrap: wrap;
+    margin-top: calc(-1 * var(--bs-gutter-y));
+    margin-right: calc(-0.5 * var(--bs-gutter-x));
+    margin-left: calc(-0.5 * var(--bs-gutter-x));
 }
 
 .team-box {
-  width: 20% !important;
-  padding: 12px;
+    width: 20% !important;
+    padding: 12px;
 }
 
 .team-user-img {
-  width: 80px;
-  border-radius: 50%;
-  border: 2px solid #fff;
+    width: 80px;
+    border-radius: 50%;
+    border: 2px solid #fff;
 }
 
 .bg-team {
-  margin-top: -1.5rem !important;
-  padding: 2.5rem 1rem 0.5rem 1rem;
-  background-color: #ffffff !important;
-  border-radius: 0.75rem;
-  box-shadow: 0 0.375rem 1.5rem 0 rgba(0, 0, 0, 0.16) !important;
+    margin-top: -1.5rem !important;
+    padding: 2.5rem 1rem 0.5rem 1rem;
+    background-color: #ffffff !important;
+    border-radius: 0.75rem;
+    box-shadow: 0 0.375rem 1.5rem 0 rgba(0, 0, 0, 0.16) !important;
 }
 
 .team-link {
-  background-color: #fff;
-  border-radius: 50%;
-  width: 1.5rem;
-  height: 1.5rem;
-  display: inline-flex;
-  align-items: center;
-  justify-content: center;
-  text-align: center;
-  font-size: 75%;
-  line-height: normal;
-  margin-right: 0.25rem;
+    background-color: #fff;
+    border-radius: 50%;
+    width: 1.5rem;
+    height: 1.5rem;
+    display: inline-flex;
+    align-items: center;
+    justify-content: center;
+    text-align: center;
+    font-size: 75%;
+    line-height: normal;
+    margin-right: 0.25rem;
 }
 
 .team-link .github-icon {
-  width: 20px;
-  height: 20px;
-  color: #fff;
+    width: 20px;
+    height: 20px;
+    color: #fff;
 }
 
 [data-theme="dark"] .team-link {
-  background-color: #95999c;
+    background-color: #95999c;
 }
 
 [data-theme="dark"] .bg-team {
-  background-color: #0e1114 !important;
+    background-color: #0e1114 !important;
 }
 
 .divider {
-  width: 100%;
-  height: 1px;
-  background-color: #dfdfdf;
+    width: 100%;
+    height: 1px;
+    background-color: #dfdfdf;
 }
 
 @media (max-width: 768px) {
-  .team-box {
-    width: 50% !important;
-  }
+    .team-box {
+        width: 50% !important;
+    }
 }
diff --git a/website/src/pages/team/index.jsx b/website/src/pages/team/index.jsx
index 9069a0f6..863980fa 100644
--- a/website/src/pages/team/index.jsx
+++ b/website/src/pages/team/index.jsx
@@ -19,25 +19,30 @@
 
 import React from 'react';
 import BrowserOnly from '@docusaurus/BrowserOnly';
-import config from "./team.json";
+import TeamData from "./data/team.json";
+import AvatarData from "./data/github-avatar.json";
 import Layout from '@theme/Layout';
 import './index.css';
 import Github from "./github.svg"
 import Translate from '@docusaurus/Translate'
-import useBaseUrl from '@docusaurus/useBaseUrl';
 
 /**
  * Derived from 
https://github.com/apache/streampark-website/tree/dev/src/pages/team
  */
 export default function () {
-    const dataSource = config;
+    const teamData = TeamData;
+    const avatarData = AvatarData;
 
     function getGitName(url) {
         return '@' + url.replace('https://github.com/', '');
     }
 
     function avatarUrl(id) {
-        return useBaseUrl('/img/team/' + id + '.png');
+        const avatarObj = avatarData.find((item) => item.id === id);
+        if (avatarObj) {
+            return "data:image/png;base64," + avatarObj.avatar_base64;
+        }
+        return "";
     }
 
     return (
@@ -54,19 +59,20 @@ export default function () {
                         </h2>
                         <div className="team-row">
                             {
-                                dataSource.pmc.map((item, i) => (
+                                teamData.pmc.map((item, i) => (
                                     <div className='team-box' key={i} 
data-aos="fade-up" data-aos-delay={i * 100}>
-                                        <div style={{ textAlign: "center" }}>
-                                            <div style={{ overflow: "hidden", 
zIndex: 1 }}>
+                                        <div style={{textAlign: "center"}}>
+                                            <div style={{overflow: "hidden", 
zIndex: 1}}>
                                                 <img className="team-user-img" 
src={avatarUrl(item.githubId)} title=""
-                                                    alt="" />
+                                                     alt=""/>
                                             </div>
                                             <div className={item.isMentor ? 
'team-mentor bg-team' : 'bg-team'}>
                                                 <h5 
className="team-name">{item.name}</h5>
                                                 
<small>{getGitName(item.gitUrl)}</small>
                                                 <div>
-                                                    <a className="team-link" 
href={item.gitUrl}>
-                                                        <Github 
className="github-icon" />
+                                                    <a className="team-link" 
href={item.gitUrl} target="_blank"
+                                                       rel="noreferrer">
+                                                        <Github 
className="github-icon"/>
                                                     </a>
                                                 </div>
                                             </div>
@@ -81,20 +87,21 @@ export default function () {
                         </h2>
                         <div className="team-row">
                             {
-                                dataSource.committer.map((item, i) => (
+                                teamData.committer.map((item, i) => (
                                     <div className='team-box' key={i} 
data-aos="fade-up" data-aos-delay={i * 100}>
-                                        <div style={{ textAlign: "center" }}>
-                                            <div style={{ overflow: "hidden", 
zIndex: 1 }}>
+                                        <div style={{textAlign: "center"}}>
+                                            <div style={{overflow: "hidden", 
zIndex: 1}}>
                                                 <img className="team-user-img" 
src={avatarUrl(item.githubId)}
-                                                    title=""
-                                                    alt="" />
+                                                     title=""
+                                                     alt=""/>
                                             </div>
                                             <div className="bg-team">
                                                 <h5 
className="team-name">{item.name}</h5>
                                                 
<small>{getGitName(item.gitUrl)}</small>
                                                 <div>
-                                                    <a className="team-link" 
href={item.gitUrl}>
-                                                        <Github 
className="github-icon" />
+                                                    <a className="team-link" 
href={item.gitUrl} target="_blank"
+                                                       rel="noreferrer">
+                                                        <Github 
className="github-icon"/>
                                                     </a>
                                                 </div>
                                             </div>
@@ -111,11 +118,7 @@ export default function () {
                             Contributors</a>
                     </div>
                 </Layout>
-                    ;
             }}
-
         </BrowserOnly>
-
     )
-        ;
 }
diff --git a/website/static/img/team/10711694.png 
b/website/static/img/team/10711694.png
deleted file mode 100644
index 428487eb..00000000
Binary files a/website/static/img/team/10711694.png and /dev/null differ
diff --git a/website/static/img/team/11783444.png 
b/website/static/img/team/11783444.png
deleted file mode 100644
index b0b4a6b9..00000000
Binary files a/website/static/img/team/11783444.png and /dev/null differ
diff --git a/website/static/img/team/13284744.png 
b/website/static/img/team/13284744.png
deleted file mode 100644
index 1b462510..00000000
Binary files a/website/static/img/team/13284744.png and /dev/null differ
diff --git a/website/static/img/team/17263766.png 
b/website/static/img/team/17263766.png
deleted file mode 100644
index 9f0a17d6..00000000
Binary files a/website/static/img/team/17263766.png and /dev/null differ
diff --git a/website/static/img/team/18475586.png 
b/website/static/img/team/18475586.png
deleted file mode 100644
index 1c2436c4..00000000
Binary files a/website/static/img/team/18475586.png and /dev/null differ
diff --git a/website/static/img/team/18818196.png 
b/website/static/img/team/18818196.png
deleted file mode 100644
index 6653c7f9..00000000
Binary files a/website/static/img/team/18818196.png and /dev/null differ
diff --git a/website/static/img/team/198714007.png 
b/website/static/img/team/198714007.png
deleted file mode 100644
index c87c2c08..00000000
Binary files a/website/static/img/team/198714007.png and /dev/null differ
diff --git a/website/static/img/team/29803617.png 
b/website/static/img/team/29803617.png
deleted file mode 100644
index 55601114..00000000
Binary files a/website/static/img/team/29803617.png and /dev/null differ
diff --git a/website/static/img/team/3264250.png 
b/website/static/img/team/3264250.png
deleted file mode 100644
index 72ac77a3..00000000
Binary files a/website/static/img/team/3264250.png and /dev/null differ
diff --git a/website/static/img/team/5753992.png 
b/website/static/img/team/5753992.png
deleted file mode 100644
index 0c020485..00000000
Binary files a/website/static/img/team/5753992.png and /dev/null differ


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to