diff --git a/stack--current/0-meta/typescript-custom-typings/chrome-ai.d.ts b/stack--current/0-meta/typescript-custom-typings/chrome-ai.d.ts
index fff958a0..9503890e 100644
--- a/stack--current/0-meta/typescript-custom-typings/chrome-ai.d.ts
+++ b/stack--current/0-meta/typescript-custom-typings/chrome-ai.d.ts
@@ -2,6 +2,7 @@
/////////////////////////////////////////////////
+// https://gemini.google.com/share/a4665036f4b9
type LLMTemperature = number
type LLMTopK = number
type LLMTokenCount = number
diff --git a/stack--current/3-advanced--browser/wc--social/README.md b/stack--current/3-advanced--browser/wc--social/README.md
index d31fe345..4fc5fcfc 100644
--- a/stack--current/3-advanced--browser/wc--social/README.md
+++ b/stack--current/3-advanced--browser/wc--social/README.md
@@ -7,7 +7,7 @@ A social media icons web component.
## Usage
-WARNING example does not work on Safari! TODO fix
+WARNING example does not work on Safari! TODO fix https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/is
https://codepen.io/Offirmo/pen/vYeobzP
diff --git a/stack--current/5-incubator/active--no-pkg/bite-sized/lists/senior-dev/tech-bites--concepts.md b/stack--current/5-incubator/active--no-pkg/bite-sized/lists/senior-dev/tech-bites--concepts.md
index a96dbdb2..049fc196 100644
--- a/stack--current/5-incubator/active--no-pkg/bite-sized/lists/senior-dev/tech-bites--concepts.md
+++ b/stack--current/5-incubator/active--no-pkg/bite-sized/lists/senior-dev/tech-bites--concepts.md
@@ -235,6 +235,8 @@ inheritance -- diamond
inheritance -- prototypal
inheritance -- substitutability = an object (such as a class) may be replaced by a sub-object (such as a class that extends the first class) without breaking the program
inner-platform effect https://en.wikipedia.org/wiki/Inner-platform_effect
+interface
+interface -- abstract = no implementation, only to be extended (OOP)
Interface segregation principle = instead of a class interface with all possible methods clients might need, there should be separate interfaces catering to the specific needs of each type of client https://en.wikipedia.org/wiki/Interface_segregation_principle
Joel test
JS equality
diff --git a/stack--current/5-incubator/active--no-pkg/bite-sized/lists/senior-dev/tech-bites--web.md b/stack--current/5-incubator/active--no-pkg/bite-sized/lists/senior-dev/tech-bites--web.md
index cf766c7f..02bfafce 100644
--- a/stack--current/5-incubator/active--no-pkg/bite-sized/lists/senior-dev/tech-bites--web.md
+++ b/stack--current/5-incubator/active--no-pkg/bite-sized/lists/senior-dev/tech-bites--web.md
@@ -175,6 +175,7 @@ User Agent Interface (UA) https://www.bram.us/2021/07/08/the-large-small-and-dyn
UX -- Above the fold = is the area of a webpage that fits in a browser window without a user having to scroll down. This is the content that is first seen by the user and often dictates whether they’ll continue reading the webpage.
UX -- honeycomb = useful + usable + findable + desirable + accessible + credible = valuable https://en.wikipedia.org/wiki/User_interface#A_model_of_design_criteria:_User_Experience_Honeycomb
viewport
+temporal dead zone (TDZ) https://devdocs.io/javascript/statements/let#temporal_dead_zone_tdz
viewport -- small <= dynamic <= large
viewport -- visual
viewport -- Visual Viewport API = Window.visualViewport https://developer.mozilla.org/en-US/docs/Web/API/VisualViewport
@@ -183,6 +184,7 @@ web components -- custom elements
web components -- is
web components -- shadow DOM
web components -- templates
+web components -- "autonomous" = no extends, no "is", must inherit from HTMLElement
web components -- templates -- slots https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/slot
web components https://developer.mozilla.org/en-US/docs/Web/API/Web_components
web workers -- dedicated = utilized by a single script https://devdocs.io/dom/worker
diff --git a/stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/.nojekyll b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/.nojekyll
similarity index 100%
rename from stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/.nojekyll
rename to stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/.nojekyll
diff --git a/stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/.well-known/security.txt b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/.well-known/security.txt
similarity index 70%
rename from stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/.well-known/security.txt
rename to stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/.well-known/security.txt
index f7b3bb80..78b64838 100644
--- a/stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/.well-known/security.txt
+++ b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/.well-known/security.txt
@@ -1,6 +1,6 @@
# https://securitytxt.org/
Please report any security issue or danger to the community to:
-- https://github.com/Yvem/applied-ai--8ball/issues
+- https://github.com/Yvem/applied-ai--2024/issues
Thanks for your contribution!
diff --git a/stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/404.html b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/404.html
similarity index 100%
rename from stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/404.html
rename to stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/404.html
diff --git a/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/fuai.html b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/fuai.html
new file mode 100644
index 00000000..2033522c
--- /dev/null
+++ b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/fuai.html
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+ Free LLM AAI ✨
+
+
+
+
+
+
+
+
+
+
+
✨ Free & Unfettered LLM AI ✨
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/humans.txt b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/humans.txt
similarity index 100%
rename from stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/humans.txt
rename to stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/humans.txt
diff --git a/stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/index.css b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/index.css
similarity index 100%
rename from stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/index.css
rename to stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/index.css
diff --git a/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/common/wc--ensure-ai-enabled/index.js b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/common/wc--ensure-ai-enabled/index.js
new file mode 100644
index 00000000..4e69be2e
--- /dev/null
+++ b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/common/wc--ensure-ai-enabled/index.js
@@ -0,0 +1,143 @@
+
+async function ೱisꓽai_webapi_available(progressCallback = () => {}) {
+ const err = new Error(`AI WebAPI not available!`)
+ err.url = 'https://docs.google.com/document/d/1VG8HIyz361zGduWgNG7R_R8Xkv0OOJ8b5C9QKeCjU0c/edit#heading=h.witohboigk0o'
+ progressCallback(0)
+
+ return new Promise((resolve, reject) => {
+ if (!globalThis.ai) {
+ reject(err)
+ return
+ }
+ progressCallback(0.1)
+
+ if (!'assistant' in ai) {
+ reject(err)
+ return
+ }
+
+ let ೱsession = ai.assistant.create({
+ monitor(m) {
+ m.addEventListener("downloadprogress", e => {
+ console.log(`ai.assistant: Downloaded ${e.loaded} of ${e.total} bytes.`);
+ progressCallback(Math.max(0.1, e.loaded / e.total))
+ });
+ }
+ }
+ )
+
+ return ೱsession.then((session) => {
+ progressCallback(1)
+ session.destroy()
+ })
+ })
+}
+
+customElements.define('ensure-ai-enabled', class Component extends HTMLElement {
+ static _DEBUG = true
+ _DEBUG = Component._DEBUG
+
+ static _id_generator = 0
+ _id = Component._id_generator++
+
+ loaded = 0.05
+ err = null
+
+ static get observedAttributes() { return [ 'apis' ] }
+
+ get_debug_id() {
+ const segments = [
+ `⟨${this.localName}${this.getAttribute('is') ? `--${this.getAttribute('is')}` : ''}⟩`,
+ `#${this._id}`,
+ ]
+ return segments.join('')
+ }
+
+ constructor() {
+ super()
+ if (this._DEBUG) console.log(`[${this.get_debug_id()}].constructor()]:`, { _this: this })
+ // The constructor for a custom element is not supposed to read or write its DOM
+ // also NOT supposed to read attributes, since createElement(...) may be in progress
+ // In general, work should be deferred to connectedCallback as much as possible
+ // https://stackoverflow.com/a/43837330
+
+ ೱisꓽai_webapi_available((completion_rate) => {
+ this.loaded = completion_rate
+ this._render()
+ })
+ .then(() => {
+ this.loaded = 1
+ })
+ .catch((err) => {
+ this.err = err
+ })
+ .finally(() => {
+ this._render()
+ })
+ }
+
+ _pendingRender = false
+ _render() {
+ if (this._pendingRender) return
+
+ if (this._DEBUG) console.log(`[${this.get_debug_id()}]._render()]:`, {
+ progress: this.loaded,
+ err: this.err,
+ })
+
+ this.progress‿elt ??= document.createElement('progress')
+
+ setTimeout(() => {
+ this._pendingRender = false
+
+ if (this.err) {
+ this.replaceChildren(
+ new Text(`[ERROR] ${this.err.message}`),
+ new Text(`(TODO instructions)`),
+ )
+ return
+ }
+
+ // can only test here!!!
+ if (!this._original_children) {
+ if (this.children.length === 0) {
+ // DOM not loaded yet, need to wait!
+ return
+ }
+ this._original_children = Array.from(this.children)
+ }
+
+ if (this.loaded >= 1) {
+ this.replaceChildren(...this._original_children)
+ return
+ }
+
+ this.progress‿elt.value = this.loaded
+ this.replaceChildren(
+ new Text( `Loading AI-enhanced experience: `),
+ this.progress‿elt
+ )
+ })
+ this._pendingRender = true
+ }
+
+ // called each time the element is added to the document. The specification recommends that, as far as possible, developers should implement custom element setup in this callback rather than the constructor.
+ // WARNING https://dev.to/dannyengelman/web-component-developers-do-not-connect-with-the-connectedcallback-yet-4jo7
+ connectedCallback() {
+ if (this._DEBUG) console.log(`[${this.get_debug_id()}].connectedCallback()]:`, { _this: this })
+
+ this._render()
+ }
+ // called each time the element is removed from the document.
+ disconnectedCallback() {
+ if (this._DEBUG) console.log(`[${this.get_debug_id()}].disconnectedCallback()]:`, { _this: this })
+ }
+ // called each time the element is moved to a new document.
+ adoptedCallback() {
+ if (this._DEBUG) console.log(`[${this.get_debug_id()}].adoptedCallback()]:`, { _this: this })
+ }
+ attributeChangedCallback(name, old_value, new_value) {
+ if (this._DEBUG) console.log(`[${this.get_debug_id()}].attributeChangedCallback():`, { name, old_value, new_value, _this: this })
+ this._render()
+ }
+});
diff --git a/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/common/wc-template/index.js b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/common/wc-template/index.js
new file mode 100644
index 00000000..60a7c926
--- /dev/null
+++ b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/common/wc-template/index.js
@@ -0,0 +1,59 @@
+
+customElements.define('no-ai', class Component extends HTMLElement {
+ static _DEBUG = true
+ _DEBUG = Component._DEBUG
+
+ static _id_generator = 0
+ _id = Component._id_generator++
+
+ static get observedAttributes() { return [ 'apis' ] }
+
+ get_debug_id() {
+ const segments = [
+ `⟨${this.localName}${this.getAttribute('is') ? `--${this.getAttribute('is')}` : ''}⟩`,
+ `#${this._id}`,
+ ]
+ return segments.join('')
+ }
+
+ constructor() {
+ super()
+ if (this._DEBUG) console.log(`[${this.get_debug_id()}].constructor()]:`, {
+ 'this': this
+ })
+ // The constructor for a custom element is not supposed to read or write its DOM
+ // also NOT supposed to read attributes, since createElement(...) may be in progress
+ // In general, work should be deferred to connectedCallback as much as possible
+ // https://stackoverflow.com/a/43837330
+ }
+
+ // called each time the element is added to the document. The specification recommends that, as far as possible, developers should implement custom element setup in this callback rather than the constructor.
+ // WARNING https://dev.to/dannyengelman/web-component-developers-do-not-connect-with-the-connectedcallback-yet-4jo7
+ connectedCallback() {
+ if (this._DEBUG) console.log(`[${this.get_debug_id()}].connectedCallback()]:`, {
+ 'this': this
+ })
+ setTimeout(() => {
+ this.innerHTML = `[${this.get_debug_id()}: Not Implemented ]`
+ })
+ }
+ // called each time the element is removed from the document.
+ disconnectedCallback() {
+ if (this._DEBUG) console.log(`[${this.get_debug_id()}].disconnectedCallback()]:`, {
+ 'this': this
+ })
+ }
+ // called each time the element is moved to a new document.
+ adoptedCallback() {
+ if (this._DEBUG) console.log(`[${this.get_debug_id()}].adoptedCallback()]:`, {
+ 'this': this
+ })
+ }
+ attributeChangedCallback(name, old_value, new_value) {
+ if (this._DEBUG) console.log(`[${this.get_debug_id()}].attributeChangedCallback():`, {
+ 'this': this,
+ name, old_value, new_value,
+ })
+ }
+
+});
diff --git a/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/fuai/index.js b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/fuai/index.js
new file mode 100644
index 00000000..8d8e0cad
--- /dev/null
+++ b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/fuai/index.js
@@ -0,0 +1,66 @@
+
+import { registry } from './wc--result/index.js'
+
+
+// How many r are there in "strawberry"?
+
+// TODO https://devdocs.io/dom/device_memory_api
+
+export default async function main() {
+ const elt_button_prompt = document.getElementById('button--prompt')
+
+ function on_click_ask() {
+ const systemPrompt = (document.getElementById('input--system-prompt').value).normalize('NFC').trim()
+ const prompt = (document.getElementById('input--prompt').value).normalize('NFC').trim()
+
+ for (let key in registry) {
+ registry[key].prompt({
+ systemPrompt,
+ prompt,
+ })
+ }
+ }
+
+ elt_button_prompt.onclick = on_click_ask
+ //setTimeout(on_click_ask, 500) // for tests, TODO remove
+
+ // https://gemini.google.com/share/a4665036f4b9
+ // temperature = 0...1
+ // low = 0.2
+ // high = 0.8
+ // Top-k = 1...100
+ // small = 5
+ // large = 40
+}
+
+function get_random_standard_8ball_answer() {
+ const d20 = getRandomIntInRange(1, 20)
+ const sentence = STANDARD_RESPONSES[d20 - 1]
+
+ return { d20, sentence }
+}
+
+async function get_response__ai(question, d20) {
+ console.log({ question, d20 })
+
+ const session = await ai.assistant.create({
+ // TODO on day monitor
+ })
+
+ const result_raw = await(async () => {
+ if (d20 <= 10) {
+ // affirmative
+ return session.prompt("Generate an affirmative, reassuring prompt to proceed.");
+ }
+ else if (d20 <= 15) {
+ // non-committal
+ return session.prompt("Generate an excuse saying you'll answer this question later.");
+ }
+ else {
+ // negative
+ return session.prompt("Generate a gentle but firm prompt to NOT proceed. Make excuses or invoke sources.");
+ }
+ })()
+
+ return filter_in_last_quoted_sentence_if_any(result_raw)
+}
diff --git a/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/fuai/wc--result/index.js b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/fuai/wc--result/index.js
new file mode 100644
index 00000000..db50005f
--- /dev/null
+++ b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/fuai/wc--result/index.js
@@ -0,0 +1,170 @@
+
+import { filter_in_last_quoted_sentence_if_any } from '../../utils/ai/index.js'
+
+export const registry = {}
+
+customElements.define('ai-prompt-result', class Component extends HTMLElement {
+ static _DEBUG = true
+ _DEBUG = Component._DEBUG
+
+ static _id_generator = 0
+ _id = Component._id_generator++
+
+ err = null
+ session = undefined
+ //signal = new AbortSignal() // TODO improve
+ capabilities = {}
+
+ static get observedAttributes() { return [ 'temperature', 'topK' ] }
+
+ get_debug_id() {
+ const segments = [
+ `⟨${this.localName}${this.getAttribute('is') ? `--${this.getAttribute('is')}` : ''}⟩`,
+ `#${this._id}`,
+ ]
+ return segments.join('')
+ }
+
+ constructor() {
+ super()
+ if (this._DEBUG) console.log(`[${this.get_debug_id()}].constructor()]:`, { _this: this })
+ // The constructor for a custom element is not supposed to read or write its DOM
+ // also NOT supposed to read attributes, since createElement(...) may be in progress
+ // In general, work should be deferred to connectedCallback as much as possible
+ // https://stackoverflow.com/a/43837330
+ ai.assistant.capabilities().then(capabilities => {
+ this.capabilities = capabilities
+ console.log('capabilities:', capabilities)
+ })
+ }
+
+ get temperature() {
+ const default_value = this.capabilities.defaultTemperature || 0.8
+
+ const raw = (this.getAttribute('temperature') || '').trim()
+ let candidate = Number(raw)
+ if (isNaN(candidate)) return default_value
+
+ if (raw === 'default') return default_value
+
+ return candidate
+ }
+
+ get topK() {
+ const default_value = this.capabilities.defaultTopK || 3
+ const max_value = this.capabilities.maxTopK || 128
+
+ const raw = (this.getAttribute('topK') || '').trim()
+ let candidate = Number(raw)
+ if (isNaN(candidate)) return default_value
+
+ if (raw === 'default') return default_value
+
+ if (candidate < 1) return 1
+ if (candidate > max_value) return max_value
+ return candidate
+ }
+
+ async prompt({systemPrompt, prompt}) {
+
+ const session = this.session = await (() => {
+ if (this.session) {
+ //signal.
+ this.session.destroy()
+ }
+
+ return ai.assistant.create({
+ //signal: this.signal,
+ systemPrompt,
+ topK: this.topK,
+ temperature: this.temperature,
+ })
+ })()
+
+ session.prompt(prompt)
+ .then(response => {
+ this.response = response
+ this._render()
+ })
+ .catch(err => {
+ this.err = err
+ this._render()
+ })
+ }
+
+ _pendingRender = false
+ _render() {
+ if (this._pendingRender) return
+
+ if (this._DEBUG) console.log(`[${this.get_debug_id()}]._render()]:`, {
+ 'this': this
+ })
+
+ setTimeout(() => {
+ this._pendingRender = false
+
+ if (this.err) {
+ this.replaceChildren(
+ new Text(`[ERROR] ${this.err.message}`),
+ )
+ this.style.backgroundColor = 'red'
+ return
+ }
+
+ const temperature = this.temperature
+ const bgcolor = (() => {
+ // https://en.wikipedia.org/wiki/Color_temperature
+
+ if (temperature >= 0.9)
+ return '#FF7900'
+
+ if (temperature >= 0.8)
+ return '#FFBFA1'
+
+ if (temperature >= 0.5)
+ return '#FFE4CC'
+
+ return '#A1BFFF'
+ })()
+ this.style.backgroundColor = bgcolor
+
+ this.innerHTML = `
+ Answer:
+
+
temperature: ${temperature}
+
topK: ${this.topK}
+
tokens: x/max (y left)
+
result:
${this.response || '(pending...)'}
+
+ `
+ })
+ this._pendingRender = true
+ }
+
+ // called each time the element is added to the document. The specification recommends that, as far as possible, developers should implement custom element setup in this callback rather than the constructor.
+ // WARNING https://dev.to/dannyengelman/web-component-developers-do-not-connect-with-the-connectedcallback-yet-4jo7
+ connectedCallback() {
+ if (this._DEBUG) console.log(`[${this.get_debug_id()}].connectedCallback()]:`, { _this: this })
+
+ registry[this._id] = this
+ this._render()
+ }
+ // called each time the element is removed from the document.
+ disconnectedCallback() {
+ if (this._DEBUG) console.log(`[${this.get_debug_id()}].disconnectedCallback()]:`, { _this: this })
+
+ delete registry[this._id]
+ if (this.session) {
+ this.session.destroy()
+ this.session = undefined
+ }
+ }
+ // called each time the element is moved to a new document.
+ adoptedCallback() {
+ if (this._DEBUG) console.log(`[${this.get_debug_id()}].adoptedCallback()]:`, { _this: this })
+ }
+ attributeChangedCallback(name, old_value, new_value) {
+ if (this._DEBUG) console.log(`[${this.get_debug_id()}].attributeChangedCallback():`, { name, old_value, new_value, _this: this })
+ this._render()
+ }
+});
diff --git a/stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/js/magic8ball/consts.js b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/magic8ball/consts.js
similarity index 100%
rename from stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/js/magic8ball/consts.js
rename to stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/magic8ball/consts.js
diff --git a/stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/js/magic8ball/index.js b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/magic8ball/index.js
similarity index 99%
rename from stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/js/magic8ball/index.js
rename to stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/magic8ball/index.js
index 05fe8126..1234df7d 100644
--- a/stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/js/magic8ball/index.js
+++ b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/magic8ball/index.js
@@ -35,7 +35,7 @@ export default async function main() {
}
elt_button_ask.onclick = on_click_ask
- on_click_ask()
+ //on_click_ask()
}
function get_random_standard_8ball_answer() {
diff --git a/stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/notes.md b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/magic8ball/notes.md
similarity index 100%
rename from stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/notes.md
rename to stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/magic8ball/notes.md
diff --git a/stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/js/utils/ai/index.js b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/utils/ai/index.js
similarity index 100%
rename from stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/js/utils/ai/index.js
rename to stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/utils/ai/index.js
diff --git a/stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/js/utils/ai/test.js b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/utils/ai/test.js
similarity index 100%
rename from stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/js/utils/ai/test.js
rename to stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/utils/ai/test.js
diff --git a/stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/js/utils/random/index.js b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/utils/random/index.js
similarity index 100%
rename from stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/js/utils/random/index.js
rename to stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/utils/random/index.js
diff --git a/stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/js/utils/random/test.js b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/utils/random/test.js
similarity index 100%
rename from stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/js/utils/random/test.js
rename to stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/js/utils/random/test.js
diff --git a/stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/magic8ball.html b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/magic8ball.html
similarity index 77%
rename from stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/magic8ball.html
rename to stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/magic8ball.html
index eb946e65..290bc9b4 100644
--- a/stack--current/5-incubator/active/interview--plf/src/applied-ai--8ball/magic8ball.html
+++ b/stack--current/5-incubator/active/interview--plf/src/applied-ai--2024/magic8ball.html
@@ -24,8 +24,8 @@