ToCode
Открыть в Telegram
1 419
Подписчики
+124 часа
Нет данных7 дней
Нет данных30 день
Архив постов
1 421
תזרוק עליו נעליים
כבני אדם אנחנו אוהבים לפתור בעיות, וכמו Chat GPT גם אצלנו כשלא מבינים את הבעיה מתחילים להמציא:
1. נסה למחוק את ה
node_modules ולהתקין מחדש.
2. תעשה ריסטרט לשרת.
3. תחזור לגירסה ישנה של הפרויקט.
4. תשדרג את התלויות.
5. תוציא מהחשמל, ספור עד 10 ותחזיר חזרה.
לפעמים אין ברירה. אני יודע, לפעמים כולם בלחץ, השרת הפסיק לעבוד, צריך עכשיו שיחזור, אין מה לעשות תזרוק עליו נעליים עד שיתחיל לתפקד שוב. הבעיה עם לזרוק נעליים על השרת היא לא שזה לא עובד (נו טוב, קצת שזה לא עובד), אלא שזה ממכר, ובמיוחד אם איזה נעל טלטלה אותו והוא חזר לעבוד.
המטרה שלנו היא להתרגל להיות אלה שעוצרים לחשוב ומוכנים להתאמץ כדי להבין. לזרוק נעליים על השרת רק מרחיק אותנו משם.
נ.ב. לזרוק נעליים על השרת = לזרוק פרומפטים ל AI1 421
פיתרון Advent Of Code 2024 יום 4 בשפת Ruby
את התרגיל הזה קלוד לא הצליח לפתור, לפחות לא עם הפרומפט הפשוט שהדבקתי לו, לכן כבר הרגשתי שמח כשפתרתי אותו לבד. בסיפור שלנו היום אנחנו מקבלים קלט בצורה של מטריצה עם כל מיני אותיות למשל:
..X...
.SAMX.
.A..A.
XMAS.S
.X....
בחלק הראשון עלינו למצוא את כל המופעים של המילה XMAS בקלט אבל בכל הכיוונים (כולל אלכסונים והפוך), כמו בתפזורת מילים. בחלק השני צריך לחפש רק מופעים של MAS שמגיעים בצורת X כלומר:
M.S
.A.
M.S
וגם הם יכולים להיות הפוכים.
התרגיל המקורי נמצא בעמוד שלהם כאן:
https://adventofcode.com/2024/day/4
פיתרון חלק 1
בשביל שני החלקים היה לי נוח לשמור את הקלט במילון, כשהמפתח הוא אינדקס והערך הוא התו שנמצא באינדקס הזה. בתרגילים של AoC למדתי שיותר קל לעבוד עם מילונים כאלה מאשר עם מערכים דו מימדיים. זה הקוד שיוצר את המילון ברובי:
$matrix = File.read('input.txt').lines.each_with_index.flat_map do |line, line_index|
line.split('').each_with_index.map do |char, column_index|
{[line_index, column_index] => char }
end
end.reduce({}) {|acc, val| acc.merge(val) }
קצת ארוך אבל עובד. אם יש לכם רעיונות יותר קצרים אפשר לשתף בתגובות.
הפונקציה הבאה שכתבתי היתה go שפשוט מתקדמת מספר צעדים בכיוון מסוים. הכיוון הכללי לפיתרון היה לרוץ על כל האינדקסים במילון, מכל אינדקס להתקדם 4 צעדים לכל 8 הכיוונים ולראות אם כתובה שם המילה XMAS. הפונקציה go נראית כך:
def go(start, direction, steps = 4)
Enumerator.produce(start) { |r, c| [r + direction[0], c + direction[1]] }.take(steps)
end
והפונקציה המרכזית של הפיתרון היא count_words_around שלוקחת נקודה ומריצה את go לכל 8 הכיוונים ואז סופרת כמה מהכיוונים האלה מכילים את המילה XMAS:
def count_words_around(point)
indexes = [[0, 1],
[1, 1],
[1, 0],
[1, -1],
[0, -1],
[-1, -1],
[-1, 0],
[-1, 1]].map { |direction| go(point, direction, 4) }
indexes.count { |path| $matrix.slice(*path).values.join('') == 'XMAS' }
end
pp $matrix.keys.map {|point| count_words_around(point) }.sum
חלק 2
בחלק השני יצרתי מטריצה באותו אופן אבל על הפונקציה go כבר וויתרתי. במקום ללכת 4 צעדים מספיק לקחת את ה X שמסביב לנקודה ולבדוק אם כתוב בו MAS או SAM. זה הקוד:
def count_words_around(point)
return 0 if $matrix[point] != 'A'
around = [
[-1, -1],
[0, 0],
[1, 1],
[-1, 1],
[0, 0],
[1, -1]
].map { |direction| [point[0] + direction[0], point[1] + direction[1]] }
.map {|i| $matrix[i] }.join('')
if %w[MASMAS MASSAM SAMMAS SAMSAM].include?(around)
1
else
0
end
end
pp $matrix.keys.map {|point| count_words_around(point) }.sum1 421
היום למדתי: הסיפור עם bcrypt ו 72 בתים
לא ברור איך העברתי חיים שלמים בלי לשים לב למגבלה הזאת, אבל עכשיו שגיליתי אותה אני משתף כאן כדי שאתם לא תיפלו באותו בור. לכוכב בסיפור של היום קוראים bcrypt והוא אלגוריתם Password Hashing ישן שעדיין נמצא בשימוש נרחב בהרבה מערכות. בין השאר ספריית Devise שהיא הספריה הפופולרית לניהול משתמשים ב Rails משתמשת בו.
בגדול bcrypt נחשב עדיין מאובטח למרות גילו המבוגר, אבל יש לו מגבלה מתועדת (ומסתבר שמאוד מפורסמת) - הוא לא יודע לערבל סיסמאות ארוכות יותר מ 72 בתים. מה זה אומר? הנה בקוד ריילס:
> u = User.new(name: 'a', email: 'ynon@gmail.com', password: '0' * 80 + '1')
> u.valid_password?('0' * 80 + '2')
=> true
כלומר בדיקת הסיסמאות היא רק על 72 הבתים הראשונים של הסיסמה. כשיש סיסמה ארוכה מ 72 בתים אנחנו מתעלמים מכל מה שבא אחרי.
לקחים? אם אפשר השתמשו ב Aragon2 במקום ב bcrypt, ובכל מקרה כשאתם בוחרים סיסמה לאתר שימו לב לא להתחיל את הסיסמה ב 72 תווים שקל לנחש ורק אז לשים את הסיסמה האמיתית. מי יודע אם הם לא משתמשים בטעות ב bcrypt וחותכים את מה שבא אחרי ה 72.
נ.ב. הפוסט הזה בנושא סופר מעניין וסוקר את המימוש של bcrypt בעוד שפות תכנות בדגש על איזה ספריות יסרבו לעבוד עם קלט שאורכו מעל 72 בתים לעומת איזה ספריות פשוט ימחקו את החלק שאחרי 72 כדי שבכל זאת דברים יעבדו:
https://n0rdy.foo/posts/20250121/okta-bcrypt-lessons-for-better-apis/1 421
טיפ פייתון: מחיקת שורה ראשונה מטקסט עם StringIO
הפונקציה הבאה מקבלת מחרוזת טקסט ומחזירה את הטקסט בלי השורה הראשונה:
def remove_first_line(text):
return '\n'.join(text.splitlines()[1:])
אבל אם בטעות נעביר ל None היא תזרוק Exception. בנוסף חיבור המחרוזות עם n עלול להיות מבלבל כי מי שיגיע לקרוא את הקוד עלול לתהות מה קורה ב Windows שם תו סוף השורה הוא שונה. לפעמים זה רעיון טוב לעצור את התוכנית אם מקבלים None, אבל לפעמים אנחנו רוצים לבנות משהו יותר גמיש. דרך נוספת למחוק את השורה הראשונה היא הקלאס StringIO מתוך המחלקה io. הנה גירסה שנייה של אותה פונקציה:
def remove_first_line(text: str):
f = StringIO(text)
f.readline()
return f.read()
הפונקציה יוצרת אוביקט שנראה כמו קובץ, אבל בעצם קורא מחרוזת מרובת שורות. בעזרת המתודות readline ו read אנחנו יכולים לקבל את כל השורות שאחרי הראשונה, בלי לפרק ולהדביק מחדש את השורות וגם אם מעבירים לפונקציה None הכל עדיין מסתדר והיא תחזיר מחרוזת ריקה.1 421
לספר מה בנינו או לדעת מה נבנה?
מה עדיף, לכתוב את הבדיקות לפני או אחרי הקוד? ואת דף הפרויקט בגיאהב? ואת התיעוד? והמדריך למשתמש?
בעבודה על פרויקט צד, רבים מעדיפים קודם לבנות את הפרויקט ואז לספר לעולם מה בנינו: אחרי כתיבת הקוד מנסחים הודעת קומיט, אחרי שהקוד מוכן כותבים בדיקות ותיעוד, אחרי שהפרויקט באוויר כותבים דף פרוקיט בגיטהאב ואחרי שהוצאנו גירסה חדשה כותבים ב Release Notes מה עשינו. התוצאה הרבה פעמים היא פרויקט "שצריך עוד תשומת לב" ומפתח שכבר התעייף מתחזוקה שלו. חלק גדול מהגישה הזאת נובע מפחד, פחד להתחייב.
אם נשים את הפחד בצד רגע נוכל לנסות גישה שונה:
1. בפרויקט קוד פתוח - מתחילים מבניית דף גיטהאב לפרויקט ומסבירים מה יהיה בו, מה הארכיטקטורה, מה התהליכים המרכזיים במערכת, באיזה טכנולוגיות נשתמש וכן גם איך אפשר לתרום קוד לפרויקט. כבר בקומיטים הראשונים מייצרים את ה Action שמעביר את הפרויקט לפרודקשן.
2. בפרויקט בתשלום - מתחילים מבניית דף נחיתה לפרויקט שמסביר מה אנחנו רוצים לבנות, כולל "צילומי מסך" ו Use Cases למוצר, והכי חשוב תיבה לאיסוף מיילים של אנשים שמתעניינים בפרויקט.
נכון, לבנות מוצר לפי Spec זה פחות מלהיב מ"לגלות תוך כדי תנועה", אבל מגדיל את הסיכויים שהפרויקט יראה אור יום בתור פרויקט שנהיה גאים בו.
1 421
force_path_style: true, # Enable 'force_path_style' => true, if bucket name is non DNS compliant
)
bucket_name = "test-bucket"
wrapper = BucketCreateWrapper.new(Aws::S3::Bucket.new(bucket_name))
return unless wrapper.create?(region)
puts "Created bucket #{wrapper.bucket.name}."
puts "Your bucket's region is: #{wrapper.location}"
end
run_demo if $PROGRAM_NAME == __FILE__
סקריפט שני כותב קובץ לאותו bucket:
require 'aws-sdk-s3'
region = "us-east-2"
Aws.config.update(
endpoint: 'http://s3.localhost.localstack.cloud:4566', # update with localstack endpoint
region: region,
force_path_style: true, # Enable 'force_path_style' => true, if bucket name is non DNS compliant
)
s3_client = Aws::S3::Client.new
bucket_name = 'test-bucket'
object_key = 'demo.txt'
file_content = "This is a demo file uploaded via Ruby to my LocalStack S3.\n"
begin
response = s3_client.put_object(
bucket: bucket_name,
key: object_key,
body: file_content
)
puts "File '#{object_key}' uploaded successfully to '#{bucket_name}'!"
rescue Aws::S3::Errors::ServiceError => e
puts "Error uploading file: #{e.message}"
end
וסקריפט שלישי עדיין ברובי קורא את הקובץ ומדפיס את תוכנו:
require 'aws-sdk-s3'
Aws.config.update(
endpoint: 'http://s3.localhost.localstack.cloud:4566', # update with localstack endpoint
region: 'us-east-2',
force_path_style: true # Enable 'force_path_style' => true, if bucket name is non DNS complian
)
s3_client = Aws::S3::Client.new
bucket_name = 'test-bucket'
object_key = 'demo.txt'
begin
response = s3_client.get_object(bucket: bucket_name, key: object_key)
file_contents = response.body.read
puts "Contents of '#{object_key}' in bucket '#{bucket_name}':\n\n"
puts file_contents
rescue Aws::S3::Errors::NoSuchKey => e
puts "File '#{object_key}' not found: #{e.message}"
rescue Aws::S3::Errors::ServiceError => e
puts "Error retrieving file: #{e.message}"
end
לסיום אפשר למחוק את הבאקט עם הסקריפט פייתון שהתקנו קודם בהפעלת:
$ awslocal s3 rb s3://test-bucket --force
סך הכל הפיתוח עם local stack מאפשר עבודה באותו ממשק כמו AWS אבל מקומית לגמרי. ברור שבסיום הפיתוח צריך לבדוק הכל על AWS ובטח יהיו בעיות ועוד צריך לדבר על הרשאות והכל נכון. אבל למי שרוצה להתחיל פיתוח שיגיע ל AWS אבל בינתיים רק לראות שדברים עובדים אצלנו על המחשב לוקאל סטאק יכול לתת פיתרון מצוין ומהיר.1 421
צעדים ראשונים עם localstack
לוקאל סטאק https://github.com/localstack/localstack הוא פרויקט שמטרתו הפעלת גירסה מקומית של AWS אצלכם על המחשב בתוך קונטיינר. הם מכסים עשרות סרביסים של AWS בחשבון החינמי, ויש גם חשבון בתשלום שכולל יותר יכולות לחלק מהסרביסים ויותר סרביסים. מה שאהבתי במיוחד בעבודה עם local stack זה שהקוד לא צריך להשתנות - הממשק שלהם זהה לממשק של AWS מלבד פקודת קונפיגורציה אחת שמגדירה את ה endpoint שלהם במקום של AWS.
בואו נראה איך להתקין ולעבוד עם סרביס S3 של לוקאל סטאק דרך שלושה סקריפטים.
התקנת הכלים
את לוקאל סטאק אפשר להתקין מדף ההתקנה שלהם כאן:
https://docs.localstack.cloud/getting-started/installation/
אחרי ההתקנה הייתי צריך להוסיף את התיקיה שלהם לתיקיות הקבצים של Docker Desktop מתוך ההגדרות של דוקר, וגם להתקין סקריפט שעוטף את aws באמצעות הפקודה:
pip install awscli-local
הפעלתי את local stack עם:
$ localstack start -d
ואחרי זה הרצתי את פקודת הסטטוס כדי לראות את הסרביסים שקיבלתי:
$ localstack status services
┏━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓
┃ Service ┃ Status ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━┩
│ acm │ ✔ available │
│ apigateway │ ✔ available │
│ cloudformation │ ✔ available │
│ cloudwatch │ ✔ available │
│ config │ ✔ available │
│ dynamodb │ ✔ available │
│ dynamodbstreams │ ✔ available │
│ ec2 │ ✔ available │
│ es │ ✔ available │
│ events │ ✔ available │
│ firehose │ ✔ available │
│ iam │ ✔ available │
│ kinesis │ ✔ available │
│ kms │ ✔ available │
│ lambda │ ✔ available │
│ logs │ ✔ available │
│ opensearch │ ✔ available │
│ redshift │ ✔ available │
│ resource-groups │ ✔ available │
│ resourcegroupstaggingapi │ ✔ available │
│ route53 │ ✔ available │
│ route53resolver │ ✔ available │
│ s3 │ ✔ running │
│ s3control │ ✔ available │
│ scheduler │ ✔ available │
│ secretsmanager │ ✔ available │
│ ses │ ✔ available │
│ sns │ ✔ available │
│ sqs │ ✔ available │
│ ssm │ ✔ available │
│ stepfunctions │ ✔ available │
│ sts │ ✔ available │
│ support │ ✔ available │
│ swf │ ✔ available │
│ transcribe │ ✔ available │
└──────────────────────────┴─────────────┘
עבודה עם S3
נמשיך לכמה סקריפטים ב Ruby שעובדים עם S3 בשביל הדוגמה. בכולם השורה הכי חשובה היא:
Aws.config.update(
endpoint: 'http://s3.localhost.localstack.cloud:4566'
region: 'us-east-2',
force_path_style: true
)
הסקריפט הראשון יוצר bucket חדש על s3 שרץ על local stack:
require "aws-sdk-s3"
class BucketCreateWrapper
attr_reader :bucket
def initialize(bucket)
@bucket = bucket
end
def create?(region)
@bucket.create(create_bucket_configuration: { location_constraint: region })
true
rescue Aws::Errors::ServiceError => e
puts "Couldn't create bucket. Here's why: #{e.message}"
false
end
def location
if @bucket.nil?
"None. You must create a bucket before you can get its location!"
else
@bucket.client.get_bucket_location(bucket: @bucket.name).location_constraint
end
rescue Aws::Errors::ServiceError => e
"Couldn't get the location of #{@bucket.name}. Here's why: #{e.message}"
end
end
def run_demo
region = "us-east-2"
Aws.config.update(
endpoint: 'http://s3.localhost.localstack.cloud:4566', # update with localstack endpoint
region: region,1 421
קצת קשה להתמצא באתר שלהם, אבל בתחתית העמוד יש מספר לינקים שימושיים ובמיוחד שווה לחטט בדף Trending Vals. תוכלו למצוא שם אינסוף סקריפטים שאנשים אחרים כתבו ותוכלו לשלב אותם בעבודה שלכם. בצד ימין למעלה יש אייקון של זכוכית מגדלת שיפתח תיבת חיפוש אם אתם רוצים לחפש סקריפטים לפי טקסט.
בנוסף הסקריפטים מקבלים גישה למספר משאבים על val.town שיעזרו לכם לכתוב דברים שימושיים: הם יודעים לשלוח אימייל, לשמור מידע בבסיס נתונים, לשמור קבצים מקומית וכמו שכבר סיפרתי לתקשר עם ChatGPT.
וכאילו שזה לא מספיק יש להם סוכן AI שכותב את הסקריפטים ומריץ אותם כך שלכם נשאר רק להביא את הרעיון.
נ.ב. העליתי לטלגרם את הבוט תרגום שתיארתי כאן. קוראים
@SpeakEnglishToMe_bot ואתם מוזמנים לשלוח אליו מילים הוא יענה בתרגום. או מה שיותר מעניין, קחו את התבנית מכאן, תעשו fork ב val town ותעלו בוטים משלכם.1 421
ואל טאון הוא הפרויקט הכי מדליק שאתם לא מכירים
אתמול פרסמתי פה סקריפט שכתבתי שמחפש מידע על פודקסטים ב val.town. כן הכרתי את val.town בעיקר בזכות הסלוגן עם החרוז שלהם וקצת זכרתי שזה אתר שיתוף קוד כמו קודפן רק לצד שרת, אבל המשחקים איתו בימים האחרונים השאירו אותי בפה פעור. ואל טאון הוא הפרויקט הכי מדליק שאתם לא מכירים, ואנסה להסביר למה:
סקריפטים פשוטים ב val town
ואל טאון מאפשר לכם לכתוב סקריפטים כולל מאוד קצרים (סקריפט של פונקציה בודדת הולך טוב). את הסקריפטים האלה אפשר להריץ ידנית או מתוך סקריפטים אחרים, מה שנותן לנו מגרש משחקים לבניית מגדלים מלגו. הנה סקריפט פשוט שכתבתי שמתרגם טקסט דרך ChatGPT מכל שפה לאנגלית:
import { OpenAI } from "https://esm.town/v/std/openai";
export default async function translateToEnglishWithOpenAI(text: string) {
const openai = new OpenAI();
const completion = await openai.chat.completions.create({
messages: [
{
role: "user",
content:
\Translate "שלום" to English. If the word the was already in English respond with its definition. Respond just with the translation or definition.\,
},
{ role: "assistant", content: \hello\ },
{
role: "user",
content:
\Translate "peace" to English. If the word the was already in English respond with its definition. Respond just with the translation or definition.\,
},
{
role: "assistant",
content:
\Peace is a stress-free state of security and calmness that comes when there’s no fighting or war, everything coexisting in perfect harmony and freedom.\,
},
{
role: "user",
content:
\Translate "${text}" to English. If the word the was already in English respond with its definition. Respond just with the translation or definition.\,
},
],
model: "gpt-4",
});
return completion.choices[0].message.content || "Translation Error";
}
ואם תתחברו לואל טאון (זה בחינם) תוכלו לשנות את הקוד ולהריץ את הסקריפט מתוך דף הסקריפט בכתובת:
https://www.val.town/v/ynonp/translateToEnglishWithOpenAI
לא צריך מפתח API ל Chat GPT כי ואל טאון נותנים לכם במתנה.
בניית סקריפטים גדולים יותר על בסיס הפשוטים
אפשר לשלב כל סקריפט שאנחנו בונים ב val.town בסקריפטים אחרים. לדוגמה הסקריפט הזה:
import translateToEnglish from "https://esm.town/v/ynonp/translateToEnglishWithOpenAI";
console.log(await translateToEnglish("מה המצב"));
או יותר מעניין, הסקריפט הזה שמייצג בוט לטלגרם:
import { OpenAI } from "https://esm.town/v/std/openai";
import { telegramSendMessage } from "https://esm.town/v/vtdocs/telegramSendMessage?v=5";
import translateToEnglishWithOpenAI from "https://esm.town/v/ynonp/translateToEnglishWithOpenAI";
export const telegramWebhookEchoMessage = async (req: Request) => {
// Verify this webhook came from our bot
if (
req.headers.get("x-telegram-bot-api-secret-token")
!== Deno.env.get("TELEGRAM_WEBHOOK_SECRET")
) {
return new Response("Not Allowed", { status: 401 });
}
// Echo back the user's message
const body = await req.json();
const text: string = body.message.text;
const chatId: number = body.message.chat.id;
const translated = await translateToEnglishWithOpenAI(text);
if (translated) {
await telegramSendMessage(
Deno.env.get("TELEGRAM_BOT_TOKEN"),
{ chat_id: chatId, text: translated },
);
} else {
await telegramSendMessage(
Deno.env.get("TELEGRAM_BOT_TOKEN"),
{ chat_id: chatId, text: "Translation error" },
);
}
return Response.json("ok");
};
את הסקריפטים שאתם כותבים שם אפשר להריץ בתגובה לאימייל שנשלח, בצורה מחזורית (cron job) או בתגובה לבקשת HTTP (כמו הבוט לטלגרם פה).
מה עוד1 421
היום למדתי: חיפוש פודקסטים ב podcast index
ל val town יש את אחד ה AI-ים הכי חמודים שפגשתי - לא רק שהוא כותב את הקוד בשבילי, אפשר גם להריץ ולעשות Deploy בלחיצת כפתור, וכל זה בחינם. וכן אני יודע שגם רפליט מספקים שירות דומה ואפילו עם תמיכה בהרבה יותר שפות, אבל רפליט לאחרונה מרגיש מסורבל מדי.
בחזרה ל val town בשביל לשחק עם הבוט ביקשתי שיכתוב פונקציה לחיפוש פודקסטים ב podcast index. למרבה ההפתעה התוצאה עבדה בניסיון הראשון, כולל הטריק מה API שלהם עם ה sha1 למפתח. זה הקוד:
import crypto from "https://esm.sh/crypto-js";
export default async function searchPodcasts(query: string) {
const apiKey = Deno.env.get("PODCAST_INDEX_API_KEY");
const apiSecret = Deno.env.get("PODCAST_INDEX_API_SECRET");
// Generate authentication headers as per Podcast Index API requirements
const currentTime = Math.floor(Date.now() / 1000);
const hashString = apiKey + apiSecret + currentTime;
const hash = crypto.SHA1(hashString).toString();
const headers = {
"X-Auth-Key": apiKey,
"X-Auth-Date": currentTime.toString(),
"Authorization": hash,
"User-Agent": "ValTownPodcastSearch/1.0",
};
try {
const response = await fetch(\https://api.podcastindex.org/api/1.0/search/byterm?q=${encodeURIComponent(query)}\, {
method: "GET",
headers: headers,
});
if (!response.ok) {
throw new Error(\HTTP error! status: ${response.status}\);
}
const data = await response.json();
return data.feeds.map(podcast => ({
title: podcast.title,
description: podcast.description,
url: podcast.url,
artwork: podcast.artwork,
}));
} catch (error) {
console.error("Podcast search error:", error);
return [];
}
}
console.log(await searchPodcasts("syntax"));
ואם יש לכם 5 דקות תוכלו גם ליצור חשבון ב val town ולהריץ אותו ישר מהממשק שלהם בקישור:
https://www.val.town/v/ynonp/righteousLimeGalliform
רק שימו לב שצריך קודם ליצור את שני משתני הסביבה PODCAST_INDEX_API_KEY ו PODCAST_INDEX_API_SECRET דרך הממשק של val town לחשבון שלכם בקישור:
https://www.val.town/settings/environment-variables
ובשביל לקבל את המפתחות יש ליצור חשבון ב podcast index api:
https://api.podcastindex.org/
נ.ב. הממשק של podcast index די מדליק אפשר למצוא את כל המידע על פודקסט, רשימות הפרקים וגם לינקים לקבצי הקול של כל פרק.1 421
חידת Vue - איך עובד Scoped Style
נכתוב את הקוד הבא בקומפוננטת App.vue:
<script setup>
import Child from './Child.vue';
</script>
<template>
<p class="red">Hello World from App</p>
<Child />
</template>
<style scoped>
.red {
color: red;
}
</style>
וזה Child.vue:
<script setup></script>
<template>
<button class="red">
Hello World from Child
</button>
</template>
אפשר לראות את הדוגמה לייב בקישור הזה:
https://tinyurl.com/4nff62kp
עכשיו לשאלות - למה הטקסט בכפתור מופיע באדום? ואיך אפשר "לנתק" אותו מהעיצוב של App כדי שלא יקבל את הגדרת האדום משם?
שימו לב שהגדרות העיצוב הן בבלוק styled scoped ושזו לא הבעיה שמתוארת כאן:
https://www.tocode.co.il/blog/2021-10-watch-out-inherited-css, למרות שגם הבעיה בפוסט ההוא מעניינת.