12 Commits

Author SHA1 Message Date
Renovate Bot
f777fb4013 chore(deps): update dependency @types/react-test-renderer to v17.0.2 2022-04-16 13:24:26 +00:00
Renovate Bot
3c54a53055 chore(deps): update dependency @testing-library/react to v12.1.5 2022-04-16 13:14:12 +00:00
Renovate Bot
6b8c33697e chore(deps): update dependency @rollup/plugin-typescript to v8.3.2 2022-04-16 10:00:58 +00:00
Renovate Bot
0f7415234b fix(deps): pin dependency @sentry/gatsby to 6.19.6 2022-04-16 04:11:39 +00:00
camperbot
6060197423 chore(i18n,docs): processed translations (#45685) 2022-04-16 04:14:53 +09:00
camperbot
d177ff4e11 chore(i18n,learn): processed translations (#45682) 2022-04-15 14:16:36 -03:00
camperbot
049689bbd8 chore(i18n,client): processed translations (#45681) 2022-04-15 14:14:15 -03:00
Naomi Archibong
4ff9c2a6fc feat: update wording for string length (#45602) 2022-04-15 08:13:42 -07:00
Tristan Toye
dfe5a7fd05 Add Sentry to client for error handling (#43920)
Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
2022-04-15 09:54:02 -05:00
Rafael D. Hernandez
832eb29c0d fix(learn): Change width for piano on step 28 (#45673)
* fix: change width on step 28

* fix: update step-33 seed

Co-authored-by: Rafael Hernandez <rafaeldavish@Rafaels-MacBook-Pro.local>
2022-04-15 09:36:24 -05:00
Oliver Eyton-Williams
4cc20172c5 fix: fallback to english challenges (#45635)
* fix: fallback to english challenges

All challenges will use the english version if a translated file is not
available.  SHOW_NEW_CURRICULUM still gates what's shown in the client.

* refactor: use closures to simplify createChallenge

* refactor: remove messy destructure

* refactor: add meta via helper

* fix: fallback to [] for meta.required

* fix: repair challenge.block

* refactor: use CONST_CASE for meta + challenge dirs

* fix: catch empty superblocks immediately

* fix: clean up path.resolves

* fix: invalid syntax in JS project steps

* fix: default to english comments and relax tests

Instead of always throwing errors when a comment is not translated, the
tests now warn while SHOW_UPCOMING_CHANGES is true, so that tests will
pass while we're developing and allow translators time to work.

They still throw when SHOW_UPCOMING_CHANGES is false to catch issues
in production

* test: update createCommentMap test

* refactor: delete stale comment

* refactor: clarify validate with explanatory consts

* feat: throw if audited cert falls back to english

* fix: stop testing upcoming localized curriculum
2022-04-15 09:17:49 -05:00
Tom
e0a5fcdb8e fix: add message about third-party cookies (#45672) 2022-04-13 20:56:16 +05:30
107 changed files with 5110 additions and 376 deletions

View File

@@ -141,7 +141,6 @@ jobs:
- name: Set Environment variables
run: |
cp sample.env .env
echo 'SHOW_UPCOMING_CHANGES=true' >> .env
cat .env
- name: Install Dependencies

View File

@@ -18,11 +18,11 @@ const reqLogFormat = ':date[iso] :status :method :response-time ms - :url';
// this may be brittle
log.enabled = true;
if (sentry.dns === 'dsn_from_sentry_dashboard') {
if (sentry.dsn === 'dsn_from_sentry_dashboard') {
log('Sentry reporting disabled unless DSN is provided.');
} else {
Sentry.init({
dsn: sentry.dns
dsn: sentry.dsn
});
log('Sentry initialized');
}

View File

@@ -4,14 +4,14 @@ import { isHandledError } from '../utils/create-handled-error';
// sends directly to Sentry
export function reportError(err) {
return sentry.dns === 'dsn_from_sentry_dashboard'
return sentry.dsn === 'dsn_from_sentry_dashboard'
? console.error(err)
: captureException(err);
}
// determines which errors should be reported
export default function sentryErrorHandler() {
return sentry.dns === 'dsn_from_sentry_dashboard'
return sentry.dsn === 'dsn_from_sentry_dashboard'
? (req, res, next) => next()
: Handlers.errorHandler({
shouldHandleError(err) {

View File

@@ -2,7 +2,7 @@ import { Handlers } from '@sentry/node';
import { sentry } from '../../../../config/secrets';
export default function sentryRequestHandler() {
return sentry.dns === 'dsn_from_sentry_dashboard'
return sentry.dsn === 'dsn_from_sentry_dashboard'
? (req, res, next) => next()
: Handlers.requestHandler();
}

View File

@@ -6,7 +6,8 @@ const {
localeChallengesRootDir
} = require('./utils/build-challenges');
const { clientLocale, curriculumLocale, homeLocation } = envData;
const { clientLocale, curriculumLocale, homeLocation, sentryClientDSN } =
envData;
const curriculumIntroRoot = path.resolve(__dirname, './src/pages');
const pathPrefix =
@@ -24,6 +25,12 @@ module.exports = {
},
pathPrefix: pathPrefix,
plugins: [
{
resolve: '@sentry/gatsby',
options: {
dsn: sentryClientDSN
}
},
{
resolve: 'gatsby-plugin-webpack-bundle-analyser-v2',
options: {

View File

@@ -783,6 +783,7 @@
"viewing-upcoming-change": "你正在查看Beta頁面。 ",
"go-back-to-learn": "回到正式版課程",
"read-database-cert-article": "請在繼續之前閱讀這個論壇帖子。",
"enable-cookies": "You must enable third-party cookies before starting.",
"english-only": "本部分的課程只提供英文。我們目前只能翻譯標題和介紹,而不能翻譯課程本身。"
}
}

View File

@@ -68,8 +68,8 @@
"ask-later": "稍後問我",
"start-coding": "開始編碼!",
"go-to-settings": "轉到設置以申請你的認證",
"click-start-course": "單擊此處開始課程",
"click-start-project": "點擊此處啓動項目"
"click-start-course": "Start the course",
"click-start-project": "Start the project"
},
"landing": {
"big-heading-1": "免費學習編程",
@@ -536,7 +536,8 @@
"code-save-error": "An error occurred trying to save your code.",
"code-save-less": "Slow Down! Your code was not saved. Try again in a few seconds.",
"challenge-save-too-big": "Sorry, you cannot save your code. Your code is {{user-size}} bytes. We allow a maximum of {{max-size}} bytes. Please make your code smaller and try again or request assistance on https://forum.freecodecamp.org",
"challenge-submit-too-big": "Sorry, you cannot submit your code. Your code is {{user-size}} bytes. We allow a maximum of {{max-size}} bytes. Please make your code smaller and try again or request assistance on https://forum.freecodecamp.org"
"challenge-submit-too-big": "Sorry, you cannot submit your code. Your code is {{user-size}} bytes. We allow a maximum of {{max-size}} bytes. Please make your code smaller and try again or request assistance on https://forum.freecodecamp.org",
"invalid-update-flag": "You are attempting to access forbidden resources. Please request assistance on https://forum.freecodecamp.org if this is a valid request."
},
"validation": {
"max-characters": "字符數最多爲 288 個,你還可以輸入 {{charsLeft}} 個字符",

View File

@@ -783,6 +783,7 @@
"viewing-upcoming-change": "你正在查看Beta页面。 ",
"go-back-to-learn": "回到正式版课程",
"read-database-cert-article": "请在继续之前阅读这个论坛帖子。",
"enable-cookies": "You must enable third-party cookies before starting.",
"english-only": "本部分的课程只提供英文。我们目前只能翻译标题和介绍,而不能翻译课程本身。"
}
}

View File

@@ -68,8 +68,8 @@
"ask-later": "稍后问我",
"start-coding": "开始编码!",
"go-to-settings": "转到设置以申请你的认证",
"click-start-course": "单击此处开始课程",
"click-start-project": "点击此处启动项目"
"click-start-course": "Start the course",
"click-start-project": "Start the project"
},
"landing": {
"big-heading-1": "免费学习编程",
@@ -536,7 +536,8 @@
"code-save-error": "An error occurred trying to save your code.",
"code-save-less": "Slow Down! Your code was not saved. Try again in a few seconds.",
"challenge-save-too-big": "Sorry, you cannot save your code. Your code is {{user-size}} bytes. We allow a maximum of {{max-size}} bytes. Please make your code smaller and try again or request assistance on https://forum.freecodecamp.org",
"challenge-submit-too-big": "Sorry, you cannot submit your code. Your code is {{user-size}} bytes. We allow a maximum of {{max-size}} bytes. Please make your code smaller and try again or request assistance on https://forum.freecodecamp.org"
"challenge-submit-too-big": "Sorry, you cannot submit your code. Your code is {{user-size}} bytes. We allow a maximum of {{max-size}} bytes. Please make your code smaller and try again or request assistance on https://forum.freecodecamp.org",
"invalid-update-flag": "You are attempting to access forbidden resources. Please request assistance on https://forum.freecodecamp.org if this is a valid request."
},
"validation": {
"max-characters": "字符数最多为 288 个,你还可以输入 {{charsLeft}} 个字符",

View File

@@ -768,6 +768,7 @@
"viewing-upcoming-change": "You are looking at a beta page. ",
"go-back-to-learn": "Go back to the stable version of the curriculum.",
"read-database-cert-article": "Please read this forum post before proceeding.",
"enable-cookies": "You must enable third-party cookies before starting.",
"english-only": "The courses in this section are only available in English. We are only able to translate the titles and introductions at the moment, not the lessons themselves."
}
}

View File

@@ -68,8 +68,8 @@
"ask-later": "Ask me later",
"start-coding": "Start coding!",
"go-to-settings": "Go to settings to claim your certification",
"click-start-course": "Click here to start the course",
"click-start-project": "Click here to start the project"
"click-start-course": "Start the course",
"click-start-project": "Start the project"
},
"landing": {
"big-heading-1": "Learn to code — for free.",

View File

@@ -783,6 +783,7 @@
"viewing-upcoming-change": "Estás viendo una página beta. ",
"go-back-to-learn": "Volver a la versión estable del currículum.",
"read-database-cert-article": "Por favor, lea este post del foro antes de continuar.",
"enable-cookies": "You must enable third-party cookies before starting.",
"english-only": "The courses in this section are only available in English. We are only able to translate the titles and introductions at the moment, not the lessons themselves."
}
}

View File

@@ -68,8 +68,8 @@
"ask-later": "Pregúntame luego",
"start-coding": "¡Empieza a programar!",
"go-to-settings": "Ve a la configuración para reclamar tu certificación",
"click-start-course": "Haga clic aquí para iniciar el curso",
"click-start-project": "Haga clic aquí para iniciar el proyecto"
"click-start-course": "Start the course",
"click-start-project": "Start the project"
},
"landing": {
"big-heading-1": "Aprende a programar gratis.",
@@ -536,7 +536,8 @@
"code-save-error": "An error occurred trying to save your code.",
"code-save-less": "Slow Down! Your code was not saved. Try again in a few seconds.",
"challenge-save-too-big": "Sorry, you cannot save your code. Your code is {{user-size}} bytes. We allow a maximum of {{max-size}} bytes. Please make your code smaller and try again or request assistance on https://forum.freecodecamp.org",
"challenge-submit-too-big": "Sorry, you cannot submit your code. Your code is {{user-size}} bytes. We allow a maximum of {{max-size}} bytes. Please make your code smaller and try again or request assistance on https://forum.freecodecamp.org"
"challenge-submit-too-big": "Sorry, you cannot submit your code. Your code is {{user-size}} bytes. We allow a maximum of {{max-size}} bytes. Please make your code smaller and try again or request assistance on https://forum.freecodecamp.org",
"invalid-update-flag": "You are attempting to access forbidden resources. Please request assistance on https://forum.freecodecamp.org if this is a valid request."
},
"validation": {
"max-characters": "Hay un límite máximo de 288 caracteres, te quedan {{charsLeft}}",

View File

@@ -783,6 +783,7 @@
"viewing-upcoming-change": "Stai guardando ad una pagina in beta. ",
"go-back-to-learn": "Torna alla versione stabile del curriculum.",
"read-database-cert-article": "Per favore leggi questo post sul forum prima di procedere.",
"enable-cookies": "You must enable third-party cookies before starting.",
"english-only": "I corsi in questa sezione sono disponibili solo in inglese. Siamo solo in grado di tradurre i titoli e le introduzioni in questo momento, non le lezioni stesse."
}
}

View File

@@ -68,8 +68,8 @@
"ask-later": "Chiedimelo più tardi",
"start-coding": "Inizia a programmare!",
"go-to-settings": "Vai alle impostazioni per richiedere la tua certificazione",
"click-start-course": "Fai click qui per iniziare il corso",
"click-start-project": "Fai click qui per iniziare il progetto"
"click-start-course": "Start the course",
"click-start-project": "Start the project"
},
"landing": {
"big-heading-1": "Impara a programmare — gratis.",
@@ -536,7 +536,8 @@
"code-save-error": "C'è stato un errore provando asalvare il tuo codice.",
"code-save-less": "Rallenta! Il tuo codice non è stato salvato. Prova di nuovo tra qualche secondo.",
"challenge-save-too-big": "Ci dispiace, non possiamo salvare il tuo codice. Il tuo codice è {{user-size}} byte. Il massimo è di {{max-size}} byte. Per cortesia rendi il tuo codice più piccolo o richiedi assistenza a https://forum.freecodecamp.org",
"challenge-submit-too-big": "Ci dispiace, non puoi consegnare il tuo codice. Il tuo codice è {{user-size}} byte. Il massimo è di {{max-size}} byte. Per cortesia rendi il tuo codice più piccolo o richiedi assistenza a https://forum.freecodecamp.org"
"challenge-submit-too-big": "Ci dispiace, non puoi consegnare il tuo codice. Il tuo codice è {{user-size}} byte. Il massimo è di {{max-size}} byte. Per cortesia rendi il tuo codice più piccolo o richiedi assistenza a https://forum.freecodecamp.org",
"invalid-update-flag": "You are attempting to access forbidden resources. Please request assistance on https://forum.freecodecamp.org if this is a valid request."
},
"validation": {
"max-characters": "C'è un limite massimo di 288 caratteri, hai {{charsLeft}} rimanenti",

View File

@@ -783,6 +783,7 @@
"viewing-upcoming-change": "ベータ版のページを閲覧中です。 ",
"go-back-to-learn": "カリキュラムの安定版へ戻る。",
"read-database-cert-article": "続行する前に、こちらのフォーラム投稿をお読みください。",
"enable-cookies": "You must enable third-party cookies before starting.",
"english-only": "このセクションのコースは、英語版でのみ利用可能です。現時点ではタイトルと紹介文のみが翻訳に対応しており、レッスン自体は翻訳されておりません。"
}
}

View File

@@ -68,8 +68,8 @@
"ask-later": "後で",
"start-coding": "コーディングを始めましょう!",
"go-to-settings": "設定へ移動して認定証を取得",
"click-start-course": "こちらをクリックしてコースを開始",
"click-start-project": "こちらをクリックしてプロジェクトを開始"
"click-start-course": "Start the course",
"click-start-project": "Start the project"
},
"landing": {
"big-heading-1": "プログラミングを無料で学ぶ。",
@@ -536,7 +536,8 @@
"code-save-error": "コードの保存中にエラーが発生しました。",
"code-save-less": "コードは保存されませんでした。数秒時間をおいて、もう一度お試しください。",
"challenge-save-too-big": "コードを保存できませんでした。あなたのコードは {{user-size}} バイトですが、保存可能なコードは最大 {{max-size}} バイトです。コードを削減してもう一度お試しいただくか、https://forum.freecodecamp.org にてサポートを依頼してください。",
"challenge-submit-too-big": "コードを提出できませんでした。あなたのコードは {{user-size}} バイトですが、提出可能なコードは最大 {{max-size}} バイトです。コードを削減してもう一度お試しいただくか、https://forum.freecodecamp.org にてサポートを依頼してください。"
"challenge-submit-too-big": "コードを提出できませんでした。あなたのコードは {{user-size}} バイトですが、提出可能なコードは最大 {{max-size}} バイトです。コードを削減してもう一度お試しいただくか、https://forum.freecodecamp.org にてサポートを依頼してください。",
"invalid-update-flag": "You are attempting to access forbidden resources. Please request assistance on https://forum.freecodecamp.org if this is a valid request."
},
"validation": {
"max-characters": "上限は 288 文字です。残り {{charsLeft}} 文字です。",

View File

@@ -783,6 +783,7 @@
"viewing-upcoming-change": "Você está vendo uma página em estágio beta. ",
"go-back-to-learn": "Voltar à versão estável do currículo.",
"read-database-cert-article": "Leia esta publicação no fórum antes de prosseguir.",
"enable-cookies": "You must enable third-party cookies before starting.",
"english-only": "Os cursos desta seção estão disponíveis apenas em inglês. Neste momento, só podemos traduzir os títulos e as introduções, não as próprias lições."
}
}

View File

@@ -68,8 +68,8 @@
"ask-later": "Pergunte-me depois",
"start-coding": "Comece a programar!",
"go-to-settings": "Vá para as configurações para solicitar sua certificação",
"click-start-course": "Clique aqui para iniciar o curso",
"click-start-project": "Clique aqui para iniciar o projeto"
"click-start-course": "Start the course",
"click-start-project": "Start the project"
},
"landing": {
"big-heading-1": "Aprenda a programar — de graça.",
@@ -536,7 +536,8 @@
"code-save-error": "Ocorreu um erro ao tentar salvar seu código.",
"code-save-less": "Devagar! O código não foi salvo. Tente novamente em alguns segundos.",
"challenge-save-too-big": "Não foi possível salvar seu código. Seu código tem {{user-size}} bytes. A capacidade é de, no máximo, {{max-size}} bytes. Diminua o tamanho do seu código e tente novamente ou peça assistência em https://forum.freecodecamp.org",
"challenge-submit-too-big": "Não foi possível enviar seu código. Seu código tem {{user-size}} bytes. É possível enviar, no máximo, {{max-size}} bytes. Diminua o tamanho do seu código e tente novamente ou peça assistência em https://forum.freecodecamp.org"
"challenge-submit-too-big": "Não foi possível enviar seu código. Seu código tem {{user-size}} bytes. É possível enviar, no máximo, {{max-size}} bytes. Diminua o tamanho do seu código e tente novamente ou peça assistência em https://forum.freecodecamp.org",
"invalid-update-flag": "You are attempting to access forbidden resources. Please request assistance on https://forum.freecodecamp.org if this is a valid request."
},
"validation": {
"max-characters": "Há um limite máximo de 288 caracteres, você tem {{charsLeft}} restante(s)",

View File

@@ -783,6 +783,7 @@
"viewing-upcoming-change": "You are looking at a beta page. ",
"go-back-to-learn": "Go back to the stable version of the curriculum.",
"read-database-cert-article": "Please read this forum post before proceeding.",
"enable-cookies": "You must enable third-party cookies before starting.",
"english-only": "The courses in this section are only available in English. We are only able to translate the titles and introductions at the moment, not the lessons themselves."
}
}

View File

@@ -68,8 +68,8 @@
"ask-later": "Запитати пізніше",
"start-coding": "Start coding!",
"go-to-settings": "Go to settings to claim your certification",
"click-start-course": "Click here to start the course",
"click-start-project": "Click here to start the project"
"click-start-course": "Start the course",
"click-start-project": "Start the project"
},
"landing": {
"big-heading-1": "Вчіться програмувати — це безкоштовно.",
@@ -536,7 +536,8 @@
"code-save-error": "An error occurred trying to save your code.",
"code-save-less": "Slow Down! Your code was not saved. Try again in a few seconds.",
"challenge-save-too-big": "Sorry, you cannot save your code. Your code is {{user-size}} bytes. We allow a maximum of {{max-size}} bytes. Please make your code smaller and try again or request assistance on https://forum.freecodecamp.org",
"challenge-submit-too-big": "Sorry, you cannot submit your code. Your code is {{user-size}} bytes. We allow a maximum of {{max-size}} bytes. Please make your code smaller and try again or request assistance on https://forum.freecodecamp.org"
"challenge-submit-too-big": "Sorry, you cannot submit your code. Your code is {{user-size}} bytes. We allow a maximum of {{max-size}} bytes. Please make your code smaller and try again or request assistance on https://forum.freecodecamp.org",
"invalid-update-flag": "You are attempting to access forbidden resources. Please request assistance on https://forum.freecodecamp.org if this is a valid request."
},
"validation": {
"max-characters": "Максимальний розмір — 288 символів, у вас залишилося {{charsLeft}}",

View File

@@ -49,6 +49,7 @@
"@freecodecamp/strip-comments": "3.0.1",
"@loadable/component": "5.15.2",
"@reach/router": "1.3.4",
"@sentry/gatsby": "6.19.6",
"@stripe/react-stripe-js": "1.7.1",
"@stripe/stripe-js": "1.27.0",
"@types/react-scrollable-anchor": "0.6.1",
@@ -132,7 +133,7 @@
"@codesee/babel-plugin-instrument": "0.227.0",
"@codesee/tracker": "0.227.0",
"@testing-library/jest-dom": "5.16.4",
"@testing-library/react": "12.1.4",
"@testing-library/react": "12.1.5",
"autoprefixer": "10.4.4",
"babel-plugin-transform-imports": "2.0.0",
"chokidar": "3.5.3",

View File

@@ -42,6 +42,7 @@ class UserToken extends Component<UserTokenProps> {
bsSize='lg'
bsStyle='danger'
className='btn-info'
data-cy='delete-user-token'
onClick={this.deleteToken}
type='button'
>

View File

@@ -1,5 +1,5 @@
// Package Utilities
import { Grid, Col, Row, Button } from '@freecodecamp/react-bootstrap';
import { Alert, Grid, Col, Row, Button } from '@freecodecamp/react-bootstrap';
import { graphql } from 'gatsby';
import React, { Component } from 'react';
import Helmet from 'react-helmet';
@@ -300,9 +300,14 @@ class ShowCodeAlly extends Component<ShowCodeAllyProps> {
: ''
}`}
>
<Alert id='codeally-cookie-warning' bsStyle='info'>
<p>{t(`intro:misc-text.enable-cookies`)}</p>
</Alert>
<Button
aria-describedby='codeally-cookie-warning'
block={true}
bsStyle='primary'
data-cy='start-codeally'
onClick={tryToShowCodeAlly}
>
{challengeType === challengeTypes.codeAllyCert

View File

@@ -1,7 +1,15 @@
// TODO: integrate with Sentry?
import * as Sentry from '@sentry/gatsby';
import envData from '../../../config/env.json';
const { sentryClientDSN } = envData;
export function reportClientSideError(
e: Error,
message = 'Unhandled error'
): void {
return console.error(`Client: ${message}`, e);
message = sentryClientDSN === null
? 'Unhandled error'
: 'Error sent to Sentry'
): string | void {
return sentryClientDSN === null
? console.error(`Client: ${message}`, e)
: Sentry.captureException(e);
}

View File

@@ -5,8 +5,9 @@ const _ = require('lodash');
const envData = require('../../config/env.json');
const {
getChallengesForLang,
createChallenge,
challengesDir,
generateChallengeCreator,
CHALLENGES_DIR,
META_DIR,
getChallengesDirForLang
} = require('../../curriculum/getChallenges');
@@ -20,22 +21,19 @@ exports.replaceChallengeNode = () => {
const blockNameRe = /\d\d-[-\w]+\/([^/]+)\//;
const posix = path.normalize(filePath).split(path.sep).join(path.posix.sep);
const blockName = posix.match(blockNameRe)[1];
const metaPath = path.resolve(
__dirname,
`../../curriculum/challenges/_meta/${blockName}/meta.json`
);
const metaPath = path.resolve(META_DIR, `/${blockName}/meta.json`);
delete require.cache[require.resolve(metaPath)];
const meta = require(metaPath);
// TODO: reimplement hot-reloading of certifications
return await createChallenge(
challengesDir,
filePath,
curriculumLocale,
meta
);
return await createChallenge(filePath, meta);
};
};
const createChallenge = generateChallengeCreator(
CHALLENGES_DIR,
curriculumLocale
);
exports.buildChallenges = async function buildChallenges() {
const curriculum = await getChallengesForLang(curriculumLocale);
const superBlocks = Object.keys(curriculum);

View File

@@ -31,6 +31,7 @@ const {
PAYPAL_CLIENT_ID: paypalClientId,
PATREON_CLIENT_ID: patreonClientId,
DEPLOYMENT_ENV: deploymentEnv,
SENTRY_CLIENT_DSN: sentryClientDSN,
SHOW_UPCOMING_CHANGES: showUpcomingChanges,
SHOW_NEW_CURRICULUM: showNewCurriculum
} = process.env;
@@ -71,6 +72,10 @@ module.exports = Object.assign(locations, {
!patreonClientId || patreonClientId === 'id_from_patreon_dashboard'
? null
: patreonClientId,
sentryClientDSN:
!sentryClientDSN || sentryClientDSN === 'dsn_from_sentry_dashboard'
? null
: sentryClientDSN,
showUpcomingChanges: showUpcomingChanges === 'true',
showNewCurriculum: showNewCurriculum === 'true'
});

View File

@@ -92,7 +92,7 @@ module.exports = {
},
sentry: {
dns: SENTRY_DSN
dsn: SENTRY_DSN
},
stripe: {

View File

@@ -199,7 +199,7 @@ const locations = [
"button text": ["REPLAY?", "REPLAY?", "REPLAY?"],
"button functions": [restart, restart, restart],
text: "You die. ☠️"
}
},
{
name: "win",
"button text": ["Fight slime", "Fight fanged beast", "Go to town square"],

View File

@@ -21,7 +21,7 @@ For example, if we created a variable `const firstName = "Ada"`, we could find o
# --instructions--
Use the `.length` property to count the number of characters in the `lastName` variable and assign it to `lastNameLength`.
Use the `.length` property to set `lastNameLength` to the number of characters in `lastName`.
# --hints--

View File

@@ -111,7 +111,7 @@ const charRange = (start, end) =>
const evalFormula = x => {
const rangeRegex = /([A-J])([1-9][0-9]?):([A-J])([1-9][0-9]?)/gi;
const rangeFromString = (n1, n2) => range(parseInt(n1), parseInt(n2));
const elemValue = n => (c => document.getElementById(c + n).value));
const elemValue = n => c => document.getElementById(c + n).value;
const fn = elemValue("1");
return fn("A");
};

View File

@@ -90,7 +90,7 @@ const spreadsheetFunctions = {
lasttwo: arr => arr.slice(-2),
even: nums => nums.filter(isEven),
sum: nums => nums.reduce((a, x) => a + x),
has2: arr => arr.includes(2)
has2: arr => arr.includes(2),
nodups: arr => arr.reduce((a, x) => a.includes(x), [])
};

View File

@@ -7,7 +7,7 @@ dashedName: step-28
# --description--
Add a new `#piano` selector within your `@media` query, and set the `width` to `335px`.
Add a new `#piano` selector within your `@media` query, and set the `width` to `358px`.
# --hints--
@@ -19,12 +19,12 @@ const piano = rules?.find(rule => rule.selectorText === '#piano');
assert(piano);
```
Your new `#piano` selector should have a `width` of `335px`.
Your new `#piano` selector should have a `width` of `358px`.
```js
const rules = new __helpers.CSSHelp(document).getRuleListsWithinMedia('(max-width: 768px)');
const piano = rules?.find(rule => rule.selectorText === '#piano');
assert(piano?.style.width === '335px');
assert(piano?.style.width === '358px');
```
# --seed--
@@ -127,7 +127,7 @@ html {
--fcc-editable-region--
@media (max-width: 768px) {
}
--fcc-editable-region--
```

View File

@@ -129,7 +129,7 @@ html {
--fcc-editable-region--
@media (max-width: 768px) {
#piano {
width: 335px;
width: 358px;
}
}
--fcc-editable-region--

View File

@@ -128,7 +128,7 @@ html {
--fcc-editable-region--
@media (max-width: 768px) {
#piano {
width: 335px;
width: 358px;
}
.keys {

View File

@@ -119,7 +119,7 @@ html {
@media (max-width: 768px) {
#piano {
width: 335px;
width: 358px;
}
.keys {

View File

@@ -126,7 +126,7 @@ html {
@media (max-width: 768px) {
#piano {
width: 335px;
width: 358px;
}
.keys {

View File

@@ -146,7 +146,7 @@ html {
@media (max-width: 768px) {
#piano {
width: 335px;
width: 358px;
}
.keys {
@@ -264,7 +264,7 @@ html {
@media (max-width: 768px) {
#piano {
width: 335px;
width: 358px;
}
.keys {

View File

@@ -1,6 +1,6 @@
---
id: 5e46f7e5ac417301a38fb928
title: Mean-Variance-Standard Deviation Calculator
title: Calculadora de varianza, desviación media, y estándar
challengeType: 10
forumTopicId: 462366
dashedName: mean-variance-standard-deviation-calculator
@@ -8,17 +8,64 @@ dashedName: mean-variance-standard-deviation-calculator
# --description--
Create a function that uses Numpy to output the mean, variance, and standard deviation of the rows, columns, and elements in a 3 x 3 matrix.
Estarás [trabajando en este proyecto con nuestro código inicial en Replit](https://replit.com/github/freeCodeCamp/boilerplate-mean-variance-standard-deviation-calculator).
You can access [the full project description and starter code on Replit](https://replit.com/github/freeCodeCamp/boilerplate-mean-variance-standard-deviation-calculator).
Todavía estamos desarrollando la parte interactiva del currículo de Python. Por ahora, aquí hay algunos videos en el canal de YouTube de freeCodeCamp.org que te enseñaran todo lo que necesitas saber para completar este proyecto:
After going to that link, fork the project. Once you complete the project based on the instructions in 'README.md', submit your project link below.
- [Python para todo el mundo Curso en Video](https://www.freecodecamp.org/news/python-for-everybody/) (14 horas)
- [Aprende el Video Curso de Python](https://www.freecodecamp.org/news/learn-python-video-course/) (10 horas)
We are still developing the interactive instructional part of the data analysis with Python curriculum. For now, you will have to use other resources to learn how to pass this challenge.
# --instructions--
Crea una función llamada `calculate()` en `mean_var_std.py` que usa Numpy para producir la media, varianza, desviación estándar, max, min, y suma de las filas, columnas y elementos en una matriz de 3 x 3.
La entrada de la función debe ser una lista que contenga 9 dígitos. La función debe convertir la lista en una matriz numérica de 3 x 3, y luego devolver un diccionario que contenga la media, varianza, desviación estándar, max, min, y suma a lo largo de ambos ejes y para la matriz aplanada.
El diccionario retornado debería seguir este formato:
```py
{
'mean': [axis1, axis2, flattened],
'variance': [axis1, axis2, flattened],
'standard deviation': [axis1, axis2, flattened],
'max': [axis1, axis2, flattened],
'min': [axis1, axis2, flattened],
'sum': [axis1, axis2, flattened]
}
```
Si una lista que contiene menos de 9 elementos es pasada a la función, debería levantar una excepción de `ValueError` con el mensaje: "La lista debe contener nueve números". Los valores en el diccionario devuelto deben ser listas y no matrices Numpy.
Por ejemplo, `calculate([0,1,2,3,4,5,6,7,8])` debe regresar:
```py
{
'mean': [[3.0, 4.0, 5.0], [1.0, 4.0, 7.0], 4.0],
'variance': [[6.0, 6.0, 6.0], [0.6666666666666666, 0.6666666666666666, 0.6666666666666666], 6.666666666666667],
'standard deviation': [[2.449489742783178, 2.449489742783178, 2.449489742783178], [0.816496580927726, 0.816496580927726, 0.816496580927726], 2.581988897471611],
'max': [[6, 7, 8], [2, 5, 8], 8],
'min': [[0, 1, 2], [0, 3, 6], 0],
'sum': [[9, 12, 15], [3, 12, 21], 36]
}
```
Las pruebas unitarias para este proyecto están en `test_module.py`.
## Desarrollo
Durante el desarrollo, puede usar `main.py` para probar su función `calculate()`. Haz clic en el botón "run" y se ejecutará `main.py`.
## Pruebas
Hemos importado las pruebas de `test_module.py` a `main.py` para tu conveniencia. Las pruebas se ejecutarán automáticamente cada vez que pulses el botón "run".
## Envío
Copia el enlace de tu proyecto y envíalo a freeCodeCamp.
# --hints--
It should pass all Python tests.
Debería pasar todas las pruebas de Python.
```js

View File

@@ -1,6 +1,6 @@
---
id: 5e46f7f8ac417301a38fb92a
title: Medical Data Visualizer
title: Visualizador de datos médicos
challengeType: 10
forumTopicId: 462368
dashedName: medical-data-visualizer
@@ -8,17 +8,74 @@ dashedName: medical-data-visualizer
# --description--
In this project, you will visualize and make calculations from medical examination data using matplotlib, seaborn, and pandas.
Estarás [trabajando en este proyecto con nuestro código inicial de Replit](https://replit.com/github/freeCodeCamp/boilerplate-medical-data-visualizer).
You can access [the full project description and starter code on Replit](https://replit.com/github/freeCodeCamp/boilerplate-medical-data-visualizer).
Todavía estamos desarrollando la parte interactiva del currículo de Python. Por ahora, aquí hay algunos vídeos en nuestro canal de YouTube freeCodeCamp.org que te enseñará todo lo que necesitas saber para completer este proyecto:
After going to that link, fork the project. Once you complete the project based on the instructions in 'README.md', submit your project link below.
- [Curso: Python para todos](https://www.freecodecamp.org/news/python-for-everybody/) (14 horas)
- [Curso: Aprende Python](https://www.freecodecamp.org/news/learn-python-video-course/) (10 horas)
We are still developing the interactive instructional part of the data analysis with Python curriculum. For now, you will have to use other resources to learn how to pass this challenge.
# --instructions--
En este proyecto, visualizarás y harás algunos cálculos a partir de datos de exámenes médicos utilizando matplotlib, seabron y pandas. Los valores del conjunto de datos (dataset) se recogieron durante los exámenes médicos.
## Descripción de datos
Las filas del conjunto de datos representan a los pacientes y las columnas representan información como medidas corporales, resultados de varios análisis de sangre y opciones de estilo de vida. Utilizarás el conjunto de datos para explorar la relación entre enfermedades cardiacas, medidas del cuerpo, indicadores sanguíneos y opciones de estilo de vida.
Nombre del archivo: medical_examination.csv
| Característica | Tipo de variable | Variable | Tipo de unidad |
|:-----------------------------------------------------:|:--------------------------:|:----------:|:---------------------------------------------------------------------:|
| Edad | Característica objetivo | edad | int (días) |
| Altura | Característica objetivo | altura | int (cm) |
| Peso | Característica objetivo | peso | float (kg) |
| Sexo | Característica objetivo | género | código de categoría |
| Presión arterial sistólica | Características del examen | ap_hi | int |
| Presión arterial diastólica | Característica del examen | ap_lo | int |
| Colesterol | Característica del examen | colesterol | 1: normal, 2: por encima de lo normal, 3: muy por encima de lo normal |
| Glucosa | Característica del examen | glúcido | 1: normal, 2: por encima de lo normal, 3: muy por encima de lo normal |
| Fumador | Característica subjetiva | humo | binario |
| Consumo de alcohol | Característica subjetiva | alco | binario |
| Actividad física | Característica subjetiva | activo | binario |
| Presencia o ausencia de enfermedades cardiovasculares | Variable objetivo | cardiaco | binario |
## Tareas
Crear un gráfico similar a `ejemplos/Figure_1. ng`, donde mostramos las cifras de resultados buenos y malos para las variables `colesterol`, `gluc`, `alco`, `activo` y `humo` en los pacientes con cardio=1 y cardio=0 en diferentes paneles.
Utiliza los datos para completar las siguientes tareas en `medical_data_visualizer.py`:
- Agrega una columna de `sobrepeso` a los datos. Para determinar si una persona tiene sobrepeso, primero calcule su IMC dividiendo su peso en kilogramos por el cuadrado de su altura en metros. Si ese valor es > 25 entonces la persona tiene sobrepeso. Utilice el valor 0 para NO sobrepeso y el valor 1 para el sobrepeso.
- Normaliza los datos haciendo 0 siempre bueno y 1 siempre malo. Si el valor de `cholesterol` o `gluc` es 1, haga que el valor 0. Si el valor es mayor que 1, haga el valor 1.
- Convierte los datos en formato largo y crea un gráfico que muestre el recuento de valores de las características categóricas usando `catplot()` de seaborn. El conjunto de datos debe dividirse por 'Cardio', así que hay un gráfico por cada valor de `cardio`. El gráfico debería verse como `examples/Figure_1.png`.
- Limpia los datos. Filtrar los siguientes segmentos de pacientes que representan datos incorrectos:
- la presión diastólica es más alta que la máxima (Mantén los datos correctos con `(df['ap_lo'] <= df['ap_hi'])`)
- la altura es menor que el 2.5º percentil (Mantén los datos correctos con `(df['height'] >= df['height'].quantile(0.025))`)
- la altura es superior al 97,5º percentil
- el peso es menor que el 2,5º percentil
- el peso es superior al 97,5º percentil
- Crear una matriz de correlación usando el conjunto de datos. Grafica la matriz de correlación usando la función `heatmap()` de seaborn. Enmascarar el triángulo superior de la matriz. El gráfico debería verse como `examples/Figure_2.png`.
Cada vez que una variable está establecida en `Ninguno`, asegúrese de establecerla en el código correcto.
Las pruebas unitarias están escritas en `test_module.py`.
## Desarrollo
Para el desarrollo, puedes usar `main.py` para probar tus funciones. Haz clic en el botón "run" y se ejecutará `main.py`.
## Pruebas
Hemos importado las pruebas de `test_module.py` a `main.py` para tu conveniencia. Las pruebas se ejecutarán automáticamente cada vez que pulses el botón "run".
## Envío
Copia el enlace de tu proyecto y envíalo a freeCodeCamp.
# --hints--
It should pass all Python tests.
Debería pasar todas las pruebas de Python.
```js

View File

@@ -1,6 +1,6 @@
---
id: 5e46f802ac417301a38fb92b
title: Page View Time Series Visualizer
title: Visualizador de vistas de página en determinados períodos de tiempo
challengeType: 10
forumTopicId: 462369
dashedName: page-view-time-series-visualizer
@@ -8,17 +8,44 @@ dashedName: page-view-time-series-visualizer
# --description--
For this project you will visualize time series data using a line chart, bar chart, and box plots. You will use Pandas, matplotlib, and seaborn to visualize a dataset containing the number of page views each day on the freeCodeCamp.org forum from 2016-05-09 to 2019-12-03. The data visualizations will help you understand the patterns in visits and identify yearly and monthly growth.
Estarás [trabajando en este proyecto con nuestro proyecto inicial de Replit](https://replit.com/github/freeCodeCamp/boilerplate-page-view-time-series-visualizer).
You can access [the full project description and starter code on Replit](https://replit.com/github/freeCodeCamp/boilerplate-page-view-time-series-visualizer).
Todavía estamos desarrollando la parte interactiva del currículo de Python. Por el momento, aquí hay algunos videos en el canal de YouTube de freeCodeCamp.org que te enseñaran todo lo que necesitas saber para completar este proyecto:
After going to that link, fork the project. Once you complete the project based on the instructions in 'README.md', submit your project link below.
- [Curso: Python para todos](https://www.freecodecamp.org/news/python-for-everybody/) (14 horas)
- [Curso: Aprende Python](https://www.freecodecamp.org/news/learn-python-video-course/) (10 horas)
We are still developing the interactive instructional part of the data analysis with Python curriculum. For now, you will have to use other resources to learn how to pass this challenge.
# --instructions--
Para este proyecto, visualizarás los datos de las series temporales utilizando un gráfico de líneas, un gráfico de barras y un gráfico de cajas. Utilizarás Pandas, Matplotlib y Seaborn para visualizar un conjunto de datos que contiene el número de vistas diarias en la página del foro de freeCodeCamp.org del 2016-05-09 al 2019-12-03. Las visualizaciones de datos le ayudarán a entender los patrones en las visitas e identificarán el crecimiento anual y mensual.
Utiliza los datos para completar las siguientes tareas:
- Utiliza Pandas para importar los datos de "fcc-forum-pageviews.csv". Establece como índice la columna "fecha".
- Limpiar los datos filtrando los días en que las vistas de la página se encuentran en el 2,5% superior del conjunto de datos o en el 2,5% inferior del conjunto de datos.
- Crea una función llamada `draw_line_plot` que utilice Matplotlib para dibujar un gráfico de línea similar a "examples/Figure_1.png". El título debe ser "Daily freeCodeCamp Forum Page Views 5/2016-12/2019". La etiqueta en el eje x debe ser "Date" y la etiqueta en el eje y debe ser "Page Views".
- Crea una función llamada `draw_bar_plot` que dibuje un gráfico de barras similar a "examples/Figure_2.png". Debe mostrar el número promedio de vistas diarias de cada mes, agrupadas por año. La leyenda debe mostrar etiquetas mensuales y tener un título de "Months". En el gráfico, la etiqueta en el eje x debe ser "Years" y la etiqueta en el eje y debe ser "Average Page Views".
- Crea una función llamada `draw_box_plot` que utilice Seaborn para dibujar dos diagramas de caja adyacentes similares a "examples/Figure_3.png". Estos diagramas de caja deben mostrar cómo se distribuyen los valores dentro de un año o mes determinado y cómo se compara con el tiempo. El título del primer gráfico debe ser "Year-wise Box Plot (Trend)" y el título del segundo gráfico debe ser "Month-wise Box Plot (Seasonality)". Asegúrese de que las etiquetas del mes en la parte inferior comienzan en "Jan" y los ejes x están etiquetados correctamente. El boilerplate incluye comandos para preparar los datos.
Para cada gráfico, asegúrese de usar una copia de los datos. Las pruebas unitarias están escritas para en `test_module.py`.
El boilerplate también incluye los comandos para guardar y devolver la imagen.
## Desarrollo
Para el desarrollo, puedes usar `main.py` para probar tus funciones. Haz clic en el botón "run" y se ejecutará `main.py`.
## Pruebas
Hemos importado las pruebas de `test_module.py` a `main.py` para tu conveniencia. Las pruebas se ejecutarán automáticamente cada vez que presiones el botón "run".
## Envío
Copia el enlace de tu proyecto y envíalo a freeCodeCamp.
# --hints--
It should pass all Python tests.
Debería pasar todas las pruebas de Python.
```js

View File

@@ -1,8 +1,12 @@
---
id: 5e9a0a8e09c5df3cc3600ed7
title: Copying Arrays Warning
title: Advertencia al copiar arrays
challengeType: 11
videoId: iIoQ0_L0GvA
bilibiliIds:
aid: 633008569
bvid: BV1Bb4y127fb
cid: 409026161
dashedName: copying-arrays-warning
---
@@ -10,7 +14,7 @@ dashedName: copying-arrays-warning
## --text--
What is the value of `a` after running the following code?
¿Cual es el valor de `a` después de ejecutar el siguiente código?
```py
import numpy as np

View File

@@ -1,8 +1,12 @@
---
id: 5e9a0a8e09c5df3cc3600ed6
title: Initialize Array Problem
title: Problema al inicializar el array
challengeType: 11
videoId: 0jGfH8BPfOk
bilibiliIds:
aid: 763027834
bvid: BV1w64y1a7eo
cid: 409025878
dashedName: initialize-array-problem
---
@@ -10,7 +14,7 @@ dashedName: initialize-array-problem
## --text--
What is another way to produce the following array?
¿Cuál es la otra forma de crear el siguiente array?
```py
[[0. 0. 0. 0. 0. 0. 0.]

View File

@@ -1,8 +1,12 @@
---
id: 5e9a0a8e09c5df3cc3600ed5
title: Initializing Different Arrays
title: Inicializando diferentes Arrays
challengeType: 11
videoId: CEykdsKT4U4
bilibiliIds:
aid: 718044756
bvid: BV1MQ4y1k7BB
cid: 409025638
dashedName: initializing-different-arrays
---
@@ -10,7 +14,7 @@ dashedName: initializing-different-arrays
## --text--
What will the following code print?
¿Qué hará el siguiente código?
```py
a = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])

View File

@@ -1,8 +1,12 @@
---
id: 5e9a0a8e09c5df3cc3600eda
title: Loading Data and Advanced Indexing
title: Cargando datos e indexación avanzada
challengeType: 11
videoId: tUdBZ7pF8Jg
bilibiliIds:
aid: 720524642
bvid: BV1xQ4y1r7mu
cid: 409027117
dashedName: loading-data-and-advanced-indexing
---
@@ -10,14 +14,14 @@ dashedName: loading-data-and-advanced-indexing
## --text--
Given a file named `data.txt` with these contents:
Se ha dado un archivo llamado `data.txt` con estos contenidos:
<pre>
29,97,32,100,45
15,88,5,75,22
</pre>
What code would produce the following array?
¿Qué código produciría el siguiente arreglo?
```py
[29. 32. 45. 15. 5. 22.]

View File

@@ -1,8 +1,12 @@
---
id: 5e9a0a8e09c5df3cc3600ed8
title: Mathematics
title: Matemáticas
challengeType: 11
videoId: 7txegvyhtVk
bilibiliIds:
aid: 890533226
bvid: BV1KP4y1h733
cid: 409026503
dashedName: mathematics
---
@@ -10,7 +14,7 @@ dashedName: mathematics
## --text--
What is the value of `b` after running the following code?
¿Cuál es el valor de `b` después de ejecutar el siguiente código?
```py
import numpy as np

View File

@@ -1,8 +1,12 @@
---
id: 5e9a0a8e09c5df3cc3600ed9
title: Reorganizing Arrays
title: Reorganizando arreglos
challengeType: 11
videoId: VNWAQbEM-C8
bilibiliIds:
aid: 548035655
bvid: BV1fq4y1N7aC
cid: 409026755
dashedName: reorganizing-arrays
---
@@ -10,7 +14,7 @@ dashedName: reorganizing-arrays
## --text--
What code would produce the following array?
¿Qué código produciría el siguiente arreglo?
```py
[[1. 1.]

View File

@@ -1,6 +1,6 @@
---
id: 5f1a4ef5d5d6b5ab580fc6ae
title: Build a Celestial Bodies Database
title: Construye una base de datos de cuerpos celestes
challengeType: 13
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-celestial-bodies-database
@@ -9,15 +9,15 @@ dashedName: build-a-celestial-bodies-database
# --description--
This is one of the required projects to earn your certification. For this project, you will build a database of celestial bodies using PostgreSQL.
Este es uno de los proyectos necesarios para obtener su certificación. Para este proyecto, construirá una base de datos de cuerpos celestes usando PostgreSQL.
# --instructions--
**Important:** After you pass all the project tests, save a dump of your database into a `universe.sql` file so you can complete step 2. There will be instructions how to do that within the virtual machine.
**Importante:** Después de pasar todas las pruebas del proyecto, guarde un volcado de su base de datos en un archivo `universe.sql` para que puedas completar el paso 2. Habrá instrucciones de cómo hacerlo dentro de la máquina virtual.
# --notes--
Required files: `universe.sql`
Archivos requeridos: `universe.sql`
# --hints--

View File

@@ -1,6 +1,6 @@
---
id: 602da04c22201c65d2a019f4
title: Build a Number Guessing Game
title: Construye un juego de adivinanzas de números
challengeType: 13
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-number-guessing-game
@@ -9,15 +9,15 @@ dashedName: build-a-number-guessing-game
# --description--
This is one of the required projects to earn your certification. For this project, you will use Bash scripting, PostgreSQL, and Git to create a number guessing game that runs in the terminal and saves user information.
Este es uno de los proyectos requeridos para obtener tu certificación. Para este proyecto, usarás scripts de Bash, PostgreSQL, y Git para crear un juego de adivinanzas de números que se ejecute en la terminal y guarde información del usuario.
# --instructions--
**Important:** After you pass all the project tests, save a dump of your database into a `number_guessers.sql` file, as well as your whole `number_guessing_game` folder, so you can complete step 2. There will be instructions how to do that within the virtual machine.
**Importante:** Después de que pases todas las pruebas del proyecto, guarda un 'dump' de tu base de datos en un archivo `number_guess.sql`, así mismo como también tu archivo `number_guess.sh`, para que puedas completar el paso 2. Habrá instrucciones sobre cómo hacer eso dentro de la máquina virtual.
# --notes--
Required files: `number_guessers.sql`, and the whole `number_guessing_game` folder
Archivos necesarios: `number_guess.sql`, `number_guess.sh`
# --hints--

View File

@@ -1,6 +1,6 @@
---
id: 602d9ff222201c65d2a019f2
title: Build a Periodic Table Database
title: Construir una base de datos de tabla periodica
challengeType: 13
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-periodic-table-database
@@ -9,15 +9,15 @@ dashedName: build-a-periodic-table-database
# --description--
This is one of the required projects to earn your certification. For this project, you will create Bash a script to get information about chemical elements from a periodic table database.
Este es uno de los proyectos necesarios para obtener su certificación. Para este proyecto, crea Bash un script para obtener información sobre elementos químicos de una base de datos de tabla periódica.
# --instructions--
**Important:** After you pass all the project tests, save a dump of your database into a `elements.sql` file, as well as your whole `periodic_table` folder, so you can complete step 2. There will be instructions how to do that within the virtual machine.
**Importante:** Después de pasar todas las pruebas del proyecto, guarde un volcado de su base de datos en un archivo `periodic_table.sql`, así como su archivo `element.sh`, para que pueda completar el paso 2. Habrá instrucciones sobre cómo hacer eso dentro de la máquina virtual.
# --notes--
Required files: `elements.sql`, and the whole `periodic_table` folder
Archivos requeridos: `periodic_table.sql`, `element.sh`
# --hints--

View File

@@ -1,6 +1,6 @@
---
id: 5f87ac112ae598023a42df1a
title: Build a Salon Appointment Scheduler
title: Construye un Planificador de Citas de Salón
challengeType: 13
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-salon-appointment-scheduler
@@ -9,15 +9,15 @@ dashedName: build-a-salon-appointment-scheduler
# --description--
This is one of the required projects to earn your certification. For this project, you will create an interactive Bash program that uses PostgreSQL to track the customers and appointments for your salon.
Este es uno de los proyectos necesarios para obtener su certificación. Para este proyecto, creará un programa Bash interactivo que utilice PostgreSQL para rastrear los clientes y citas de su salón.
# --instructions--
**Important:** After you pass all the project tests, save a dump of your database into a `salon.sql` file, as well as your `salon.sh` file, so you can complete step 2. There will be instructions how to do that within the virtual machine.
**Importante:** Después de pasar todas las pruebas del proyecto, guarde un volcado de su base de datos en un archivo `salon.sql`, así como su archivo `salon.sh`, para que pueda completar el paso 2. Habrá instrucciones sobre cómo hacerlo dentro de la máquina virtual.
# --notes--
Required files: `salon.sql`, `salon.sh`
Archivos requeridos: `salon.sql`, `salon.sh`
# --hints--

View File

@@ -1,6 +1,6 @@
---
id: 5f9771307d4d22b9d2b75a94
title: Build a World Cup Database
title: Construir una base de datos de la Copa Mundial
challengeType: 13
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-world-cup-database
@@ -9,15 +9,15 @@ dashedName: build-a-world-cup-database
# --description--
This is one of the required projects to earn your certification. For this project, you will create a Bash script that enters information from World Cup games into PostgreSQL, then query the database for useful statistics.
Este es uno de los proyectos necesarios para obtener su certificación. Para este proyecto, crearás un script Bash que ingrese información de los juegos de la Copa del Mundo en PostgreSQL, luego consultarás la base de datos para obtener estadísticas útiles.
# --instructions--
**Important:** After you pass all the project tests, save a dump of your database into a `worldcup.sql` file, as well as your `insert_data.sh` and `queries.sh` files, so you can complete step 2. There will be instructions how to do that within the virtual machine.
**Importante:** Después de pasar todas las pruebas del proyecto, guarda un volcado de tu base de datos en un archivo `worldcup.sql`, así como su `insert_data.sh` y `queries.sh`, por lo que puede completar el paso 2. Habrá instrucciones sobre cómo hacerlo dentro de la máquina virtual.
# --notes--
Required files: `worldcup.sql`, `insert_data.sh`, `queries.sh`
Archivos requeridos: `worldcup.sql`, `insert_data.sh`, `queries.sh`
# --hints--

View File

@@ -1,6 +1,6 @@
---
id: 602da0de22201c65d2a019f6
title: Build a Kitty Ipsum Translator
title: Construye un traductor de Kitty Ipsum
challengeType: 12
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-advanced-bash-by-building-a-kitty-ipsum-translator
@@ -9,7 +9,7 @@ dashedName: build-a-kitty-ipsum-translator
# --description--
In this 140 lesson course, you will learn some more complex commands, and the details of how commands work.
En este curso de 140 lecciones, aprenderás algunos comandos más complejos, y los detalles de cómo funcionan los comandos.
# --instructions--

View File

@@ -1,6 +1,6 @@
---
id: 5f5b969a05380d2179fe6e18
title: Build a Bike Rental Shop
title: Construye una tienda de alquiler de bicicletas
challengeType: 12
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-bash-and-sql-by-building-a-bike-rental-shop
@@ -9,7 +9,7 @@ dashedName: build-a-bike-rental-shop
# --description--
In this 210 lesson course, you will build an interactive Bash program that stores rental information for your bike rental shop using PostgreSQL.
En este curso de 210 lecciones, construirás un programa interactivo de Bash que almacena información de alquiler para tu tienda de alquiler de bicicletas usando PostgreSQL.
# --instructions--

View File

@@ -1,6 +1,6 @@
---
id: 5ea8adfab628f68d805bfc5e
title: Build a Boilerplate
title: Construye un Boilerplate
challengeType: 12
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-bash-by-building-a-boilerplate
@@ -9,7 +9,7 @@ dashedName: build-a-boilerplate
# --description--
In this 170 lesson course, you will learn basic commands by creating a website boilerplate using only the command line.
En este curso de 170 lecciones, aprenderá los comandos del terminal creando un boilerplate del sitio web usando sólo la línea de comandos.
# --instructions--

View File

@@ -1,6 +1,6 @@
---
id: 5f5904ac738bc2fa9efecf5a
title: Build Five Programs
title: Construye cinco programas
challengeType: 12
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-bash-scripting-by-building-five-programs
@@ -9,7 +9,7 @@ dashedName: build-five-programs
# --description--
In this 220 lesson course, you will learn more terminal commands and how to use them within Bash scripts by creating five small programs.
En este curso de 220 lecciones, aprenderá más comandos de terminal y cómo usarlos dentro de scripts de Bash creando cinco programas pequeños.
# --instructions--

View File

@@ -1,6 +1,6 @@
---
id: 5fa323cdaf6a73463d590659
title: Build an SQL Reference Object
title: Construir un objeto de referencia SQL
challengeType: 12
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-git-by-building-an-sql-reference-object
@@ -9,7 +9,7 @@ dashedName: build-an-sql-reference-object
# --description--
In this 240 lesson course, you will learn how Git keeps track of your code by creating an object containing commonly used SQL commands.
En este curso de 240 lecciones, aprenderá cómo Git realiza un seguimiento de su código creando un objeto que contiene comandos SQL comúnmente utilizados.
# --instructions--

View File

@@ -1,6 +1,6 @@
---
id: 5f32db63eb37f7e17323f459
title: Build a Castle
title: Construye un castillo
challengeType: 12
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-nano-by-building-a-castle
@@ -9,7 +9,7 @@ dashedName: build-a-castle
# --description--
In this 40 lesson course, you will learn how to edit files in the terminal with Nano while building a castle.
En este curso de 40 lecciones, aprenderás cómo editar archivos en la terminal con Nano mientras construyes un castillo.
# --instructions--

View File

@@ -1,6 +1,6 @@
---
id: 5f2c289f164c29556da632fd
title: Build a Mario Database
title: Construir una base de datos Mario
challengeType: 12
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-relational-databases-by-building-a-mario-database
@@ -9,7 +9,7 @@ dashedName: build-a-mario-database
# --description--
In this 165 lesson course, you will learn the basics of relational databases by creating a PostgreSQL database filled with video game characters.
En este curso de 165 lecciones, aprenderá los fundamentos de una base de datos relacional creando una base de datos PostgreSQL llena de caracteres de videojuego.
# --instructions--

View File

@@ -1,6 +1,6 @@
---
id: 602da0c222201c65d2a019f5
title: "Build a Student Database: Part 1"
title: "Construir una base de datos de estudiantes: Parte 1"
challengeType: 12
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-sql-by-building-a-student-database-part-1
@@ -9,7 +9,7 @@ dashedName: build-a-student-database-part-1
# --description--
In this 140 lesson course, you will create a Bash script that uses SQL to enter information about your computer science students into PostgreSQL.
En este curso de 140 lecciones, creará un script Bash que utilice SQL para introducir información sobre sus estudiantes de informática en PostgreSQL.
# --instructions--

View File

@@ -1,6 +1,6 @@
---
id: 618590adb0730ca724e37672
title: "Build a Student Database: Part 2"
title: "Construir una base de datos de estudiantes: Parte 2"
challengeType: 12
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-sql-by-building-a-student-database-part-2
@@ -9,7 +9,7 @@ dashedName: build-a-student-database-part-2
# --description--
In this 140 lesson course, you will complete your student database while diving deeper into SQL commands.
En este curso de 140 lecciones, completará su base de datos de estudiantes mientras se sumerge más en comandos SQL.
# --instructions--

View File

@@ -8,16 +8,49 @@ dashedName: book-recommendation-engine-using-knn
# --description--
Neste desafio, você criará um algoritmo de recomendação de livros usando os vizinhos K-mais próximos.
Você usará o conjunto de dados do Book-Crossings. Este conjunto de dados contém 1,1 milhão de classificações (na escala de 1-10) de 270.000 livros por 90.000 usuários.
Você pode acessar [as instruções completas do projeto e o código inicial no Google Colaboratory](https://colab.research.google.com/github/freeCodeCamp/boilerplate-book-recommendation-engine/blob/master/fcc_book_recommendation_knn.ipynb).
Você [trabalhará neste projeto com Google Colaboratory](https://colab.research.google.com/github/freeCodeCamp/boilerplate-book-recommendation-engine/blob/master/fcc_book_recommendation_knn.ipynb).
Depois de acessar esse link, crie uma cópia do notebook em sua própria conta ou localmente. Depois que você completar o projeto e que ele passar pelo teste (incluído nesse link), envie o link do projeto abaixo. Se você estiver enviando um link do Google Colaboratory, certifique-se de ativar o compartilhamento de links para "qualquer um que tenha o link".
Ainda estamos desenvolvendo o conteúdo instrucional interativo do currículo de aprendizagem de máquina. Por enquanto, você pode ver os desafios de vídeo desta certificação. Você também pode ter que procurar recursos adicionais de aprendizagem, do mesmo modo que você faria ao trabalhar em um projeto do mundo real.
# --instructions--
Neste desafio, você criará um algoritmo de recomendação de livros usando os **vizinhos K-mais próximos**.
Você usará o [dataset do Book-Crossings](http://www2.informatik.uni-freiburg.de/~cziegler/BX/). Este conjunto de dados contém 1,1 milhão de classificações (na escala de 1-10) de 270.000 livros por 90.000 usuários.
Após importar e limpar os dados, use `NearestNeighbors` de `sklearn.neighbors` para desenvolver um modelo que mostra livros semelhantes a um livro específico. O algoritmo dos vizinhos mais próximos mede a distância para determinar a "aproximação" das instâncias.
Crie uma função chamada `get_recommends` que recebe um título de livro (do dataset) como um argumento e retorna uma lista de 5 livros semelhantes com suas distâncias do argumento do livro.
Este código:
```py
get_recommends("The Queen of the Damned (Vampire Chronicles (Paperback))")
```
deve retornar:
```py
[
'The Queen of the Damned (Vampire Chronicles (Paperback))',
[
['Catch 22', 0.793983519077301],
['The Witching Hour (Lives of the Mayfair Witches)', 0.7448656558990479],
['Interview with the Vampire', 0.7345068454742432],
['The Tale of the Body Thief (Vampire Chronicles (Paperback))', 0.5376338362693787],
['The Vampire Lestat (Vampire Chronicles, Book II)', 0.5178412199020386]
]
]
```
Observe que os dados retornados de `get_recommends()` são uma lista. O primeiro elemento na lista é o título do livro passado para a função. O segundo elemento da lista é uma lista com mais cinco listas. Cada uma das cinco listas contém um livro recomendado e a distância do livro recomendado até o livro passar para a função.
Se você colocar o conjunto de dados em um gráfico (opcional), notará que a maioria dos livros não é classificada com frequência. Para garantir a significância estatística, remova do conjunto de dados usuários com menos de 200 avaliações e livros com menos de 100 avaliações.
As primeiras três células importam bibliotecas de que você pode precisar e os dados a serem utilizados. A célula final é para os testes. Escreva todo o código entre essas células.
# --hints--
Ele deve passar em todos os testes do Python.

View File

@@ -8,14 +8,98 @@ dashedName: cat-and-dog-image-classifier
# --description--
Para este desafio, você usará o TensorFlow 2.0 e o Keras para criar uma rede neural convolucional que classifique corretamente imagens de gatos e cães com, pelo menos, 63% de precisão.
Você pode acessar [as instruções completas do projeto e o código inicial no Google Colaboratory](https://colab.research.google.com/github/freeCodeCamp/boilerplate-cat-and-dog-image-classifier/blob/master/fcc_cat_dog.ipynb).
Você [trabalhará neste projeto com Google Colaboratory](https://colab.research.google.com/github/freeCodeCamp/boilerplate-cat-and-dog-image-classifier/blob/master/fcc_cat_dog.ipynb).
Depois de acessar esse link, crie uma cópia do notebook em sua própria conta ou localmente. Depois que você completar o projeto e que ele passar pelo teste (incluído nesse link), envie o link do projeto abaixo. Se você estiver enviando um link do Google Colaboratory, certifique-se de ativar o compartilhamento de links para "qualquer um que tenha o link".
Ainda estamos desenvolvendo o conteúdo instrucional interativo do currículo de aprendizagem de máquina. Por enquanto, você pode ver os desafios de vídeo desta certificação. Você também pode ter que procurar recursos adicionais de aprendizagem, do mesmo modo que você faria ao trabalhar em um projeto do mundo real.
# --instructions--
Para este desafio, você completará o código para classificar imagens de cães e gatos. Você usará o TensorFlow 2.0 e o Keras para criar uma rede neural convolucional que classifique corretamente imagens de gatos e cães com, pelo menos, 63% de precisão. (Você ganha créditos extras se conseguir 70% de precisão!)
Parte do código é dado a você, mas a outra parte você deve preencher para completar este desafio. Leia a instrução em cada célula de texto para saber o que tem de fazer em cada célula de código.
A primeira célula de código importa as bibliotecas necessárias. A segunda célula de código baixa os dados e define as principais variáveis. A terceira célula é o primeiro lugar onde você escreverá seu próprio código.
A estrutura dos arquivos do conjunto de dados que foram baixados tem essa aparência (você notará que o diretório de testes não tem subdiretórios e que as imagens não estão identificadas):
```py
cats_and_dogs
|__ train:
|______ cats: [cat.0.jpg, cat.1.jpg ...]
|______ dogs: [dog.0.jpg, dog.1.jpg ...]
|__ validation:
|______ cats: [cat.2000.jpg, cat.2001.jpg ...]
|______ dogs: [dog.2000.jpg, dog.2001.jpg ...]
|__ test: [1.jpg, 2.jpg ...]
```
Você pode ajustar epochs e tamanho do lote se quiser, mas não é necessário.
As instruções a seguir correspondem a números de célula específicos, indicados com um comentário no topo da célula (como `# 3`).
## Célula 3
Agora é a sua vez! Defina cada uma das variáveis nessa célula corretamente (elas não devem mais ser iguais a `None`).
Crie geradores de imagem para cada um dos três conjuntos de dados de imagens (treinamento, validação, teste). Use `ImageDataGenerator` para ler/decodificar as imagens e convertê-las em tensores de ponto flutuante. Use o argumento `rescale` (e não há outros argumentos por enquanto) para redimensionar os tensores dos valores entre 0 e 255 para valores entre 0 e 1.
Para as variáveis `*_data_gen`, use o método `flow_from_directory`. Passe o tamanho do lote, diretório, tamanho do destino (`(IMG_HEIGHT, IMG_WIDTH)`), modo de classe e tudo o mais que for necessário. `test_data_gen` será o mais complicado. Para `test_data_gen`, certifique-se de passar `shuffle=False` para o método `flow_from_directory`. Isto garantirá que as previsões finais permaneçam na ordem que o nosso teste espera. Para `test_data_gen` será útil observar a estrutura de diretório.
Após executar o código, a saída deverá ficar assim:
```py
Found 2000 images belonging to 2 classes.
Found 1000 images belonging to 2 classes.
Found 50 images belonging to 1 class.
```
## Célula 4
A função `plotImages` será usada algumas vezes para desenhar imagens. Ela pega um array de imagens e uma lista de probabilidades, embora a lista de probabilidades seja opcional. Este código é dado para você. Se você criou a variável `train_data_gen` corretamente, ao executar essa célula, verá representadas cinco imagens aleatórias de treino.
## Célula 5
Recrie o `train_image_generator` usando o `ImageDataGenerator`.
Como há um pequeno número de exemplos de treinamento, existe o risco de sobreposição. Uma maneira de resolver esse problema é criar mais dados de treinamento a partir dos exemplos existentes usando transformações aleatórias.
Adicione 4 a 6 transformações aleatórias como argumentos para `ImageDataGenerator`. Não se esqueça de redimensioná-la como antes.
## Célula 6
Você não tem que fazer nada para esta célula. `train_data_gen` é criado como antes, mas com o novo `train_image_generator`. Então, uma única imagem é desenhada cinco vezes usando variações diferentes.
## Célula 7
Nesta célula, crie um modelo para a rede neural que produza as probabilidades de classe. Ele deve usar o modelo sequencial do Keras. Isso provavelmente envolverá uma pilha de camadas Conv2D e MaxPooling2D e, em seguida, uma camada totalmente conectada no topo, que é ativada por uma função de ativação de ReLU.
Faça a compilação do modelo passando os argumentos para definir o otimizador e a perda. Inclua também `metrics=['accuracy']` para visualizar a precisão do treinamento e da validação de cada epoch de treinamento.
## Célula 8
Use o método `fit` no seu `model` para treinar a rede. Certifique-se de passar argumentos para `x`, `steps_per_epoch`, `epochs`, `validation_data` e `validation_steps`.
## Célula 9
Execute esta célula para visualizar a precisão e a perda do modelo.
## Célula 10
Agora é hora de usar o nosso modelo para prever se uma nova imagem é um gato ou um cão.
Nesta célula, obtenha a probabilidade de que cada imagem de teste (de `test_data_gen`) seja um cão ou um gato. `probabilities` deve ser uma lista de números inteiros.
Chame a função `plotImages` e passe as imagens de teste e as probabilidades correspondentes a cada imagem de teste.
Depois de executar a célula, você deve ver todas as 50 imagens de teste com um rótulo mostrando a porcentagem de "certeza" de que a imagem é um gato ou um cachorro. A precisão corresponderá à precisão mostrada no gráfico acima (após executar a célula anterior). O aumento do treinamento de imagens poderia levar a uma maior precisão.
## Célula 11
Execute esta célula final para ver se passou no desafio ou se precisa continuar tentando.
# --hints--
Ele deve passar em todos os testes do Python.

View File

@@ -8,16 +8,30 @@ dashedName: linear-regression-health-costs-calculator
# --description--
Neste desafio, você preverá os custos de saúde usando um algoritmo de regressão.
Você recebe um conjunto de dados que contém informações sobre diferentes pessoas, incluindo seus custos de saúde. Use os dados para prever custos de saúde com base em novos dados.
Você pode acessar [as instruções completas do projeto e o código inicial no Google Colaboratory](https://colab.research.google.com/github/freeCodeCamp/boilerplate-linear-regression-health-costs-calculator/blob/master/fcc_predict_health_costs_with_regression.ipynb).
Você [trabalhará neste projeto com Google Colaboratory](https://colab.research.google.com/github/freeCodeCamp/boilerplate-linear-regression-health-costs-calculator/blob/master/fcc_predict_health_costs_with_regression.ipynb).
Depois de acessar esse link, crie uma cópia do notebook em sua própria conta ou localmente. Depois que você completar o projeto e que ele passar pelo teste (incluído nesse link), envie o link do projeto abaixo. Se você estiver enviando um link do Google Colaboratory, certifique-se de ativar o compartilhamento de links para "qualquer um que tenha o link".
Ainda estamos desenvolvendo o conteúdo instrucional interativo do currículo de aprendizagem de máquina. Por enquanto, você pode ver os desafios de vídeo desta certificação. Você também pode ter que procurar recursos adicionais de aprendizagem, do mesmo modo que você faria ao trabalhar em um projeto do mundo real.
# --instructions--
Neste desafio, você preverá os custos de saúde usando um algoritmo de regressão.
Você recebe um conjunto de dados que contém informações sobre diferentes pessoas, incluindo seus custos de saúde. Use os dados para prever custos de saúde com base em novos dados.
As duas primeiras células deste caderno importam bibliotecas e dados.
Certifique-se de converter os dados categorizados em números. Use 80% dos dados como o `train_dataset` e 20% dos dados como o `test_dataset`.
Use `pop` para a coluna "expenses" (despesas) destes conjuntos de dados para criar novos conjuntos de dados chamados `train_labels` e `test_labels`. Use essas etiquetas ao treinar o seu modelo.
Crie um modelo e treine com o `train_dataset`. Execute a célula final neste caderno para verificar o seu modelo. A célula final usará o `test_dataset` não visto para verificar se o modelo generaliza bem.
Para passar no desafio, `model.evaluate` deve retornar um erro médio absoluto de menos de 3500. Isto significa que prevê o custo correto dos cuidados de saúde na faixa de $3500.
A célula final também preverá despesas usando o `test_dataset` e colocará os resultados em gráficos.
# --hints--
Ele deve passar em todos os testes do Python.

View File

@@ -8,14 +8,22 @@ dashedName: neural-network-sms-text-classifier
# --description--
Neste desafio, você precisa criar um modelo de aprendizagem de máquina que classificará as mensagens de SMS como "ham" ou "spam". Uma mensagem de "ham" é uma mensagem normal enviada por um amigo. Uma mensagem de "spam" é um anúncio ou uma mensagem enviada por uma empresa.
Você pode acessar [as instruções completas do projeto e o código inicial no Google Colaboratory](https://colab.research.google.com/github/freeCodeCamp/boilerplate-neural-network-sms-text-classifier/blob/master/fcc_sms_text_classification.ipynb).
Você [trabalhará neste projeto com Google Colaboratory](https://colab.research.google.com/github/freeCodeCamp/boilerplate-neural-network-sms-text-classifier/blob/master/fcc_sms_text_classification.ipynb).
Depois de acessar esse link, crie uma cópia do notebook em sua própria conta ou localmente. Depois que você completar o projeto e que ele passar pelo teste (incluído nesse link), envie o link do projeto abaixo. Se você estiver enviando um link do Google Colaboratory, certifique-se de ativar o compartilhamento de links para "qualquer um que tenha o link".
Ainda estamos desenvolvendo o conteúdo instrucional interativo do currículo de aprendizagem de máquina. Por enquanto, você pode ver os desafios de vídeo desta certificação. Você também pode ter que procurar recursos adicionais de aprendizagem, do mesmo modo que você faria ao trabalhar em um projeto do mundo real.
# --instructions--
Neste desafio, você precisa criar um modelo de aprendizagem de máquina que classificará as mensagens de SMS como "ham" ou "spam". Uma mensagem de "ham" é uma mensagem normal enviada por um amigo. Uma mensagem de "spam" é um anúncio ou uma mensagem enviada por uma empresa.
Você deve criar uma função chamada `predict_message` que recebe uma string de mensagem como argumento e retorna uma lista. O primeiro elemento da lista deve ser um número entre zero e um, que indica a probabilidade de "ham" (0) ou de "spam" (1). O segundo elemento na lista deve ser a palavra "ham" ou "spam", dependendo do que for mais provável.
Para este desafio, você usará o conjunto de dados [SMS Spam Collection](http://www.dt.fee.unicamp.br/~tiago/smsspamcollection/). O conjunto de dados já foi agrupado em dados de treinamento e dados de teste.
As duas primeiras células importam as bibliotecas e dados. A célula final testa seu modelo e função. Adicione o código entre essas células.
# --hints--
Ele deve passar em todos os testes do Python.

View File

@@ -8,14 +8,58 @@ dashedName: rock-paper-scissors
# --description--
Para este desafio, você criará um programa para jogar Pedra, Papel e Tesoura. Um programa que escolhe aleatoriamente geralmente ganha 50% das vezes. Para passar neste desafio, o programa deve jogar partidas contra quatro bots diferentes, ganhando pelo menos 60% dos jogos em cada partida.
Você pode acessar [a descrição completa do projeto e o código inicial no Replit](https://replit.com/github/freeCodeCamp/boilerplate-rock-paper-scissors).
Depois de ir para esse link, faça fork no projeto. Depois que você completar o projeto com base nas instruções do 'README.md', envie o link do seu projeto abaixo.
Você [trabalhará neste projeto com nosso código inicial do Replit](https://replit.com/github/freeCodeCamp/boilerplate-rock-paper-scissors).
Ainda estamos desenvolvendo a parte instrucional interativa do currículo de aprendizagem de máquina. Por enquanto, você terá que usar outros recursos para aprender a vencer este desafio.
# --instructions--
Crie uma função chamada `calculate()` em `mean_var_std.py` que use o Numpy para produzir a média, variância, desvio-padrão, máximo, mínimo e soma das linhas, colunas e elementos em uma matriz de 3 x 3.
A entrada da função deve ser uma lista com 9 algarismos. A função deve converter a lista em um array 3 x 3 do Numpy e, em seguida, retornar um dicionário contendo a média, variância, desvio padrão, máximo, mínimo e soma ao longo de ambos os eixos e para a matriz nivelada.
O dicionário retornado deve seguir esse formato:
```py
{
'mean': [axis1, axis2, flattened],
'variance': [axis1, axis2, flattened],
'standard deviation': [axis1, axis2, flattened],
'max': [axis1, axis2, flattened],
'min': [axis1, axis2, flattened],
'sum': [axis1, axis2, flattened]
}
```
Se uma lista que contiver menos de 9 elementos for passada para a função, ela deve criar uma exceção `ValueError` com a mensagem: "List must contain nine numbers." (A lista deve conter nove números). Os valores do dicionário retornado devem ser listas e não matrizes do Numpy.
Por exemplo, `calculate([0,1,2,3,4,5,6,7,8])` deve retornar:
```py
{
'mean': [[3.0, 4.0, 5.0], [1.0, 4.0, 7.0], 4.0],
'variance': [[6.0, 6.0, 6.0], [0.6666666666666666, 0.6666666666666666, 0.6666666666666666], 6.666666666666667],
'standard deviation': [[2.449489742783178, 2.449489742783178, 2.449489742783178], [0.816496580927726, 0.816496580927726, 0.816496580927726], 2.581988897471611],
'max': [[6, 7, 8], [2, 5, 8], 8],
'min': [[0, 1, 2], [0, 3, 6], 0],
'sum': [[9, 12, 15], [3, 12, 21], 36]
}
```
Os testes unitários para este projeto estão em `test_module.py`.
## Desenvolvimento
Para o desenvolvimento, você pode usar `main.py` para testar sua função `calculate()`. Clique no botão "Run" e `main.py` será executado.
## Testes
Importamos os testes de `test_module.py` em `main.py` para a sua conveniência. Os testes serão executados automaticamente sempre que você clicar no botão "Run".
## Envio
Copie o URL do seu projeto e envie-o abaixo.
# --hints--
Ele deve passar em todos os testes do Python.

View File

@@ -0,0 +1,66 @@
---
id: 613e275749ebd008e74bb62e
title: Passo 8
challengeType: 0
dashedName: step-8
---
# --description--
Uma propriedade útil de um _SVG_ (gráficos vetoriais escaláveis) é o atributo `path` (caminho), que permite que a imagem seja dimensionada sem afetar a resolução da imagem resultante.
Atualmente, o `img` está assumindo que é o tamanho padrão, o que é muito grande. Para arrumar, dimensione a imagem usando o `id` como seletor e defina a largura `width` como `max(100px, 18vw)`.
# --hints--
Você deve usar o seletor `#logo` para direcionar o elemento `img`.
```js
assert.exists(new __helpers.CSSHelp(document).getStyle('#logo'));
```
Você deve dar à `img` uma `width` de `max(100px, 18vw)`.
```js
assert.equal(new __helpers.CSSHelp(document).getStyle('#logo')?.width, 'max(100px, 18vw)');
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="freeCodeCamp Accessibility Quiz practice project" />
<title>Accessibility Quiz</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header>
<img id="logo" src="https://cdn.freecodecamp.org/platform/universal/fcc_primary.svg">
<h1>HTML/CSS Quiz</h1>
<nav></nav>
</header>
<main></main>
</body>
</html>
```
```css
body {
background: #f5f6f7;
color: #1b1b32;
font-family: Helvetica;
margin: 0;
}
--fcc-editable-region--
--fcc-editable-region--
```

View File

@@ -0,0 +1,93 @@
---
id: 6140827cff96e906bd38fc2b
title: Passo 9
challengeType: 0
dashedName: step-9
---
# --description--
Como descrito no [guia de estilo do freeCodeCamp](https://design-style-guide.freecodecamp.org/), o logotipo deve manter uma proporção de `35:4` e um preenchimento (padding) ao redor do texto.
Primeiro, altere a `background-color` para `#0a0a23` para ver o logotipo. Em seguida, use a propriedade `aspect-ratio` para definir a proporção desejada. Por fim, adicione um `padding` de `0.4rem` ao redor.
# --hints--
Você deve dar a `#logo` uma `background-color` de `#0a0a23`.
```js
assert.equal(new __helpers.CSSHelp(document).getStyle('#logo')?.backgroundColor, 'rgb(10, 10, 35)');
```
Você deve usar a propriedade `aspect-ratio`.
```js
assert.notEmpty(new __helpers.CSSHelp(document).getStyle('#logo')?.aspectRatio);
```
Você não deve usar a propriedade `height`.
```js
assert.isEmpty(new __helpers.CSSHelp(document).getStyle('#logo')?.height);
```
Você não deve alterar a propriedade `width`.
```js
assert.equal(new __helpers.CSSHelp(document).getStyle('#logo')?.width, 'max(100px, 18vw)');
```
Você deve dar ao `img` um `aspect-ratio` de `35 / 4`.
```js
assert.equal(new __helpers.CSSHelp(document).getStyle('#logo')?.aspectRatio, '35 / 4');
```
Você deve dar ao `img` um `padding` de `0.4rem`.
```js
assert.equal(new __helpers.CSSHelp(document).getStyle('#logo')?.padding, '0.4rem');
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="freeCodeCamp Accessibility Quiz practice project" />
<title>Accessibility Quiz</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header>
<img id="logo" src="https://cdn.freecodecamp.org/platform/universal/fcc_primary.svg">
<h1>HTML/CSS Quiz</h1>
<nav></nav>
</header>
<main></main>
</body>
</html>
```
```css
body {
background: #f5f6f7;
color: #1b1b32;
font-family: Helvetica;
margin: 0;
}
--fcc-editable-region--
#logo {
width: max(100px, 18vw);
}
--fcc-editable-region--
```

View File

@@ -0,0 +1,89 @@
---
id: 6140883f74224508174794c0
title: Passo 10
challengeType: 0
dashedName: step-10
---
# --description--
Faça com que o `header` ocupe toda a largura de seu contêiner pai, defina sua `height` como `50px` e defina a `background-color< /code> para <code>#1b1b32`. Em seguida, defina o `display` para usar o _Flexbox_.
# --hints--
Você deve usar o seletor de elemento `header`.
```js
assert.exists(new __helpers.CSSHelp(document).getStyle('header'));
```
Você deve dar ao `header` uma `width` de `100%`.
```js
assert.equal(new __helpers.CSSHelp(document).getStyle('header')?.width, '100%');
```
Você deve dar ao `header` uma `height` de `50px`.
```js
assert.equal(new __helpers.CSSHelp(document).getStyle('header')?.height, '50px');
```
Você deve dar ao `header` uma `background-color` de `#1b1b32`.
```js
assert.equal(new __helpers.CSSHelp(document).getStyle('header')?.backgroundColor, 'rgb(27, 27, 50)');
```
Você deve dar ao `header` um `display` de `flex`.
```js
assert.equal(new __helpers.CSSHelp(document).getStyle('header')?.display, 'flex');
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="freeCodeCamp Accessibility Quiz practice project" />
<title>Accessibility Quiz</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header>
<img id="logo" src="https://cdn.freecodecamp.org/platform/universal/fcc_primary.svg">
<h1>HTML/CSS Quiz</h1>
<nav></nav>
</header>
<main></main>
</body>
</html>
```
```css
body {
background: #f5f6f7;
color: #1b1b32;
font-family: Helvetica;
margin: 0;
}
--fcc-editable-region--
--fcc-editable-region--
#logo {
width: max(100px, 18vw);
background-color: #0a0a23;
aspect-ratio: 35 / 4;
padding: 0.4rem;
}
```

View File

@@ -0,0 +1,83 @@
---
id: 61408e4ae3e35d08feb260eb
title: Passo 11
challengeType: 0
dashedName: step-11
---
# --description--
Altere a cor da fonte `h1` para `#f1be32`, e defina o tamanho da fonte para `min(5vw, 1.2em)`.
# --hints--
Você deve usar o seletor de elemento `h1`.
```js
assert.exists(new __helpers.CSSHelp(document).getStyle('h1'));
```
Você deve dar ao `h1` uma `color` com o valor de `#f1be32`.
```js
assert.equal(new __helpers.CSSHelp(document).getStyle('h1')?.color, 'rgb(241, 190, 50)');
```
Você deve dar ao `h1` uma `font-size` de `min(5vw, 1.2em)`.
```js
assert.equal(new __helpers.CSSHelp(document).getStyle('h1')?.fontSize, 'min(5vw, 1.2em)');
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="freeCodeCamp Accessibility Quiz practice project" />
<title>Accessibility Quiz</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header>
<img id="logo" src="https://cdn.freecodecamp.org/platform/universal/fcc_primary.svg">
<h1>HTML/CSS Quiz</h1>
<nav></nav>
</header>
<main></main>
</body>
</html>
```
```css
body {
background: #f5f6f7;
color: #1b1b32;
font-family: Helvetica;
margin: 0;
}
header {
width: 100%;
height: 50px;
background-color: #1b1b32;
display: flex;
}
#logo {
width: max(100px, 18vw);
background-color: #0a0a23;
aspect-ratio: 35 / 4;
padding: 0.4rem;
}
--fcc-editable-region--
--fcc-editable-region--
```

View File

@@ -0,0 +1,112 @@
---
id: 61408f155e798909b6908712
title: Passo 12
challengeType: 0
dashedName: step-12
---
# --description--
Para permitir a navegação na página, adicione uma lista não ordenada com os três itens da lista a seguir:
- `INFO`
- `HTML`
- `CSS`
O texto da lista de itens deve estar envolvido pelas tags de âncora.
# --hints--
Você deve aninhar um elemento `ul` dentro de `nav`.
```js
assert.equal(document.querySelectorAll('nav > ul')?.length, 1);
```
Você deve aninhar três elementos `li` dentro do elemento `ul`.
```js
assert.equal(document.querySelectorAll('nav > ul > li')?.length, 3);
```
Você deve aninhar um elemento `a` dentro de cada elemento `li`.
```js
assert.equal(document.querySelectorAll('nav > ul > li > a')?.length, 3);
```
Você deve dar ao primeiro elemento `a` o texto `INFO`.
```js
assert.equal(document.querySelectorAll('nav > ul > li > a')?.[0]?.textContent, 'INFO');
```
Você deve dar ao segundo elemento `a` o texto `HTML`.
```js
assert.equal(document.querySelectorAll('nav > ul > li > a')?.[1]?.textContent, 'HTML');
```
Você deve dar ao terceiro elemento `a` o texto `CSS`.
```js
assert.equal(document.querySelectorAll('nav > ul > li > a')?.[2]?.textContent, 'CSS');
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="freeCodeCamp Accessibility Quiz practice project" />
<title>Accessibility Quiz</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header>
<img id="logo" src="https://cdn.freecodecamp.org/platform/universal/fcc_primary.svg">
<h1>HTML/CSS Quiz</h1>
--fcc-editable-region--
<nav>
</nav>
--fcc-editable-region--
</header>
<main></main>
</body>
</html>
```
```css
body {
background: #f5f6f7;
color: #1b1b32;
font-family: Helvetica;
margin: 0;
}
header {
width: 100%;
height: 50px;
background-color: #1b1b32;
display: flex;
}
#logo {
width: max(100px, 18vw);
background-color: #0a0a23;
aspect-ratio: 35 / 4;
padding: 0.4rem;
}
h1 {
color: #f1be32;
font-size: min(5vw, 1.2em);
}
```

View File

@@ -0,0 +1,125 @@
---
id: 6141fabd6f75610664e908fd
title: Passo 14
challengeType: 0
dashedName: step-14
---
# --description--
Como este é um quiz, você precisará de um formulário para os usuários enviarem respostas. Você pode separar semanticamente o conteúdo do formulário usando elementos `section`.
Dentro do elemento `main`, crie um formulário com três elementos `section` dentro dele. Em seguida, faça o formulário enviar o conteúdo para `https://freecodecamp.org/practice-project/accessibility-quiz`, usando o método correto.
# --hints--
Você deve criar um elemento `form` dentro do elemento `main`.
```js
assert.exists(document.querySelector('main > form'));
```
Você precisa de três elementos `section` dentro do elemento `form`.
```js
assert.equal(document.querySelectorAll('main > form > section')?.length, 3);
```
Você deve dar ao elemento `form` um atributo `action`.
```js
assert.notEmpty(document.querySelector('main > form')?.action);
```
Você deve dar ao atributo `action` um valor de `https://freecodecamp.org/practice-project/accessibility-quiz`.
```js
assert.equal(document.querySelector('main > form')?.action, 'https://freecodecamp.org/practice-project/accessibility-quiz');
```
Você deve dar ao elemento `form` um atributo `method`.
```js
assert.notEmpty(document.querySelector('main > form')?.method);
```
Você deve dar ao elemento `form` um atributo `method` com o valor de `post`.
```js
assert.equal(document.querySelector('main > form')?.method?.toLowerCase(), 'post');
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="freeCodeCamp Accessibility Quiz practice project" />
<title>Accessibility Quiz</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header>
<img id="logo" src="https://cdn.freecodecamp.org/platform/universal/fcc_primary.svg">
<h1>HTML/CSS Quiz</h1>
<nav>
<ul>
<li><a>INFO</a></li>
<li><a>HTML</a></li>
<li><a>CSS</a></li>
</ul>
</nav>
</header>
--fcc-editable-region--
<main>
</main>
--fcc-editable-region--
</body>
</html>
```
```css
body {
background: #f5f6f7;
color: #1b1b32;
font-family: Helvetica;
margin: 0;
}
header {
width: 100%;
height: 50px;
background-color: #1b1b32;
display: flex;
}
#logo {
width: max(100px, 18vw);
background-color: #0a0a23;
aspect-ratio: 35 / 4;
padding: 0.4rem;
}
h1 {
color: #f1be32;
font-size: min(5vw, 1.2em);
}
nav {
width: 50%;
max-width: 300px;
height: 50px;
}
nav > ul {
display: flex;
justify-content: space-evenly;
}
```

View File

@@ -0,0 +1,111 @@
---
id: 6141fed65b61320743da5894
title: Passo 15
challengeType: 0
dashedName: step-15
---
# --description--
Para aumentar a acessibilidade da página, o atributo `role` pode ser usado para indicar para tecnologias assistivas a finalidade por trás de um elemento na página. O atributo `role` é parte da _Iniciativa de Acessibilidade da Web_ (WAI) e aceita valores pré-definidos.
Dê a cada elemento `section` a função `region`.
# --hints--
Dê ao primeiro elemento `section` a função `region`.
```js
assert.equal(document.querySelectorAll('section')?.[0]?.getAttribute('role'), 'region');
```
Dê ao segundo elemento `section` a função `region`.
```js
assert.equal(document.querySelectorAll('section')?.[1]?.getAttribute('role'), 'region');
```
Dê ao terceiro elemento `section` a função `region`.
```js
assert.equal(document.querySelectorAll('section')?.[2]?.getAttribute('role'), 'region');
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="freeCodeCamp Accessibility Quiz practice project" />
<title>Accessibility Quiz</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header>
<img id="logo" src="https://cdn.freecodecamp.org/platform/universal/fcc_primary.svg">
<h1>HTML/CSS Quiz</h1>
<nav>
<ul>
<li><a>INFO</a></li>
<li><a>HTML</a></li>
<li><a>CSS</a></li>
</ul>
</nav>
</header>
<main>
--fcc-editable-region--
<form method="post" action="https://freecodecamp.org/practice-project/accessibility-quiz">
<section></section>
<section></section>
<section></section>
</form>
--fcc-editable-region--
</main>
</body>
</html>
```
```css
body {
background: #f5f6f7;
color: #1b1b32;
font-family: Helvetica;
margin: 0;
}
header {
width: 100%;
height: 50px;
background-color: #1b1b32;
display: flex;
}
#logo {
width: max(100px, 18vw);
background-color: #0a0a23;
aspect-ratio: 35 / 4;
padding: 0.4rem;
}
h1 {
color: #f1be32;
font-size: min(5vw, 1.2em);
}
nav {
width: 50%;
max-width: 300px;
height: 50px;
}
nav > ul {
display: flex;
justify-content: space-evenly;
}
```

View File

@@ -0,0 +1,171 @@
---
id: 614202874ca576084fca625f
title: Passo 16
challengeType: 0
dashedName: step-16
---
# --description--
Cada função `region` requer um rótulo visível, que deve ser referenciado pelo atributo `aria-labelledby`.
Para os elementos `section`, forneça os seguintes atributos `aria-labelledby`:
- `student-info`
- `html-questions`
- `css-questions`
Então, dentro de cada elemento `section`, aninhe um elemento `h2` com um `id` que corresponda ao atributo `aria-labelledby` correspondente. Dê a cada `h2` conteúdo de texto adequado.
# --hints--
Você deve dar ao primeiro elemento `section` um atributo `aria-labelledby` de `student-info`.
```js
assert.equal(document.querySelectorAll('section')?.[0]?.getAttribute('aria-labelledby'), 'student-info');
```
Você deve dar ao segundo elemento `section` um atributo `aria-labelledby` de `html-questions`.
```js
assert.equal(document.querySelectorAll('section')?.[1]?.getAttribute('aria-labelledby'), 'html-questions');
```
Você deve dar ao terceiro elemento `section` um atributo `aria-labelledby` de `css-questions`.
```js
assert.equal(document.querySelectorAll('section')?.[2]?.getAttribute('aria-labelledby'), 'css-questions');
```
Você deve aninhar um elemento `h2` dentro do primeiro elemento `section`.
```js
assert.equal(document.querySelectorAll('section')?.[0]?.querySelectorAll('h2')?.length, 1);
```
Você deve aninhar um elemento `h2` dentro do segundo elemento `section`.
```js
assert.equal(document.querySelectorAll('section')?.[1]?.querySelectorAll('h2')?.length, 1);
```
Você deve aninhar um elemento `h2` dentro do terceiro elemento `section`.
```js
assert.equal(document.querySelectorAll('section')?.[2]?.querySelectorAll('h2')?.length, 1);
```
Você deve dar ao primeiro elemento `h2` um atributo `id` de `student-info`.
```js
assert.equal(document.querySelectorAll('h2')?.[0]?.id, 'student-info');
```
Você deve dar ao segundo elemento `h2` um atributo `id` de `html-questions`.
```js
assert.equal(document.querySelectorAll('h2')?.[1]?.id, 'html-questions');
```
Você deve dar ao terceiro elemento `h2` um atributo `id` de `css-questions`.
```js
assert.equal(document.querySelectorAll('h2')?.[2]?.id, 'css-questions');
```
Você deve dar ao primeiro elemento `h2` um conteúdo de texto adequado. _Dica: eu teria escolhido `Student Info`_
```js
assert.isAtLeast(document.querySelectorAll('h2')?.[0]?.textContent?.length, 1);
```
Você deve fornecer ao segundo elemento `h2` um conteúdo de texto adequado. _Dica: eu teria escolhido `HTML`_
```js
assert.isAtLeast(document.querySelectorAll('h2')?.[1]?.textContent?.length, 1);
```
Você deve fornecer ao terceiro elemento `h2` um conteúdo de texto adequado. _Dica: eu teria escolhido `CSS`_
```js
assert.isAtLeast(document.querySelectorAll('h2')?.[2]?.textContent?.length, 1);
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="freeCodeCamp Accessibility Quiz practice project" />
<title>Accessibility Quiz</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header>
<img id="logo" src="https://cdn.freecodecamp.org/platform/universal/fcc_primary.svg">
<h1>HTML/CSS Quiz</h1>
<nav>
<ul>
<li><a>INFO</a></li>
<li><a>HTML</a></li>
<li><a>CSS</a></li>
</ul>
</nav>
</header>
<main>
--fcc-editable-region--
<form method="post" action="https://freecodecamp.org/practice-project/accessibility-quiz">
<section role="region"></section>
<section role="region"></section>
<section role="region"></section>
</form>
--fcc-editable-region--
</main>
</body>
</html>
```
```css
body {
background: #f5f6f7;
color: #1b1b32;
font-family: Helvetica;
margin: 0;
}
header {
width: 100%;
height: 50px;
background-color: #1b1b32;
display: flex;
}
#logo {
width: max(100px, 18vw);
background-color: #0a0a23;
aspect-ratio: 35 / 4;
padding: 0.4rem;
}
h1 {
color: #f1be32;
font-size: min(5vw, 1.2em);
}
nav {
width: 50%;
max-width: 300px;
height: 50px;
}
nav > ul {
display: flex;
justify-content: space-evenly;
}
```

View File

@@ -0,0 +1,140 @@
---
id: 614206033d366c090ca7dd42
title: Passo 17
challengeType: 0
dashedName: step-17
---
# --description--
O tipo de letra desempenha um papel importante na acessibilidade de uma página. Algumas fontes são mais fáceis de ler do que outras. Isso é especialmente verdadeiro em telas de baixa resolução.
Altere a fonte dos elementos `h1` e `h2` para `Verdana` e use outra fonte segura para a Web na família sans-serif como substituto.
Além disso, adicione um `border-bottom` de `4px solid #dfdfe2` aos elementos `h2` para tornar as seções distintas.
# --hints--
Você deve usar um seletor de elementos múltiplos para direcionar os elementos `h1` e `h2`.
```js
const gs = (s) => new __helpers.CSSHelp(document).getStyle(s);
assert.exists(gs('h1, h2') || gs('h2, h1'));
```
Você deve definir o primeiro valor da propriedade `font-family` para `Verdana`.
```js
const gs = (s) => new __helpers.CSSHelp(document).getStyle(s);
const style = gs('h1, h2') || gs('h2, h1');
assert.include(style?.fontFamily, 'Verdana');
```
Você deve definir o segundo valor da propriedade `font-family` para outra fonte sans-serif, fonte segura da web. _Dica: eu escolheria Tahoma_.
```js
// Acceptable fonts: Arial, sans-serif, Helvetica, Tahoma, Trebuchet MS.
const gs = (s) => new __helpers.CSSHelp(document).getStyle(s);
const style = gs('h1, h2') || gs('h2, h1');
assert.match(style?.fontFamily, /(Tahoma)|(Arial)|(sans-serif)|(Helvetica)|(Trebuchet MS)/);
```
Você deve usar um seletor de elemento `h2` para direcionar os elementos `h2`.
```js
assert.exists(new __helpers.CSSHelp(document).getStyle('h2'));
```
Você deve dar a `h2` uma propriedade `border-bottom` de `4px solid #dfdfe2`.
```js
assert.equal(new __helpers.CSSHelp(document).getStyle('h2')?.borderBottom, '4px solid rgb(223, 223, 226)');
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="freeCodeCamp Accessibility Quiz practice project" />
<title>Accessibility Quiz</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header>
<img id="logo" src="https://cdn.freecodecamp.org/platform/universal/fcc_primary.svg">
<h1>HTML/CSS Quiz</h1>
<nav>
<ul>
<li><a>INFO</a></li>
<li><a>HTML</a></li>
<li><a>CSS</a></li>
</ul>
</nav>
</header>
<main>
<form method="post" action="https://freecodecamp.org/practice-project/accessibility-quiz">
<section role="region" aria-labelledby="student-info">
<h2 id="student-info">Student Info</h2>
</section>
<section role="region" aria-labelledby="html-questions">
<h2 id="html-questions">HTML</h2>
</section>
<section role="region" aria-labelledby="css-questions">
<h2 id="css-questions">CSS</h2>
</section>
</form>
</main>
</body>
</html>
```
```css
body {
background: #f5f6f7;
color: #1b1b32;
font-family: Helvetica;
margin: 0;
}
header {
width: 100%;
height: 50px;
background-color: #1b1b32;
display: flex;
}
#logo {
width: max(100px, 18vw);
background-color: #0a0a23;
aspect-ratio: 35 / 4;
padding: 0.4rem;
}
h1 {
color: #f1be32;
font-size: min(5vw, 1.2em);
}
nav {
width: 50%;
max-width: 300px;
height: 50px;
}
nav > ul {
display: flex;
justify-content: space-evenly;
}
--fcc-editable-region--
--fcc-editable-region--
```

View File

@@ -0,0 +1,125 @@
---
id: 61435e3c0679a306c20f1acc
title: Passo 18
challengeType: 0
dashedName: step-18
---
# --description--
Para poder navegar na página, dê a cada elemento âncora um `href` correspondente ao elemento `id` dos elementos `h2`.
# --hints--
Você deve dar ao primeiro elemento `a` um `href` de `#student-info`.
```js
assert.equal(document.querySelectorAll('a')?.[0]?.getAttribute('href'), '#student-info');
```
Você deve dar ao segundo elemento `a` um `href` de `#html-questions`.
```js
assert.equal(document.querySelectorAll('a')?.[1]?.getAttribute('href'), '#html-questions');
```
Você deve dar ao terceiro elemento `a` um `href` de `#css-questions`.
```js
assert.equal(document.querySelectorAll('a')?.[2]?.getAttribute('href'), '#css-questions');
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="freeCodeCamp Accessibility Quiz practice project" />
<title>Accessibility Quiz</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header>
<img id="logo" src="https://cdn.freecodecamp.org/platform/universal/fcc_primary.svg">
<h1>HTML/CSS Quiz</h1>
<nav>
--fcc-editable-region--
<ul>
<li><a>INFO</a></li>
<li><a>HTML</a></li>
<li><a>CSS</a></li>
</ul>
--fcc-editable-region--
</nav>
</header>
<main>
<form method="post" action="https://freecodecamp.org/practice-project/accessibility-quiz">
<section role="region" aria-labelledby="student-info">
<h2 id="student-info">Student Info</h2>
</section>
<section role="region" aria-labelledby="html-questions">
<h2 id="html-questions">HTML</h2>
</section>
<section role="region" aria-labelledby="css-questions">
<h2 id="css-questions">CSS</h2>
</section>
</form>
</main>
</body>
</html>
```
```css
body {
background: #f5f6f7;
color: #1b1b32;
font-family: Helvetica;
margin: 0;
}
header {
width: 100%;
height: 50px;
background-color: #1b1b32;
display: flex;
}
#logo {
width: max(100px, 18vw);
background-color: #0a0a23;
aspect-ratio: 35 / 4;
padding: 0.4rem;
}
h1 {
color: #f1be32;
font-size: min(5vw, 1.2em);
}
nav {
width: 50%;
max-width: 300px;
height: 50px;
}
nav > ul {
display: flex;
justify-content: space-evenly;
}
h1,
h2 {
font-family: Verdana, Tahoma;
}
h2 {
border-bottom: 4px solid #dfdfe2;
}
```

View File

@@ -0,0 +1,173 @@
---
id: 6143610161323a081b249c19
title: Passo 19
challengeType: 0
dashedName: step-19
---
# --description--
Preenchendo o conteúdo do quiz, abaixo de `#student-info`, adicione três elementos `div` com uma `class` de `info`.
Em seguida, dentro de cada `div` aninhe um elemento `label` e um elemento `input`.
# --hints--
Você deve aninhar três elementos `div` abaixo do elemento `h2#student-info`.
```js
assert.equal(document.querySelectorAll('h2#student-info ~ div')?.length, 3);
```
Você deve dar ao primeiro `div` uma `class` de `info`.
```js
assert.equal(document.querySelectorAll('h2#student-info ~ div')?.[0]?.className, 'info');
```
Você deve dar ao segundo `div` uma `class` de `info`.
```js
assert.equal(document.querySelectorAll('h2#student-info ~ div')?.[1]?.className, 'info');
```
Você deve dar ao terceiro `div` uma `class` de `info`.
```js
assert.equal(document.querySelectorAll('h2#student-info ~ div')?.[2]?.className, 'info');
```
Você deve aninhar um elemento `label` dentro do primeiro `div`.
```js
assert.equal(document.querySelectorAll('h2#student-info ~ div')?.[0]?.querySelectorAll('label')?.length, 1);
```
Você deve aninhar um elemento `input` no primeiro `div`, após o `label`.
```js
assert.equal(document.querySelectorAll('h2#student-info ~ div')?.[0]?.querySelectorAll('input')?.length, 1);
assert.exists(document.querySelectorAll('h2#student-info ~ div')?.[0]?.querySelector('label + input'));
```
Você deve aninhar um elemento `label` dentro do segundo `div`.
```js
assert.equal(document.querySelectorAll('h2#student-info ~ div')?.[1]?.querySelectorAll('label')?.length, 1);
```
Você deve aninhar um elemento `input` dentro do segundo `div`, após o `label`.
```js
assert.equal(document.querySelectorAll('h2#student-info ~ div')?.[1]?.querySelectorAll('input')?.length, 1);
assert.exists(document.querySelectorAll('h2#student-info ~ div')?.[1]?.querySelector('label + input'));
```
Você deve aninhar um elemento `label` dentro do terceiro `div`.
```js
assert.equal(document.querySelectorAll('h2#student-info ~ div')?.[2]?.querySelectorAll('label')?.length, 1);
```
Você deve aninhar um elemento `input` dentro do terceiro `div`, após o `label`.
```js
assert.equal(document.querySelectorAll('h2#student-info ~ div')?.[2]?.querySelectorAll('input')?.length, 1);
assert.exists(document.querySelectorAll('h2#student-info ~ div')?.[2]?.querySelector('label + input'));
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="freeCodeCamp Accessibility Quiz practice project" />
<title>Accessibility Quiz</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header>
<img id="logo" src="https://cdn.freecodecamp.org/platform/universal/fcc_primary.svg">
<h1>HTML/CSS Quiz</h1>
<nav>
<ul>
<li><a href="#student-info">INFO</a></li>
<li><a href="#html-questions">HTML</a></li>
<li><a href="#css-questions">CSS</a></li>
</ul>
</nav>
</header>
<main>
<form method="post" action="https://freecodecamp.org/practice-project/accessibility-quiz">
--fcc-editable-region--
<section role="region" aria-labelledby="student-info">
<h2 id="student-info">Student Info</h2>
</section>
--fcc-editable-region--
<section role="region" aria-labelledby="html-questions">
<h2 id="html-questions">HTML</h2>
</section>
<section role="region" aria-labelledby="css-questions">
<h2 id="css-questions">CSS</h2>
</section>
</form>
</main>
</body>
</html>
```
```css
body {
background: #f5f6f7;
color: #1b1b32;
font-family: Helvetica;
margin: 0;
}
header {
width: 100%;
height: 50px;
background-color: #1b1b32;
display: flex;
}
#logo {
width: max(100px, 18vw);
background-color: #0a0a23;
aspect-ratio: 35 / 4;
padding: 0.4rem;
}
h1 {
color: #f1be32;
font-size: min(5vw, 1.2em);
}
nav {
width: 50%;
max-width: 300px;
height: 50px;
}
nav > ul {
display: flex;
justify-content: space-evenly;
}
h1,
h2 {
font-family: Verdana, Tahoma;
}
h2 {
border-bottom: 4px solid #dfdfe2;
}
```

View File

@@ -0,0 +1,195 @@
---
id: 6143639d5eddc7094161648c
title: Passo 20
challengeType: 0
dashedName: step-20
---
# --description--
É importante vincular cada `input` ao elemento `label` correspondente. Isso fornece aos usuários de tecnologia assistiva uma referência visual para a entrada.
Isso é feito dando ao `label` um atributo `for`, que contém o `id` do `input`.
Esta seção terá o nome do aluno, endereço de e-mail e data de nascimento. Dê aos elementos `label` apropriados `for` atributos, bem como conteúdo de texto. Em seguida, vincule os elementos `input` aos elementos `label` correspondentes.
# --hints--
Você deve dar ao primeiro elemento `label` um atributo `for` apropriado.
```js
assert.isAtLeast(document.querySelectorAll('label')?.[0]?.htmlFor?.length, 1);
```
Você deve dar ao segundo elemento `label` um atributo `for` apropriado.
```js
assert.isAtLeast(document.querySelectorAll('label')?.[1]?.htmlFor?.length, 1);
```
Você deve dar ao terceiro elemento `label` um atributo `for` apropriado.
```js
assert.isAtLeast(document.querySelectorAll('label')?.[2]?.htmlFor?.length, 1);
```
Você deve dar ao primeiro elemento `label` um conteúdo de texto apropriado.
```js
assert.isAtLeast(document.querySelectorAll('label')?.[0]?.textContent?.length, 1);
```
Você deve dar ao segundo elemento `label` um conteúdo de texto apropriado.
```js
assert.isAtLeast(document.querySelectorAll('label')?.[1]?.textContent?.length, 1);
```
Você deve dar ao terceiro elemento `label` um conteúdo de texto apropriado.
```js
assert.isAtLeast(document.querySelectorAll('label')?.[2]?.textContent?.length, 1);
```
Você deve dar ao primeiro elemento `input` um atributo `id` que corresponda ao atributo `for` do primeiro `label`.
```js
assert.equal(document.querySelectorAll('input')?.[0]?.id, document.querySelectorAll('label')?.[0]?.htmlFor);
```
Você deve dar ao segundo elemento `input` um atributo `id` que corresponda ao atributo `for` do segundo `label`.
```js
assert.equal(document.querySelectorAll('input')?.[1]?.id, document.querySelectorAll('label')?.[1]?.htmlFor);
```
Você deve dar ao terceiro elemento `input` um atributo `id` que corresponda ao atributo `for` do terceiro `label`.
```js
assert.equal(document.querySelectorAll('input')?.[2]?.id, document.querySelectorAll('label')?.[2]?.htmlFor);
```
Você não deve usar o mesmo atributo `id` para mais de um elemento `input`.
```js
const id = (n) => document.querySelectorAll('input')?.[n]?.id;
assert.notEqual(id(0), id(1));
assert.notEqual(id(0), id(2));
assert.notEqual(id(1), id(2));
```
Você não deve usar o mesmo atributo `for` para mais de um elemento `label`.
```js
const htmlFor = (n) => document.querySelectorAll('label')?.[n]?.htmlFor;
assert.notEqual(htmlFor(0), htmlFor(1));
assert.notEqual(htmlFor(0), htmlFor(2));
assert.notEqual(htmlFor(1), htmlFor(2));
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="freeCodeCamp Accessibility Quiz practice project" />
<title>Accessibility Quiz</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header>
<img id="logo" src="https://cdn.freecodecamp.org/platform/universal/fcc_primary.svg">
<h1>HTML/CSS Quiz</h1>
<nav>
<ul>
<li><a href="#student-info">INFO</a></li>
<li><a href="#html-questions">HTML</a></li>
<li><a href="#css-questions">CSS</a></li>
</ul>
</nav>
</header>
<main>
<form method="post" action="https://freecodecamp.org/practice-project/accessibility-quiz">
--fcc-editable-region--
<section role="region" aria-labelledby="student-info">
<h2 id="student-info">Student Info</h2>
<div class="info">
<label></label>
<input />
</div>
<div class="info">
<label></label>
<input />
</div>
<div class="info">
<label></label>
<input />
</div>
</section>
--fcc-editable-region--
<section role="region" aria-labelledby="html-questions">
<h2 id="html-questions">HTML</h2>
</section>
<section role="region" aria-labelledby="css-questions">
<h2 id="css-questions">CSS</h2>
</section>
</form>
</main>
</body>
</html>
```
```css
body {
background: #f5f6f7;
color: #1b1b32;
font-family: Helvetica;
margin: 0;
}
header {
width: 100%;
height: 50px;
background-color: #1b1b32;
display: flex;
}
#logo {
width: max(100px, 18vw);
background-color: #0a0a23;
aspect-ratio: 35 / 4;
padding: 0.4rem;
}
h1 {
color: #f1be32;
font-size: min(5vw, 1.2em);
}
nav {
width: 50%;
max-width: 300px;
height: 50px;
}
nav > ul {
display: flex;
justify-content: space-evenly;
}
h1,
h2 {
font-family: Verdana, Tahoma;
}
h2 {
border-bottom: 4px solid #dfdfe2;
}
```

View File

@@ -0,0 +1,161 @@
---
id: 6143908b6aafb00a659ca189
title: Passo 21
challengeType: 0
dashedName: step-21
---
# --description--
Tendo em mente as práticas recomendadas para entradas de formulário, dê a cada `input` um atributo `type` e `name` apropriado. Em seguida, dê ao primeiro `input` um atributo `placeholder`.
# --hints--
Você deve dar ao primeiro `input` um `type` de `text`.
```js
assert.equal(document.querySelectorAll('input')?.[0]?.type, 'text');
```
Você deve dar ao segundo `input` um `type` de `email`.
```js
assert.equal(document.querySelectorAll('input')?.[1]?.type, 'email');
```
Você deve dar ao terceiro `input` um `type` de `date`.
```js
assert.equal(document.querySelectorAll('input')?.[2]?.type, 'date');
```
Você deve dar ao primeiro `input` um atributo `name` apropriado.
```js
assert.isAtLeast(document.querySelectorAll('input')?.[0]?.name?.length, 1);
```
Você deve dar ao segundo `input` um atributo `name` apropriado.
```js
assert.isAtLeast(document.querySelectorAll('input')?.[1]?.name?.length, 1);
```
Você deve dar ao terceiro `input` um atributo `name` apropriado.
```js
assert.isAtLeast(document.querySelectorAll('input')?.[2]?.name?.length, 1);
```
Você deve dar ao primeiro `input` um atributo `placeholder`.
```js
assert.notEmpty(document.querySelectorAll('input')?.[0]?.placeholder);
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="freeCodeCamp Accessibility Quiz practice project" />
<title>Accessibility Quiz</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header>
<img id="logo" src="https://cdn.freecodecamp.org/platform/universal/fcc_primary.svg">
<h1>HTML/CSS Quiz</h1>
<nav>
<ul>
<li><a href="#student-info">INFO</a></li>
<li><a href="#html-questions">HTML</a></li>
<li><a href="#css-questions">CSS</a></li>
</ul>
</nav>
</header>
<main>
<form method="post" action="https://freecodecamp.org/practice-project/accessibility-quiz">
--fcc-editable-region--
<section role="region" aria-labelledby="student-info">
<h2 id="student-info">Student Info</h2>
<div class="info">
<label for="student-name">Name:</label>
<input id="student-name" />
</div>
<div class="info">
<label for="student-email">Email:</label>
<input id="student-email" />
</div>
<div class="info">
<label for="birth-date">D.O.B.:</label>
<input id="birth-date" />
</div>
</section>
--fcc-editable-region--
<section role="region" aria-labelledby="html-questions">
<h2 id="html-questions">HTML</h2>
</section>
<section role="region" aria-labelledby="css-questions">
<h2 id="css-questions">CSS</h2>
</section>
</form>
</main>
</body>
</html>
```
```css
body {
background: #f5f6f7;
color: #1b1b32;
font-family: Helvetica;
margin: 0;
}
header {
width: 100%;
height: 50px;
background-color: #1b1b32;
display: flex;
}
#logo {
width: max(100px, 18vw);
background-color: #0a0a23;
aspect-ratio: 35 / 4;
padding: 0.4rem;
}
h1 {
color: #f1be32;
font-size: min(5vw, 1.2em);
}
nav {
width: 50%;
max-width: 300px;
height: 50px;
}
nav > ul {
display: flex;
justify-content: space-evenly;
}
h1,
h2 {
font-family: Verdana, Tahoma;
}
h2 {
border-bottom: 4px solid #dfdfe2;
}
```

View File

@@ -0,0 +1,127 @@
---
id: 6143920c8eafb00b735746ce
title: Passo 22
challengeType: 0
dashedName: step-22
---
# --description--
Mesmo que você tenha adicionado um `placeholder` ao primeiro elemento `input` na lição anterior, esta não é uma prática recomendada para acessibilidade. Com muita frequência, os usuários confundem o texto do espaço reservado com um valor de entrada real - eles pensam que já existe um valor na entrada.
Remova o texto do espaço reservado do primeiro elemento `input`, contando com o `label` como a melhor prática.
# --hints--
Você deve remover o atributo `placeholder` do primeiro elemento `input`.
```js
assert.isEmpty(document.querySelectorAll('input')?.[0]?.placeholder);
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="freeCodeCamp Accessibility Quiz practice project" />
<title>Accessibility Quiz</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header>
<img id="logo" src="https://cdn.freecodecamp.org/platform/universal/fcc_primary.svg">
<h1>HTML/CSS Quiz</h1>
<nav>
<ul>
<li><a href="#student-info">INFO</a></li>
<li><a href="#html-questions">HTML</a></li>
<li><a href="#css-questions">CSS</a></li>
</ul>
</nav>
</header>
<main>
<form method="post" action="https://freecodecamp.org/practice-project/accessibility-quiz">
<section role="region" aria-labelledby="student-info">
<h2 id="student-info">Student Info</h2>
--fcc-editable-region--
<div class="info">
<label for="student-name">Name:</label>
<input type="text" name="student-name" id="student-name" placeholder="e.g. Quincy Larson" />
</div>
--fcc-editable-region--
<div class="info">
<label for="student-email">Email:</label>
<input type="email" name="student-email" id="student-email" />
</div>
<div class="info">
<label for="birth-date">D.O.B.:</label>
<input type="date" name="birth-date" id="birth-date" />
</div>
</section>
<section role="region" aria-labelledby="html-questions">
<h2 id="html-questions">HTML</h2>
</section>
<section role="region" aria-labelledby="css-questions">
<h2 id="css-questions">CSS</h2>
</section>
</form>
</main>
</body>
</html>
```
```css
body {
background: #f5f6f7;
color: #1b1b32;
font-family: Helvetica;
margin: 0;
}
header {
width: 100%;
height: 50px;
background-color: #1b1b32;
display: flex;
}
#logo {
width: max(100px, 18vw);
background-color: #0a0a23;
aspect-ratio: 35 / 4;
padding: 0.4rem;
}
h1 {
color: #f1be32;
font-size: min(5vw, 1.2em);
}
nav {
width: 50%;
max-width: 300px;
height: 50px;
}
nav > ul {
display: flex;
justify-content: space-evenly;
}
h1,
h2 {
font-family: Verdana, Tahoma;
}
h2 {
border-bottom: 4px solid #dfdfe2;
}
```

View File

@@ -0,0 +1,139 @@
---
id: 6143931a113bb80c45546287
title: Passo 23
challengeType: 0
dashedName: step-23
---
# --description--
Indiscutivelmente, `D.O.B.` não é suficientemente descritivo. Isto é especialmente verdadeiro para usuários com deficiência visual. Uma maneira de contornar esse problema, sem precisar adicionar texto visível à etiqueta, é adicionar texto que apenas um leitor de tela possa ler.
Anexe um elemento `span` com uma classe de `sr-only` ao conteúdo de texto atual do terceiro elemento `label`.
# --hints--
Você deve adicionar um elemento `span` dentro do terceiro elemento `label`.
```js
assert.exists(document.querySelector('.info:nth-of-type(3) > label > span'));
```
Você deve dar ao elemento `span` uma classe de `sr-only`.
```js
assert.equal(document.querySelector('.info:nth-of-type(3) > label > span')?.className, 'sr-only');
```
Você deve colocar o `span` após o conteúdo do texto `D.O.B.`.
```js
assert.match(document.querySelector('.info:nth-of-type(3) > label')?.innerHTML, /D\.O\.B\.<span/);
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="freeCodeCamp Accessibility Quiz practice project" />
<title>Accessibility Quiz</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header>
<img id="logo" src="https://cdn.freecodecamp.org/platform/universal/fcc_primary.svg">
<h1>HTML/CSS Quiz</h1>
<nav>
<ul>
<li><a href="#student-info">INFO</a></li>
<li><a href="#html-questions">HTML</a></li>
<li><a href="#css-questions">CSS</a></li>
</ul>
</nav>
</header>
<main>
<form method="post" action="https://freecodecamp.org/practice-project/accessibility-quiz">
<section role="region" aria-labelledby="student-info">
<h2 id="student-info">Student Info</h2>
<div class="info">
<label for="student-name">Name:</label>
<input type="text" name="student-name" id="student-name" />
</div>
<div class="info">
<label for="student-email">Email:</label>
<input type="email" name="student-email" id="student-email" />
</div>
--fcc-editable-region--
<div class="info">
<label for="birth-date">D.O.B.</label>
<input type="date" name="birth-date" id="birth-date" />
</div>
--fcc-editable-region--
</section>
<section role="region" aria-labelledby="html-questions">
<h2 id="html-questions">HTML</h2>
</section>
<section role="region" aria-labelledby="css-questions">
<h2 id="css-questions">CSS</h2>
</section>
</form>
</main>
</body>
</html>
```
```css
body {
background: #f5f6f7;
color: #1b1b32;
font-family: Helvetica;
margin: 0;
}
header {
width: 100%;
height: 50px;
background-color: #1b1b32;
display: flex;
}
#logo {
width: max(100px, 18vw);
background-color: #0a0a23;
aspect-ratio: 35 / 4;
padding: 0.4rem;
}
h1 {
color: #f1be32;
font-size: min(5vw, 1.2em);
}
nav {
width: 50%;
max-width: 300px;
height: 50px;
}
nav > ul {
display: flex;
justify-content: space-evenly;
}
h1,
h2 {
font-family: Verdana, Tahoma;
}
h2 {
border-bottom: 4px solid #dfdfe2;
}
```

View File

@@ -0,0 +1,197 @@
---
id: 6143956ed76ed60e012faa51
title: Passo 25
challengeType: 0
dashedName: step-25
---
# --description--
O texto `.sr-only` ainda está visível. Existe um padrão comum para ocultar visualmente o texto para que apenas os leitores de tela leiam.
Este padrão é para definir as seguintes propriedades do CSS:
```css
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
```
Use o padrão acima para definir a classe `sr-only`.
# --hints--
Você deve usar o seletor `.sr-only`.
```js
assert.exists(new __helpers.CSSHelp(document).getStyle('.sr-only'));
```
Você deve dar ao `.sr-only` uma `position` de `absolute`.
```js
assert.equal(new __helpers.CSSHelp(document).getStyle('.sr-only')?.position, 'absolute');
```
Você deve dar ao `.sr-only` um `width` de `1px`.
```js
assert.equal(new __helpers.CSSHelp(document).getStyle('.sr-only')?.width, '1px');
```
Você deve dar ao `.sr-only` uma `height` de `1px`.
```js
assert.equal(new __helpers.CSSHelp(document).getStyle('.sr-only')?.height, '1px');
```
Você deve dar ao `.sr-only` um `padding` de `0`.
```js
assert.equal(new __helpers.CSSHelp(document).getStyle('.sr-only')?.padding, '0px');
```
Você deve dar ao `.sr-only` um `margin` de `-1px`.
```js
assert.equal(new __helpers.CSSHelp(document).getStyle('.sr-only')?.margin, '-1px');
```
Você deve dar ao `.sr-only` um `overflow` de `hidden`.
```js
assert.equal(new __helpers.CSSHelp(document).getStyle('.sr-only')?.overflow, 'hidden');
```
Você deve dar ao `.sr-only` um `clip` de `rect(0, 0, 0, 0)`.
```js
assert.equal(new __helpers.CSSHelp(document).getStyle('.sr-only')?.clip, 'rect(0px, 0px, 0px, 0px)');
```
Você deve dar ao `.sr-only` um `white-space` de `nowrap`.
```js
assert.equal(new __helpers.CSSHelp(document).getStyle('.sr-only')?.whiteSpace, 'nowrap');
```
Você deve dar ao `.sr-only` um `border` de `0`.
```js
assert.equal(new __helpers.CSSHelp(document).getStyle('.sr-only')?.borderWidth, '0px');
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="freeCodeCamp Accessibility Quiz practice project" />
<title>Accessibility Quiz</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header>
<img id="logo" src="https://cdn.freecodecamp.org/platform/universal/fcc_primary.svg">
<h1>HTML/CSS Quiz</h1>
<nav>
<ul>
<li><a href="#student-info">INFO</a></li>
<li><a href="#html-questions">HTML</a></li>
<li><a href="#css-questions">CSS</a></li>
</ul>
</nav>
</header>
<main>
<form method="post" action="https://freecodecamp.org/practice-project/accessibility-quiz">
<section role="region" aria-labelledby="student-info">
<h2 id="student-info">Student Info</h2>
<div class="info">
<label for="student-name">Name:</label>
<input type="text" name="student-name" id="student-name" />
</div>
<div class="info">
<label for="student-email">Email:</label>
<input type="email" name="student-email" id="student-email" />
</div>
<div class="info">
<label for="birth-date">D.O.B.<span class="sr-only">(Date of Birth)</span></label>
<input type="date" name="birth-date" id="birth-date" />
</div>
</section>
<section role="region" aria-labelledby="html-questions">
<h2 id="html-questions">HTML</h2>
</section>
<section role="region" aria-labelledby="css-questions">
<h2 id="css-questions">CSS</h2>
</section>
</form>
</main>
</body>
</html>
```
```css
body {
background: #f5f6f7;
color: #1b1b32;
font-family: Helvetica;
margin: 0;
}
header {
width: 100%;
height: 50px;
background-color: #1b1b32;
display: flex;
}
#logo {
width: max(100px, 18vw);
background-color: #0a0a23;
aspect-ratio: 35 / 4;
padding: 0.4rem;
}
h1 {
color: #f1be32;
font-size: min(5vw, 1.2em);
}
nav {
width: 50%;
max-width: 300px;
height: 50px;
}
nav > ul {
display: flex;
justify-content: space-evenly;
}
h1,
h2 {
font-family: Verdana, Tahoma;
}
h2 {
border-bottom: 4px solid #dfdfe2;
}
--fcc-editable-region--
--fcc-editable-region--
```

View File

@@ -0,0 +1,177 @@
---
id: 6143cb26f7edff2dc28f7da5
title: Passo 27
challengeType: 0
dashedName: step-27
---
# --description--
Cada `fieldset` conterá uma pergunta verdadeira/falsa.
Dentro de cada `fieldset`, aninhe um elemento `legend`, e um elemento `ul` com duas opções.
# --hints--
Você deve aninhar um elemento `legend` dentro do primeiro elemento `fieldset`.
```js
assert.equal(document.querySelectorAll('.question-block:nth-of-type(1) > fieldset > legend')?.length, 1);
```
Você deve aninhar um elemento `ul` dentro do primeiro elemento `fieldset`.
```js
assert.equal(document.querySelectorAll('.question-block:nth-of-type(1) > fieldset > ul')?.length, 1);
```
Você deve aninhar dois elementos `li` dentro do primeiro elemento `ul`.
```js
assert.equal(document.querySelectorAll('fieldset > ul')?.[0]?.querySelectorAll('li')?.length, 2);
```
Você deve aninhar dois elementos `legend`dentro do segundo elemento `fieldset`.
```js
assert.equal(document.querySelectorAll('.question-block:nth-of-type(2) > fieldset > legend')?.length, 1);
```
Você deve aninhar um elemento `ul` dentro do segundo elemento `fieldset`.
```js
assert.equal(document.querySelectorAll('.question-block:nth-of-type(2) > fieldset > ul')?.length, 1);
```
Você deve aninhar dois elementos `li` dentro do segundo elemento `ul`.
```js
assert.equal(document.querySelectorAll('fieldset > ul')?.[1]?.querySelectorAll('li')?.length, 2);
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="freeCodeCamp Accessibility Quiz practice project" />
<title>Accessibility Quiz</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header>
<img id="logo" src="https://cdn.freecodecamp.org/platform/universal/fcc_primary.svg">
<h1>HTML/CSS Quiz</h1>
<nav>
<ul>
<li><a href="#student-info">INFO</a></li>
<li><a href="#html-questions">HTML</a></li>
<li><a href="#css-questions">CSS</a></li>
</ul>
</nav>
</header>
<main>
<form method="post" action="https://freecodecamp.org/practice-project/accessibility-quiz">
<section role="region" aria-labelledby="student-info">
<h2 id="student-info">Student Info</h2>
<div class="info">
<label for="student-name">Name:</label>
<input type="text" name="student-name" id="student-name" />
</div>
<div class="info">
<label for="student-email">Email:</label>
<input type="email" name="student-email" id="student-email" />
</div>
<div class="info">
<label for="birth-date">D.O.B.<span class="sr-only">(Date of Birth)</span></label>
<input type="date" name="birth-date" id="birth-date" />
</div>
</section>
--fcc-editable-region--
<section role="region" aria-labelledby="html-questions">
<h2 id="html-questions">HTML</h2>
<div class="question-block">
<p>1</p>
<fieldset class="question"></fieldset>
</div>
<div class="question-block">
<p>2</p>
<fieldset class="question"></fieldset>
</div>
</section>
--fcc-editable-region--
<section role="region" aria-labelledby="css-questions">
<h2 id="css-questions">CSS</h2>
</section>
</form>
</main>
</body>
</html>
```
```css
body {
background: #f5f6f7;
color: #1b1b32;
font-family: Helvetica;
margin: 0;
}
header {
width: 100%;
height: 50px;
background-color: #1b1b32;
display: flex;
}
#logo {
width: max(100px, 18vw);
background-color: #0a0a23;
aspect-ratio: 35 / 4;
padding: 0.4rem;
}
h1 {
color: #f1be32;
font-size: min(5vw, 1.2em);
}
nav {
width: 50%;
max-width: 300px;
height: 50px;
}
nav > ul {
display: flex;
justify-content: space-evenly;
}
h1,
h2 {
font-family: Verdana, Tahoma;
}
h2 {
border-bottom: 4px solid #dfdfe2;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
```

View File

@@ -0,0 +1,195 @@
---
id: 6144e818fd5ea704fe56081d
title: Passo 28
challengeType: 0
dashedName: step-28
---
# --description--
Dê a cada `fieldset` um atributo `name` adequado. Em seguida, dê a ambas as listas não ordenadas uma `class` de `answers-list`.
Finalmente, use `legend` para legendar o conteúdo do `fieldset` colocando uma pergunta verdadeira/falsa como o conteúdo do texto.
# --hints--
Você deve dar ao primeiro `fieldset` um atributo `name` adequado. _Dica: Eu usaria `html-question-one`_
```js
assert.notEmpty(document.querySelectorAll('fieldset')?.[0]?.name);
```
Você deve dar ao segundo `fieldset` um atributo `name` adequado. _Dica: Eu usaria `html-question-two`_
```js
assert.notEmpty(document.querySelectorAll('fieldset')?.[1]?.name);
```
Você deve dar ao primeiro elemento `ul` uma `class` de `answers-list`.
```js
assert.equal(document.querySelectorAll('fieldset > ul')?.[0]?.className, 'answers-list');
```
Você deve dar ao segundo elemento `ul` uma `class` de `answers-list`.
```js
assert.equal(document.querySelectorAll('fieldset > ul')?.[1]?.className, 'answers-list');
```
Você deve dar ao primeiro elemento `legend` conteúdo de texto.
```js
assert.notEmpty(document.querySelectorAll('legend')?.[0]?.textContent);
```
Você deve dar ao segundo elemento `legend` conteúdo de texto.
```js
assert.notEmpty(document.querySelectorAll('legend')?.[1]?.textContent);
```
Você não deve usar o mesmo conteúdo de texto para ambos elementos `legend`.
```js
assert.notEqual(document.querySelectorAll('legend')?.[0]?.textContent, document.querySelectorAll('legend')?.[1]?.textContent);
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="freeCodeCamp Accessibility Quiz practice project" />
<title>Accessibility Quiz</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header>
<img id="logo" src="https://cdn.freecodecamp.org/platform/universal/fcc_primary.svg">
<h1>HTML/CSS Quiz</h1>
<nav>
<ul>
<li><a href="#student-info">INFO</a></li>
<li><a href="#html-questions">HTML</a></li>
<li><a href="#css-questions">CSS</a></li>
</ul>
</nav>
</header>
<main>
<form method="post" action="https://freecodecamp.org/practice-project/accessibility-quiz">
<section role="region" aria-labelledby="student-info">
<h2 id="student-info">Student Info</h2>
<div class="info">
<label for="student-name">Name:</label>
<input type="text" name="student-name" id="student-name" />
</div>
<div class="info">
<label for="student-email">Email:</label>
<input type="email" name="student-email" id="student-email" />
</div>
<div class="info">
<label for="birth-date">D.O.B.<span class="sr-only">(Date of Birth)</span></label>
<input type="date" name="birth-date" id="birth-date" />
</div>
</section>
--fcc-editable-region--
<section role="region" aria-labelledby="html-questions">
<h2 id="html-questions">HTML</h2>
<div class="question-block">
<p>1</p>
<fieldset class="question">
<legend></legend>
<ul>
<li></li>
<li></li>
</ul>
</fieldset>
</div>
<div class="question-block">
<p>2</p>
<fieldset class="question">
<legend></legend>
<ul>
<li></li>
<li></li>
</ul>
</fieldset>
</div>
</section>
--fcc-editable-region--
<section role="region" aria-labelledby="css-questions">
<h2 id="css-questions">CSS</h2>
</section>
</form>
</main>
</body>
</html>
```
```css
body {
background: #f5f6f7;
color: #1b1b32;
font-family: Helvetica;
margin: 0;
}
header {
width: 100%;
height: 50px;
background-color: #1b1b32;
display: flex;
}
#logo {
width: max(100px, 18vw);
background-color: #0a0a23;
aspect-ratio: 35 / 4;
padding: 0.4rem;
}
h1 {
color: #f1be32;
font-size: min(5vw, 1.2em);
}
nav {
width: 50%;
max-width: 300px;
height: 50px;
}
nav > ul {
display: flex;
justify-content: space-evenly;
}
h1,
h2 {
font-family: Verdana, Tahoma;
}
h2 {
border-bottom: 4px solid #dfdfe2;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
```

View File

@@ -0,0 +1,231 @@
---
id: 6144f8dc6849e405dd8bb829
title: Passo 29
challengeType: 0
dashedName: step-29
---
# --description--
Para fornecer a funcionalidade das perguntas de verdadeiro/falso, precisamos de um conjunto de entradas que não permita que ambas sejam selecionadas ao mesmo tempo.
Dentro de cada elemento da lista, aninhe um elemento `label`, e, dentro de cada elemento `label`, aninhe um elemento `input` com o `type` apropriado.
# --hints--
Você deve aninhar um elemento `label` dentro do primeiro elemento `li`.
```js
assert.exists(document.querySelectorAll('ul.answers-list > li')?.[0]?.querySelector('label'));
```
Você deve aninhar um elemento `label` dentro do segundo elemento `li`.
```js
assert.exists(document.querySelectorAll('ul.answers-list > li')?.[1]?.querySelector('label'));
```
Você deve aninhar um elemento `label` dentro do terceiro elemento `li`.
```js
assert.exists(document.querySelectorAll('ul.answers-list > li')?.[2]?.querySelector('label'));
```
Você deve aninhar um elemento `label` dentro do quarto elemento `li`.
```js
assert.exists(document.querySelectorAll('ul.answers-list > li')?.[3]?.querySelector('label'));
```
Você deve aninhar um elemento `input` dentro do primeiro elemento `label`.
```js
assert.exists(document.querySelectorAll('ul.answers-list > li')?.[0]?.querySelector('label')?.querySelector('input'));
```
Você deve aninhar um elemento `input` dentro do segundo elemento `label`.
```js
assert.exists(document.querySelectorAll('ul.answers-list > li')?.[1]?.querySelector('label')?.querySelector('input'));
```
Você deve aninhar um elemento `input` dentro do terceiro elemento `label`.
```js
assert.exists(document.querySelectorAll('ul.answers-list > li')?.[2]?.querySelector('label')?.querySelector('input'));
```
Você deve aninhar um elemento `input` dentro do quarto elemento `label`.
```js
assert.exists(document.querySelectorAll('ul.answers-list > li')?.[3]?.querySelector('label')?.querySelector('input'));
```
Você deve dar ao primeiro `input` um `type` de `radio`.
```js
assert.equal(document.querySelectorAll('ul.answers-list > li > label > input')?.[0]?.type, 'radio');
```
Você deve dar ao segundo `input` um `type` de `radio`.
```js
assert.equal(document.querySelectorAll('ul.answers-list > li > label > input')?.[1]?.type, 'radio');
```
Você deve dar ao terceiro `input` um `type` de `radio`.
```js
assert.equal(document.querySelectorAll('ul.answers-list > li > label > input')?.[2]?.type, 'radio');
```
Você deve dar ao quarto `input` um `type` de `radio`.
```js
assert.equal(document.querySelectorAll('ul.answers-list > li > label > input')?.[3]?.type, 'radio');
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="freeCodeCamp Accessibility Quiz practice project" />
<title>Accessibility Quiz</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header>
<img id="logo" src="https://cdn.freecodecamp.org/platform/universal/fcc_primary.svg">
<h1>HTML/CSS Quiz</h1>
<nav>
<ul>
<li><a href="#student-info">INFO</a></li>
<li><a href="#html-questions">HTML</a></li>
<li><a href="#css-questions">CSS</a></li>
</ul>
</nav>
</header>
<main>
<form method="post" action="https://freecodecamp.org/practice-project/accessibility-quiz">
<section role="region" aria-labelledby="student-info">
<h2 id="student-info">Student Info</h2>
<div class="info">
<label for="student-name">Name:</label>
<input type="text" name="student-name" id="student-name" />
</div>
<div class="info">
<label for="student-email">Email:</label>
<input type="email" name="student-email" id="student-email" />
</div>
<div class="info">
<label for="birth-date">D.O.B.<span class="sr-only">(Date of Birth)</span></label>
<input type="date" name="birth-date" id="birth-date" />
</div>
</section>
<section role="region" aria-labelledby="html-questions">
<h2 id="html-questions">HTML</h2>
<div class="question-block">
<p>1</p>
<fieldset class="question" name="html-question-one">
<legend>
The legend element represents a caption for the content of its
parent fieldset element
</legend>
--fcc-editable-region--
<ul class="answers-list">
<li></li>
<li></li>
</ul>
</fieldset>
</div>
<div class="question-block">
<p>2</p>
<fieldset class="question" name="html-question-two">
<legend>
A label element nesting an input element is required to have a
for attribute with the same value as the input's id
</legend>
<ul class="answers-list">
<li></li>
<li></li>
</ul>
--fcc-editable-region--
</fieldset>
</div>
</section>
<section role="region" aria-labelledby="css-questions">
<h2 id="css-questions">CSS</h2>
</section>
</form>
</main>
</body>
</html>
```
```css
body {
background: #f5f6f7;
color: #1b1b32;
font-family: Helvetica;
margin: 0;
}
header {
width: 100%;
height: 50px;
background-color: #1b1b32;
display: flex;
}
#logo {
width: max(100px, 18vw);
background-color: #0a0a23;
aspect-ratio: 35 / 4;
padding: 0.4rem;
}
h1 {
color: #f1be32;
font-size: min(5vw, 1.2em);
}
nav {
width: 50%;
max-width: 300px;
height: 50px;
}
nav > ul {
display: flex;
justify-content: space-evenly;
}
h1,
h2 {
font-family: Verdana, Tahoma;
}
h2 {
border-bottom: 4px solid #dfdfe2;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
```

View File

@@ -0,0 +1,207 @@
---
id: 6145e6eeaa66c605eb087fe9
title: Passo 30
challengeType: 0
dashedName: step-30
---
# --description--
Embora não seja necessário para elementos `label` com um `input` aninhado, ainda é uma prática recomendada vincular explicitamente um `label` com seu elemento `input` correspondente.
Vincule os elementos `label` com seus elementos `input` correspondentes.
# --hints--
Você deve dar ao primeiro `label` um atributo `for` que corresponda ao `id` de seu elemento `input`.
```js
const htmlFor = document.querySelectorAll('ul.answers-list > li > label')?.[0]?.htmlFor;
assert.notEmpty(htmlFor);
assert.equal(htmlFor, document.querySelectorAll('ul.answers-list > li > label > input')?.[0]?.id);
```
Você deve dar ao segundo `label` um atributo `for` que corresponda ao `id` de seu elemento `input`.
```js
const htmlFor = document.querySelectorAll('ul.answers-list > li > label')?.[1]?.htmlFor;
assert.notEmpty(htmlFor);
assert.equal(htmlFor, document.querySelectorAll('ul.answers-list > li > label > input')?.[1]?.id);
```
Você deve dar ao terceiro `label` um atributo `for` que corresponda ao `id` de seu elemento `input`.
```js
const htmlFor = document.querySelectorAll('ul.answers-list > li > label')?.[2]?.htmlFor;
assert.notEmpty(htmlFor);
assert.equal(htmlFor, document.querySelectorAll('ul.answers-list > li > label > input')?.[2]?.id);
```
Você deve dar ao `label` um atributo `for` que corresponda ao `id` de seu elemento `input`.
```js
const htmlFor = document.querySelectorAll('ul.answers-list > li > label')?.[3]?.htmlFor;
assert.notEmpty(htmlFor);
assert.equal(htmlFor, document.querySelectorAll('ul.answers-list > li > label > input')?.[3]?.id);
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="freeCodeCamp Accessibility Quiz practice project" />
<title>Accessibility Quiz</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header>
<img id="logo" src="https://cdn.freecodecamp.org/platform/universal/fcc_primary.svg">
<h1>HTML/CSS Quiz</h1>
<nav>
<ul>
<li><a href="#student-info">INFO</a></li>
<li><a href="#html-questions">HTML</a></li>
<li><a href="#css-questions">CSS</a></li>
</ul>
</nav>
</header>
<main>
<form method="post" action="https://freecodecamp.org/practice-project/accessibility-quiz">
<section role="region" aria-labelledby="student-info">
<h2 id="student-info">Student Info</h2>
<div class="info">
<label for="student-name">Name:</label>
<input type="text" name="student-name" id="student-name" />
</div>
<div class="info">
<label for="student-email">Email:</label>
<input type="email" name="student-email" id="student-email" />
</div>
<div class="info">
<label for="birth-date">D.O.B.<span class="sr-only">(Date of Birth)</span></label>
<input type="date" name="birth-date" id="birth-date" />
</div>
</section>
<section role="region" aria-labelledby="html-questions">
<h2 id="html-questions">HTML</h2>
<div class="question-block">
<p>1</p>
<fieldset class="question" name="html-question-one">
<legend>
The legend element represents a caption for the content of its
parent fieldset element
</legend>
--fcc-editable-region--
<ul class="answers-list">
<li>
<label>
<input type="radio" />
</label>
</li>
<li>
<label>
<input type="radio" />
</label>
</li>
</ul>
</fieldset>
</div>
<div class="question-block">
<p>2</p>
<fieldset class="question" name="html-question-two">
<legend>
A label element nesting an input element is required to have a
for attribute with the same value as the input's id
</legend>
<ul class="answers-list">
<li>
<label>
<input type="radio" />
</label>
</li>
<li>
<label>
<input type="radio" />
</label>
</li>
</ul>
--fcc-editable-region--
</fieldset>
</div>
</section>
<section role="region" aria-labelledby="css-questions">
<h2 id="css-questions">CSS</h2>
</section>
</form>
</main>
</body>
</html>
```
```css
body {
background: #f5f6f7;
color: #1b1b32;
font-family: Helvetica;
margin: 0;
}
header {
width: 100%;
height: 50px;
background-color: #1b1b32;
display: flex;
}
#logo {
width: max(100px, 18vw);
background-color: #0a0a23;
aspect-ratio: 35 / 4;
padding: 0.4rem;
}
h1 {
color: #f1be32;
font-size: min(5vw, 1.2em);
}
nav {
width: 50%;
max-width: 300px;
height: 50px;
}
nav > ul {
display: flex;
justify-content: space-evenly;
}
h1,
h2 {
font-family: Verdana, Tahoma;
}
h2 {
border-bottom: 4px solid #dfdfe2;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
```

View File

@@ -0,0 +1,220 @@
---
id: 6145f8f8bcd4370f6509078e
title: Passo 42
challengeType: 0
dashedName: step-42
---
# --description--
Dentro do elemento `address`, adicione o seguinte:
```html
freeCodeCamp<br />
San Francisco<br />
California<br />
USA
```
Você pode visitar, mas pode não encontrar nada...
# --hints--
Você deve adicionar o texto acima incluindo as tags `<br />` ao elemento `address`.
```js
assert.equal(document.querySelector('address')?.innerText, 'freeCodeCamp\nSan Francisco\nCalifornia\nUSA');
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="freeCodeCamp Accessibility Quiz practice project" />
<title>Accessibility Quiz</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header>
<img id="logo" src="https://cdn.freecodecamp.org/platform/universal/fcc_primary.svg">
<h1>HTML/CSS Quiz</h1>
<nav>
<ul>
<li><a href="#student-info">INFO</a></li>
<li><a href="#html-questions">HTML</a></li>
<li><a href="#css-questions">CSS</a></li>
</ul>
</nav>
</header>
<main>
<form method="post" action="https://freecodecamp.org/practice-project/accessibility-quiz">
<section role="region" aria-labelledby="student-info">
<h2 id="student-info">Student Info</h2>
<div class="info">
<label for="student-name">Name:</label>
<input type="text" name="student-name" id="student-name" />
</div>
<div class="info">
<label for="student-email">Email:</label>
<input type="email" name="student-email" id="student-email" />
</div>
<div class="info">
<label for="birth-date">D.O.B.<span class="sr-only">(Date of Birth)</span></label>
<input type="date" name="birth-date" id="birth-date" />
</div>
</section>
<section role="region" aria-labelledby="html-questions">
<h2 id="html-questions">HTML</h2>
<div class="question-block">
<p>1</p>
<fieldset class="question" name="html-question-one">
<legend>
The legend element represents a caption for the content of its
parent fieldset element
</legend>
<ul class="answers-list">
<li>
<label for="q1-a1">
<input type="radio" id="q1-a1" name="q1" value="true" />
True
</label>
</li>
<li>
<label for="q1-a2">
<input type="radio" id="q1-a2" name="q1" value="false" />
False
</label>
</li>
</ul>
</fieldset>
</div>
<div class="question-block">
<p>2</p>
<fieldset class="question" name="html-question-two">
<legend>
A label element nesting an input element is required to have a
for attribute with the same value as the input's id
</legend>
<ul class="answers-list">
<li>
<label for="q2-a1">
<input type="radio" id="q2-a1" name="q2" value="true" />
True
</label>
</li>
<li>
<label for="q2-a2">
<input type="radio" id="q2-a2" name="q2" value="false" />
False
</label>
</li>
</ul>
</fieldset>
</div>
</section>
<section role="region" aria-labelledby="css-questions">
<h2 id="css-questions">CSS</h2>
<div class="formrow">
<div class="question-block">
<label for="customer">Are you a frontend developer?</label>
</div>
<div class="answer">
<select name="customer" id="customer" required>
<option value="">Select an option</option>
<option value="yes">Yes</option>
<option value="no">No</option>
</select>
</div>
<div class="question-block">
<label for="css-questions">Do you have any questions:</label>
</div>
<div class="answer">
<textarea id="css-questions" name="css-questions" rows="5" cols="24" placeholder="Who is flexbox..."></textarea>
</div>
</div>
</section>
<button type="submit">Submit</button>
</form>
</main>
--fcc-editable-region--
<footer>
<address>
</address>
</footer>
--fcc-editable-region--
</body>
</html>
```
```css
body {
background: #f5f6f7;
color: #1b1b32;
font-family: Helvetica;
margin: 0;
}
header {
width: 100%;
height: 50px;
background-color: #1b1b32;
display: flex;
}
#logo {
width: max(100px, 18vw);
background-color: #0a0a23;
aspect-ratio: 35 / 4;
padding: 0.4rem;
}
h1 {
color: #f1be32;
font-size: min(5vw, 1.2em);
}
nav {
width: 50%;
max-width: 300px;
height: 50px;
}
nav > ul {
display: flex;
justify-content: space-evenly;
}
h1,
h2 {
font-family: Verdana, Tahoma;
}
h2 {
border-bottom: 4px solid #dfdfe2;
}
p::before {
content: "Question #";
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
```

View File

@@ -0,0 +1,261 @@
---
id: 61487b77d4a37707073a64e5
title: Passo 48
challengeType: 0
dashedName: step-48
---
# --description--
Quando a largura da tela é pequena, o `h1` não envolve seu conteúdo de texto como deveria. Centralize o texto para `h1`.
Em seguida, dê a `main` um espaçamento de maneira que a seção de `Student Info` possa ser totalmente vista.
# --hints--
Você deve dar ao `h1` um `text-align` de `center`.
```js
assert.equal(new __helpers.CSSHelp(document).getStyle('h1')?.textAlign, 'center');
```
Você deve adicionar um seletor `main` para segmentar o elemento `main`.
```js
assert.exists(new __helpers.CSSHelp(document).getStyle('main'));
```
Você deve dar ao `main` um `padding-top` de pelo menos `25px`.
```js
assert.isAtLeast(Number(new __helpers.CSSHelp(document).getStyle('main')?.paddingTop?.replace(/\D+/, '')), 25);
```
Você deve alterar somente o valor `padding-top`.
```js
assert.isEmpty(new __helpers.CSSHelp(document).getStyle('main')?.paddingBottom);
assert.isEmpty(new __helpers.CSSHelp(document).getStyle('main')?.paddingLeft);
assert.isEmpty(new __helpers.CSSHelp(document).getStyle('main')?.paddingRight);
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="freeCodeCamp Accessibility Quiz practice project" />
<title>Accessibility Quiz</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header>
<img id="logo" src="https://cdn.freecodecamp.org/platform/universal/fcc_primary.svg">
<h1>HTML/CSS Quiz</h1>
<nav>
<ul>
<li><a href="#student-info">INFO</a></li>
<li><a href="#html-questions">HTML</a></li>
<li><a href="#css-questions">CSS</a></li>
</ul>
</nav>
</header>
<main>
<form method="post" action="https://freecodecamp.org/practice-project/accessibility-quiz">
<section role="region" aria-labelledby="student-info">
<h2 id="student-info">Student Info</h2>
<div class="info">
<label for="student-name">Name:</label>
<input type="text" name="student-name" id="student-name" />
</div>
<div class="info">
<label for="student-email">Email:</label>
<input type="email" name="student-email" id="student-email" />
</div>
<div class="info">
<label for="birth-date">D.O.B.<span class="sr-only">(Date of Birth)</span></label>
<input type="date" name="birth-date" id="birth-date" />
</div>
</section>
<section role="region" aria-labelledby="html-questions">
<h2 id="html-questions">HTML</h2>
<div class="question-block">
<p>1</p>
<fieldset class="question" name="html-question-one">
<legend>
The legend element represents a caption for the content of its
parent fieldset element
</legend>
<ul class="answers-list">
<li>
<label for="q1-a1">
<input type="radio" id="q1-a1" name="q1" value="true" />
True
</label>
</li>
<li>
<label for="q1-a2">
<input type="radio" id="q1-a2" name="q1" value="false" />
False
</label>
</li>
</ul>
</fieldset>
</div>
<div class="question-block">
<p>2</p>
<fieldset class="question" name="html-question-two">
<legend>
A label element nesting an input element is required to have a
for attribute with the same value as the input's id
</legend>
<ul class="answers-list">
<li>
<label for="q2-a1">
<input type="radio" id="q2-a1" name="q2" value="true" />
True
</label>
</li>
<li>
<label for="q2-a2">
<input type="radio" id="q2-a2" name="q2" value="false" />
False
</label>
</li>
</ul>
</fieldset>
</div>
</section>
<section role="region" aria-labelledby="css-questions">
<h2 id="css-questions">CSS</h2>
<div class="formrow">
<div class="question-block">
<label for="customer">Are you a frontend developer?</label>
</div>
<div class="answer">
<select name="customer" id="customer" required>
<option value="">Select an option</option>
<option value="yes">Yes</option>
<option value="no">No</option>
</select>
</div>
<div class="question-block">
<label for="css-questions">Do you have any questions:</label>
</div>
<div class="answer">
<textarea id="css-questions" name="css-questions" rows="5" cols="24" placeholder="Who is flexbox..."></textarea>
</div>
</div>
</section>
<button type="submit">Submit</button>
</form>
</main>
<footer>
<address>
<a href="https://freecodecamp.org">freeCodeCamp</a><br />
San Francisco<br />
California<br />
USA
</address>
</footer>
</body>
</html>
```
```css
body {
background: #f5f6f7;
color: #1b1b32;
font-family: Helvetica;
margin: 0;
}
header {
width: 100%;
height: 50px;
background-color: #1b1b32;
display: flex;
justify-content: space-between;
align-items: center;
position: fixed;
top: 0;
}
#logo {
width: max(100px, 18vw);
background-color: #0a0a23;
aspect-ratio: 35 / 4;
padding: 0.4rem;
}
--fcc-editable-region--
h1 {
color: #f1be32;
font-size: min(5vw, 1.2em);
}
--fcc-editable-region--
nav {
width: 50%;
max-width: 300px;
height: 50px;
}
nav > ul {
display: flex;
justify-content: space-evenly;
}
nav > ul > li {
color: #dfdfe2;
margin: 0 0.2rem;
padding: 0.2rem;
display: block;
}
nav > ul > li:hover {
background-color: #dfdfe2;
color: #1b1b32;
cursor: pointer;
}
li > a {
color: inherit;
text-decoration: none;
}
h1,
h2 {
font-family: Verdana, Tahoma;
}
h2 {
border-bottom: 4px solid #dfdfe2;
}
p::before {
content: "Question #";
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
```

View File

@@ -0,0 +1,107 @@
---
id: 5f3c866d0fc037f7311b4ac8
title: Passo 39
challengeType: 0
dashedName: step-39
---
# --description--
Isso é mais perto, mas o preço não ficou mais à direita. Isto se deve ao fato de que os elementos `inline-block` só ocupam a largura de seu conteúdo. Para distribuí-los, adicione uma propriedade `width` aos seletores de classe `flavor` e `price` com um valor de `50%` cada.
# --hints--
Você deve definir a propriedade `width` para `50%` em seu seletor `.flavor`.
```js
const flavorWidth = new __helpers.CSSHelp(document).getStyle('.flavor')?.getPropertyValue('width');
assert(flavorWidth === '50%');
```
Você deve definir a propriedade `width` para `50%` em seu seletor `.price`.
```js
const priceWidth = new __helpers.CSSHelp(document).getStyle('.price')?.getPropertyValue('width');
assert(priceWidth === '50%');
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Cafe Menu</title>
<link href="styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div class="menu">
<header>
<h1>CAMPER CAFE</h1>
<p>Est. 2020</p>
</header>
<main>
<section>
<h2>Coffee</h2>
<article class="item">
<p class="flavor">French Vanilla</p>
<p class="price">3.00</p>
</article>
<article>
<p>Caramel Macchiato</p>
<p>3.75</p>
</article>
<article>
<p>Pumpkin Spice</p>
<p>3.50</p>
</article>
<article>
<p>Hazelnut</p>
<p>4.00</p>
</article>
<article>
<p>Mocha</p>
<p>4.50</p>
</article>
</section>
</main>
</div>
</body>
<html>
```
```css
body {
background-image: url(https://cdn.freecodecamp.org/curriculum/css-cafe/beans.jpg);
}
h1, h2, p {
text-align: center;
}
.menu {
width: 80%;
background-color: burlywood;
margin-left: auto;
margin-right: auto;
}
.item p {
display: inline-block;
}
--fcc-editable-region--
.flavor {
text-align: left;
}
.price {
text-align: right;
}
--fcc-editable-region--
```

View File

@@ -0,0 +1,100 @@
---
id: 5f3c866d28d7ad0de6470505
title: Passo 33
challengeType: 0
dashedName: step-33
---
# --description--
Os sabores e preços estão atualmente empilhados uns sobre os outros e centrados com seus elementos `p` respectivos. Seria bom se o sabor estivesse à esquerda e o preço estivesse à direita.
Adicione o nome da classe `flavor` ao elemento `p` que diz `French Vanilla`.
# --hints--
Você deve adicionar a classe `flavor` ao seu elemento `p`.
```js
assert(code.match(/<p\s*class=('|")flavor\1\s*>/i));
```
Você deve ter apenas um elemento com a classe `flavor`.
```js
assert($('.flavor').length === 1);
```
Sua classe `flavor` deve estar no elemento `p` com o texto `French Vanilla`.
```js
assert($('.flavor')[0].innerText.match(/French Vanilla/i));
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Cafe Menu</title>
<link href="styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div class="menu">
<header>
<h1>CAMPER CAFE</h1>
<p>Est. 2020</p>
</header>
<main>
<section>
<h2>Coffee</h2>
<article>
--fcc-editable-region--
<p>French Vanilla</p>
<p>3.00</p>
--fcc-editable-region--
</article>
<article>
<p>Caramel Macchiato</p>
<p>3.75</p>
</article>
<article>
<p>Pumpkin Spice</p>
<p>3.50</p>
</article>
<article>
<p>Hazelnut</p>
<p>4.00</p>
</article>
<article>
<p>Mocha</p>
<p>4.50</p>
</article>
</section>
</main>
</div>
</body>
<html>
```
```css
body {
background-image: url(https://cdn.freecodecamp.org/curriculum/css-cafe/beans.jpg);
}
h1, h2, p {
text-align: center;
}
.menu {
width: 80%;
background-color: burlywood;
margin-left: auto;
margin-right: auto;
}
```

View File

@@ -0,0 +1,128 @@
---
id: 5f3c866d5414453fc2d7b480
title: Passo 32
challengeType: 0
dashedName: step-32
---
# --description--
Começando abaixo do par café/preço existente, adicione os cafés e preços abaixo usando elementos `article` com dois elementos aninhados dentro de cada `p`. Como antes, o primeiro texto `p` deve conter o sabor do café e o segundo texto `p` deve conter o preço.
```bash
Caramel Macchiato 3.75
Pumpkin Spice 3.50
Hazelnut 4.00
Mocha 4.50
```
# --hints--
Você deve ter cinco elementos `article`.
```js
assert($('article').length === 5);
```
Cada elemento `article` deve ter dois elementos `p`.
```js
const articles = $('article');
assert(articles[0].children.length === 2);
assert(articles[1].children.length === 2);
assert(articles[2].children.length === 2);
assert(articles[3].children.length === 2);
assert(articles[4].children.length === 2);
```
Seu primeiro elemento `article` deve ter elementos `p` com o texto `French Vanilla` e `3.00`.
```js
const children = $('article')[0].children;
assert(children[0].innerText.match(/French Vanilla/i));
assert(children[1].innerText.match(/3\.00/i));
```
Seu segundo elemento `article` deve ter elementos `p` com o texto `Caramel Macchiato` e `3.75`.
```js
const children = $('article')[1].children;
assert(children[0].innerText.match(/Caramel Macchiato/i));
assert(children[1].innerText.match(/3\.75/i));
```
Seu terceiro elemento `article` deve ter elementos `p` com o texto `Pumpkin Spice` e `3.50`.
```js
const children = $('article')[2].children;
assert(children[0].innerText.match(/Pumpkin Spice/i));
assert(children[1].innerText.match(/3\.50/i));
```
Seu quarto elemento `article` deve ter elementos `p` com o texto `Hazelnut` e `4.00`.
```js
const children = $('article')[3].children;
assert(children[0].innerText.match(/Hazelnut/i));
assert(children[1].innerText.match(/4\.00/i));
```
Seu quinto elemento `article` deve ter elementos `p` com o texto `Mocha` e `4.50`.
```js
const children = $('article')[4].children;
assert(children[0].innerText.match(/Mocha/i));
assert(children[1].innerText.match(/4\.50/i));
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Cafe Menu</title>
<link href="styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div class="menu">
<header>
<h1>CAMPER CAFE</h1>
<p>Est. 2020</p>
</header>
<main>
<section>
<h2>Coffee</h2>
--fcc-editable-region--
<article>
<p>French Vanilla</p>
<p>3.00</p>
</article>
--fcc-editable-region--
</section>
</main>
</div>
</body>
<html>
```
```css
body {
background-image: url(https://cdn.freecodecamp.org/curriculum/css-cafe/beans.jpg);
}
h1, h2, p {
text-align: center;
}
.menu {
width: 80%;
background-color: burlywood;
margin-left: auto;
margin-right: auto;
}
```

View File

@@ -0,0 +1,59 @@
---
id: 5dc174fcf86c76b9248c6eb2
title: Passo 1
challengeType: 0
dashedName: step-1
---
# --description--
Os elementos em HTML têm tags de abertura, como `<h1>`, e tags de fechamento, como `</h1>`.
Encontre o elemento `h1` e altere o texto entre suas tags de abertura e fechamento para que diga `CatPhotoApp`.
# --hints--
O texto `CatPhotoApp` deve estar presente no código. Não se esqueça de verificar a ortografia.
```js
assert(code.match(/catphotoapp/i));
```
O elemento `h1` deve ter uma tag de abertura. As tags de abertura têm essa sintaxe: `<elementName>`.
```js
assert(document.querySelector('h1'));
```
O elemento `h1` deve ter uma tag de fechamento. As tags de fechamento têm um caractere `/` logo após o caractere `<`.
```js
assert(code.match(/<\/h1\>/));
```
Você tem mais de um elemento `h1`. Remova o elemento `h1` a mais.
```js
assert(document.querySelectorAll('h1').length === 1);
```
O elemento `h1` deve conter o texto `CatPhotoApp`. Você omitiu o texto, digitou o texto incorretamente ou ele não está entre as tags de abertura e fechamento do elemento `h1`.
```js
assert(document.querySelector('h1').innerText.toLowerCase() === 'catphotoapp');
```
# --seed--
## --seed-contents--
```html
<html>
<body>
--fcc-editable-region--
<h1>Hello World</h1>
--fcc-editable-region--
</body>
</html>
```

View File

@@ -0,0 +1,82 @@
---
id: 5dc1798ff86c76b9248c6eb3
title: Passo 2
challengeType: 0
dashedName: step-2
---
# --description--
Os elementos de título, que vão de `h1` a `h6`, são usados para dar significado à importância do conteúdo abaixo deles. Quanto menor o número, maior a importância. Assim, os elementos `h2` têm menos importância que os elementos `h1`. Use apenas um elemento `h1` por página e coloque os títulos de importância inferior abaixo dos títulos de maior importância.
Adicione um elemento `h2` abaixo do elemento `h1` que diga `Cat Photos`.
# --hints--
O elemento `h1` deve ter uma tag de abertura. As tags de abertura têm essa sintaxe: `<elementName>`.
```js
assert(document.querySelector('h1'));
```
O elemento `h1` deve ter uma tag de fechamento. As tags de fechamento têm um caractere `/` logo após o caractere `<`.
```js
assert(code.match(/<\/h1\>/));
```
Você deve ter apenas um elemento `h1`. Remova o elemento adicional.
```js
assert(
document.querySelector('h1') && document.querySelectorAll('h1').length === 1
);
```
O elemento `h1` deve conter o texto 'CatPhotoApp'. Você omitiu o texto ou tem um erro de digitação.
```js
assert(document.querySelector('h1').innerText.toLowerCase() === 'catphotoapp');
```
O elemento `h2` deve ter uma tag de abertura. As tags de abertura têm essa sintaxe: `<elementName>`.
```js
assert(document.querySelector('h2'));
```
O elemento `h2` deve ter uma tag de fechamento. As tags de fechamento têm um caractere `/` logo após o caractere `<`.
```js
assert(code.match(/<\/h2\>/));
```
O elemento `h2` deve conter o texto 'Cat Photos'. Coloque apenas o texto `Cat Photos` entre as tags de abertura e de fechamento de `h2`.
```js
assert(document.querySelector('h2').innerText.toLowerCase() === 'cat photos');
```
O elemento `h2` deve estar abaixo do elemento `h1`. O elemento `h1` tem maior importância e deve estar acima do elemento `h2`.
```js
const collection = [...document.querySelectorAll('h1,h2')].map(
(node) => node.nodeName
);
assert(collection.indexOf('H1') < collection.indexOf('H2'));
```
# --seed--
## --seed-contents--
```html
<html>
<body>
--fcc-editable-region--
<h1>CatPhotoApp</h1>
--fcc-editable-region--
</body>
</html>
```

View File

@@ -106,5 +106,6 @@
"es69h6": "When you join two windows into one window",
"fho5t5": "When you open a new tab at the end",
"00kcrm": "yields true",
"sxpg2a": "Your mailbox, drive, and other work sites"
"sxpg2a": "Your mailbox, drive, and other work sites",
"4143lf": "initialize buttons"
}

View File

@@ -1,8 +1,9 @@
const fs = require('fs');
const path = require('path');
const util = require('util');
const assert = require('assert');
const yaml = require('js-yaml');
const { findIndex } = require('lodash');
const { findIndex, isEmpty } = require('lodash');
const readDirP = require('readdirp');
const { helpCategoryMap } = require('../client/utils/challenge-types');
const { showUpcomingChanges } = require('../config/env.json');
@@ -22,13 +23,13 @@ const { getSuperOrder, getSuperBlockFromDir } = require('./utils');
const access = util.promisify(fs.access);
const challengesDir = path.resolve(__dirname, './challenges');
const metaDir = path.resolve(challengesDir, '_meta');
exports.challengesDir = challengesDir;
exports.metaDir = metaDir;
const CHALLENGES_DIR = path.resolve(__dirname, 'challenges');
const META_DIR = path.resolve(CHALLENGES_DIR, '_meta');
exports.CHALLENGES_DIR = CHALLENGES_DIR;
exports.META_DIR = META_DIR;
const COMMENT_TRANSLATIONS = createCommentMap(
path.resolve(__dirname, './dictionaries')
path.resolve(__dirname, 'dictionaries')
);
function getTranslatableComments(dictionariesDir) {
@@ -109,20 +110,19 @@ function getTranslationEntry(dicts, { engId, text }) {
if (entry) {
return { ...acc, [lang]: entry };
} else {
throw Error(`Missing translation for comment
'${text}'
with id of ${engId}`);
// default to english
return { ...acc, [lang]: text };
}
}, {});
}
function getChallengesDirForLang(lang) {
return path.resolve(challengesDir, `./${lang}`);
return path.resolve(CHALLENGES_DIR, `${lang}`);
}
function getMetaForBlock(block) {
return JSON.parse(
fs.readFileSync(path.resolve(metaDir, `./${block}/meta.json`), 'utf8')
fs.readFileSync(path.resolve(META_DIR, `${block}/meta.json`), 'utf8')
);
}
@@ -153,7 +153,9 @@ const walk = (root, target, options, cb) => {
};
exports.getChallengesForLang = async function getChallengesForLang(lang) {
const root = getChallengesDirForLang(lang);
// english determines the shape of the curriculum, all other languages mirror
// it.
const root = getChallengesDirForLang('english');
// scaffold the curriculum, first set up the superblocks, then recurse into
// the blocks
const curriculum = await walk(
@@ -162,6 +164,9 @@ exports.getChallengesForLang = async function getChallengesForLang(lang) {
{ type: 'directories', depth: 0 },
buildSuperBlocks
);
Object.entries(curriculum).forEach(([name, superBlock]) => {
assert(!isEmpty(superBlock.blocks), `superblock ${name} has no blocks`);
});
const cb = (file, curriculum) => buildChallenges(file, curriculum, lang);
// fill the scaffold with the challenges
return walk(
@@ -173,10 +178,7 @@ exports.getChallengesForLang = async function getChallengesForLang(lang) {
};
async function buildBlocks({ basename: blockName }, curriculum, superBlock) {
const metaPath = path.resolve(
__dirname,
`./challenges/_meta/${blockName}/meta.json`
);
const metaPath = path.resolve(META_DIR, `${blockName}/meta.json`);
if (fs.existsSync(metaPath)) {
// try to read the file, if the meta path does not exist it should be a certification.
@@ -240,9 +242,10 @@ async function buildChallenges({ path: filePath }, curriculum, lang) {
) {
return;
}
const createChallenge = generateChallengeCreator(CHALLENGES_DIR, lang);
const challenge = isCert
? await createCertification(challengesDir, filePath, lang)
: await createChallenge(challengesDir, filePath, lang, meta);
? await createCertification(CHALLENGES_DIR, filePath, lang)
: await createChallenge(filePath, meta);
challengeBlock.challenges = [...challengeBlock.challenges, challenge];
}
@@ -258,8 +261,7 @@ async function parseTranslation(transPath, dict, lang, parse = parseMD) {
: translatedChal;
}
// eslint-disable-next-line no-unused-vars
async function createCertification(basePath, filePath, lang) {
async function createCertification(basePath, filePath) {
function getFullPath(pathLang) {
return path.resolve(__dirname, basePath, pathLang, filePath);
}
@@ -270,90 +272,111 @@ async function createCertification(basePath, filePath, lang) {
return parseCert(getFullPath('english'));
}
async function createChallenge(basePath, filePath, lang, maybeMeta) {
function getFullPath(pathLang) {
// This is a slightly weird abstraction, but it lets us define helper functions
// without passing around a ton of arguments.
function generateChallengeCreator(basePath, lang) {
function getFullPath(pathLang, filePath) {
return path.resolve(__dirname, basePath, pathLang, filePath);
}
let meta;
if (maybeMeta) {
meta = maybeMeta;
} else {
const metaPath = path.resolve(
metaDir,
`./${getBlockNameFromPath(filePath)}/meta.json`
);
meta = require(metaPath);
}
const { superBlock } = meta;
if (!curriculumLangs.includes(lang))
throw Error(`${lang} is not a accepted language.
Trying to parse ${filePath}`);
if (lang !== 'english' && !(await hasEnglishSource(basePath, filePath)))
throw Error(`Missing English challenge for
async function validate(filePath, superBlock) {
const invalidLang = !curriculumLangs.includes(lang);
if (invalidLang)
throw Error(`${lang} is not a accepted language.
Trying to parse ${filePath}`);
const missingEnglish =
lang !== 'english' && !(await hasEnglishSource(basePath, filePath));
if (missingEnglish)
throw Error(`Missing English challenge for
${filePath}
It should be in
${getFullPath('english')}
${getFullPath('english', filePath)}
`);
// assumes superblock names are unique
// while the auditing is ongoing, we default to English for un-audited certs
// once that's complete, we can revert to using isEnglishChallenge(fullPath)
const useEnglish = lang === 'english' || !isAuditedCert(lang, superBlock);
const challenge = await (useEnglish
? parseMD(getFullPath('english'))
: parseTranslation(getFullPath(lang), COMMENT_TRANSLATIONS, lang));
const missingAuditedChallenge =
isAuditedCert(lang, superBlock) &&
!fs.existsSync(getFullPath(lang, filePath));
if (missingAuditedChallenge)
throw Error(`Missing ${lang} audited challenge for
${filePath}
No audited challenges should fallback to English.
`);
}
const challengeOrder = findIndex(
meta.challengeOrder,
([id]) => id === challenge.id
);
const {
name: blockName,
hasEditableBoundaries,
order,
isPrivate,
required = [],
template,
time,
usesMultifileEditor
} = meta;
challenge.block = dasherize(blockName);
challenge.hasEditableBoundaries = !!hasEditableBoundaries;
challenge.order = order;
const superOrder = getSuperOrder(superBlock, {
showNewCurriculum: process.env.SHOW_NEW_CURRICULUM === 'true'
});
if (superOrder !== null) challenge.superOrder = superOrder;
/* Since there can be more than one way to complete a certification (using the
function addMetaToChallenge(challenge, meta) {
const challengeOrder = findIndex(
meta.challengeOrder,
([id]) => id === challenge.id
);
challenge.block = meta.name ? dasherize(meta.name) : null;
challenge.hasEditableBoundaries = !!meta.hasEditableBoundaries;
challenge.order = meta.order;
const superOrder = getSuperOrder(meta.superBlock, {
showNewCurriculum: process.env.SHOW_NEW_CURRICULUM === 'true'
});
if (superOrder !== null) challenge.superOrder = superOrder;
/* Since there can be more than one way to complete a certification (using the
legacy curriculum or the new one, for instance), we need a certification
field to track which certification this belongs to. */
// TODO: generalize this to all superBlocks
challenge.certification =
superBlock === '2022/responsive-web-design'
? 'responsive-web-design'
: superBlock;
challenge.superBlock = superBlock;
challenge.challengeOrder = challengeOrder;
challenge.isPrivate = challenge.isPrivate || isPrivate;
challenge.required = required.concat(challenge.required || []);
challenge.template = template;
challenge.time = time;
challenge.helpCategory =
challenge.helpCategory || helpCategoryMap[challenge.block];
challenge.translationPending =
lang !== 'english' && !isAuditedCert(lang, superBlock);
challenge.usesMultifileEditor = !!usesMultifileEditor;
if (challenge.challengeFiles) {
// The client expects the challengeFiles to be an array of polyvinyls
challenge.challengeFiles = challengeFilesToPolys(challenge.challengeFiles);
}
if (challenge.solutions?.length) {
// The test runner needs the solutions to be arrays of polyvinyls so it
// can sort them correctly.
challenge.solutions = challenge.solutions.map(challengeFilesToPolys);
// TODO: generalize this to all superBlocks
challenge.certification =
meta.superBlock === '2022/responsive-web-design'
? 'responsive-web-design'
: meta.superBlock;
challenge.superBlock = meta.superBlock;
challenge.challengeOrder = challengeOrder;
challenge.isPrivate = challenge.isPrivate || meta.isPrivate;
challenge.required = (meta.required || []).concat(challenge.required || []);
challenge.template = meta.template;
challenge.time = meta.time;
challenge.helpCategory =
challenge.helpCategory || helpCategoryMap[challenge.block];
challenge.translationPending =
lang !== 'english' && !isAuditedCert(lang, meta.superBlock);
challenge.usesMultifileEditor = !!meta.usesMultifileEditor;
if (challenge.challengeFiles) {
// The client expects the challengeFiles to be an array of polyvinyls
challenge.challengeFiles = challengeFilesToPolys(
challenge.challengeFiles
);
}
if (challenge.solutions?.length) {
// The test runner needs the solutions to be arrays of polyvinyls so it
// can sort them correctly.
challenge.solutions = challenge.solutions.map(challengeFilesToPolys);
}
}
return challenge;
async function createChallenge(filePath, maybeMeta) {
const meta = maybeMeta
? maybeMeta
: require(path.resolve(
META_DIR,
`${getBlockNameFromPath(filePath)}/meta.json`
));
await validate(filePath, meta.superBlock);
const useEnglish =
lang === 'english' ||
!isAuditedCert(lang, meta.superBlock) ||
!fs.existsSync(getFullPath(lang, filePath));
const challenge = await (useEnglish
? parseMD(getFullPath('english', filePath))
: parseTranslation(
getFullPath(lang, filePath),
COMMENT_TRANSLATIONS,
lang
));
addMetaToChallenge(challenge, meta);
return challenge;
}
return createChallenge;
}
function challengeFilesToPolys(files) {
@@ -390,4 +413,4 @@ function getBlockNameFromPath(filePath) {
exports.hasEnglishSource = hasEnglishSource;
exports.parseTranslation = parseTranslation;
exports.createChallenge = createChallenge;
exports.generateChallengeCreator = generateChallengeCreator;

View File

@@ -1,7 +1,7 @@
const path = require('path');
const {
createChallenge,
generateChallengeCreator,
hasEnglishSource,
createCommentMap
} = require('./getChallenges');
@@ -12,21 +12,25 @@ const MISSING_CHALLENGE_PATH = 'no/challenge.md';
const basePath = '__fixtures__';
describe('create non-English challenge', () => {
describe('createChallenge', () => {
it('throws if lang is an invalid language', async () => {
await expect(
createChallenge(basePath, EXISTING_CHALLENGE_PATH, 'notlang', {})
).rejects.toThrow('notlang is not a accepted language');
});
it('throws an error if the source challenge is missing', async () => {
await expect(
createChallenge(basePath, MISSING_CHALLENGE_PATH, 'chinese', {})
).rejects.toThrow(
`Missing English challenge for
describe('generateChallengeCreator', () => {
describe('createChallenge', () => {
it('throws if lang is an invalid language', async () => {
const createChallenge = generateChallengeCreator(basePath, 'notlang');
await expect(
createChallenge(EXISTING_CHALLENGE_PATH, {})
).rejects.toThrow('notlang is not a accepted language');
});
it('throws an error if the source challenge is missing', async () => {
const createChallenge = generateChallengeCreator(basePath, 'chinese');
await expect(
createChallenge(MISSING_CHALLENGE_PATH, {})
).rejects.toThrow(
`Missing English challenge for
${MISSING_CHALLENGE_PATH}
It should be in
`
);
);
});
});
});
describe('hasEnglishSource', () => {
@@ -69,9 +73,15 @@ It should be in
expect(typeof createCommentMap(dictionaryDir)).toBe('object');
});
it('throws if an entry is missing', () => {
expect.assertions(1);
expect(() => createCommentMap(incompleteDictDir)).toThrow();
it('fallback to the untranslated string', () => {
expect.assertions(2);
const commentMap = createCommentMap(incompleteDictDir);
expect(commentMap['To be translated one'].spanish).toEqual(
'Spanish translation one'
);
expect(commentMap['To be translated two'].spanish).toEqual(
'To be translated two'
);
});
it('returns an object with an expected form', () => {

View File

@@ -23,7 +23,7 @@ const fileJoi = Joi.object().keys({
const schema = Joi.object()
.keys({
block: Joi.string().regex(slugRE),
block: Joi.string().regex(slugRE).required(),
blockId: Joi.objectId(),
challengeOrder: Joi.number(),
removeComments: Joi.bool(),

View File

@@ -317,13 +317,13 @@ function populateTestsForLang({ lang, challenges, meta }) {
// Note: the title in meta.json are purely for human readability and
// do not include translations, so we do not validate against them.
it('Matches an ID in meta.json', function () {
const index = meta[dashedBlockName].challengeOrder.findIndex(
const index = meta[dashedBlockName]?.challengeOrder?.findIndex(
arr => arr[0] === challenge.id
);
if (index < 0) {
throw new AssertionError(
`Cannot find ID "${challenge.id}" in meta.json file`
`Cannot find ID "${challenge.id}" in meta.json file for block "${dashedBlockName}"`
);
}
});
@@ -370,11 +370,14 @@ function populateTestsForLang({ lang, challenges, meta }) {
// currently have the text of a comment elsewhere. If that happens
// we can handle that challenge separately.
TRANSLATABLE_COMMENTS.forEach(comment => {
const errorText = `English comment '${comment}' should be replaced with its translation`;
challenge.challengeFiles.forEach(challengeFile => {
if (challengeFile.contents.includes(comment))
throw Error(
`English comment '${comment}' should be replaced with its translation`
);
if (process.env.SHOW_UPCOMING_CHANGES == 'true') {
console.warn(errorText);
} else {
throw Error(errorText);
}
});
});
@@ -414,7 +417,10 @@ function populateTestsForLang({ lang, challenges, meta }) {
if (isEmpty(challenge.__commentCounts) && isEmpty(commentMap))
return;
if (!isEqual(commentMap, challenge.__commentCounts))
if (
process.env.SHOW_NEW_CURRICULUM !== 'true' &&
!isEqual(commentMap, challenge.__commentCounts)
)
throw Error(`Mismatch in ${challenge.title}. Replaced comments:
${inspect(challenge.__commentCounts)}
Comments in translated text:

View File

@@ -7,6 +7,7 @@ describe('User token widget on settings page,', function () {
});
it('should not render', function () {
// make sure 'Danger Zone' is there so we know the page has rendered
cy.contains('Danger Zone');
cy.get('.user-token').should('not.exist');
});
@@ -19,18 +20,19 @@ describe('User token widget on settings page,', function () {
cy.visit(
'/learn/relational-database/learn-bash-by-building-a-boilerplate/build-a-boilerplate'
);
cy.contains('Click here to start the course').click();
cy.get('[data-cy=start-codeally]').click();
cy.wait(2000);
cy.visit('/settings');
});
it('should render', function () {
// make sure 'Danger Zone' is there so we know the page has rendered
cy.contains('Danger Zone');
cy.get('.user-token').should('have.length', 1);
});
it('should allow you to delete your token', function () {
cy.contains('Delete my user token').click();
cy.get('[data-cy=delete-user-token]').click();
cy.contains('Your user token has been deleted.');
});
});

View File

@@ -14,7 +14,7 @@ Primero, visita el archivo `config/i18n/all-langs.ts` para agregar el idioma a l
- `auditedCerts`: Agrega el nombre del texto como la _clave_, y añade un arreglo de variables de `SuperBlocks.{cert}` como el _value_. Esto le dice al cliente qué certificaciones están totalmente traducidas.
- `i18nextCodes`: Estos son los codigos de idioma ISO para cada lenguaje. Necesitarás añadir el código ISO apropiado para el idioma que estás activando. Estos deben ser únicos para cada lenguaje.
- `langDisplayNames`: Estos son los nombres que se muestran en el selector de idioma en el menú de navegación.
- `langCodes`: These are the language codes used for formatting dates and numbers. Estos deben ser códigos CLDR Unicode en lugar de códigos ISO.
- `langCodes`: Estos son los códigos de idioma utilizados para el formateo de fechas y números. Estos deben ser códigos CLDR Unicode en lugar de códigos ISO.
Por ejemplo, si quisieras habilitar Dothraki como un lenguaje, tus objetos `all-langs.js` deberían verse así:
@@ -131,7 +131,7 @@ CURRICULUM_LOCALE="dothraki"
## Habilitar Videos Localizados
For the video challenges, you need to change a few things. First add the new locale to the GraphQL query in the `client/src/templates/Challenges/video/Show.tsx` file. For example, adding Dothraki to the query:
Para los desafíos de vídeo, tienes que cambiar algunas cosas. Primero agregue la nueva configuración regional a la consulta GraphQL en el archivo `client/src/templates/Challenges/video/Show.tsx`. Por ejemplo, agregando Dothraki a la consulta:
```tsx
query VideoChallenge($slug: String!) {
@@ -146,7 +146,7 @@ For the video challenges, you need to change a few things. First add the new loc
...
```
Then add an id for the new language to any video challenge in an audited block. For example, if `auditedCerts` in `all-langs.ts` includes `scientific-computing-with-python` for `dothraki`, then you must add a `dothraki` entry in `videoLocaleIds`. The frontmatter should then look like this:
Luego, agregue una identificación para el nuevo idioma a cualquier desafío de video en un bloque auditado. Por ejemplo, si `auditedCerts` en `all-langs.ts` incluye `scientific-computing-with-python` para `dothraki`, luego debe agregar una entrada `dothraki` en `videoLocaleIds`. La portada debería verse así:
```yml
videoLocaleIds:
@@ -158,7 +158,7 @@ dashedName: introduction-why-program
---
```
Update the `VideoLocaleIds` interface in `client/src/redux/prop-types` to include the new language.
Actualice la interfaz `VideoLocaleIds` en `client/src/redux/prop-types` para incluir el nuevo idioma.
```ts
export interface VideoLocaleIds {
@@ -169,7 +169,7 @@ export interface VideoLocaleIds {
}
```
And finally update the challenge schema in `curriculum/schema/challengeSchema.js`.
Y finalmente actualice el esquema de desafío en `curriculum/schema/challengeSchema.js`.
```js
videoLocaleIds: Joi.when('challengeType', {
@@ -185,10 +185,10 @@ videoLocaleIds: Joi.when('challengeType', {
## Cargando traducciones
Because the language has not been approved for production, our scripts are not automatically downloading the translations yet. Only staff have the access to directly download the translations - you are welcome to reach out to us in our [contributors chat room](https://chat.freecodecamp.org/channel/contributors), or you can translate the English markdown files locally for testing purposes.
Como el lenguaje no ha sido aprovado para producción, nuestros scripts aún no descargan las traducciones de manera automática. Sólo el personal tiene acceso a la descarga directa de traducciones. Eres bienvenido a comunicarte con nosotros en nuestra [sala de chat para contribuidores](https://chat.freecodecamp.org/channel/contributors), o puedes traducir los archivos markdown localmente con razones de testeo.
Once you have the files, you will need to place them in the correct directory. For the curriculum challenges, you should place the certification folders (i.e. `01-responsive-web-design`) within the `curriculum/challenges/{lang}` directory. For our Dothraki translations, this would be `curriculum/challenges/dothraki`. The client translation `.json` files will go in the `client/i18n/locales/{lang}` directory.
Una vez que poseas los archivos, necesitarás colocarlos en el directorio correcto. Para los retos del plan de estudios, debe colocar las carpetas de certificación (por ejemplo, `01-responsive-web-design`) dentro del directorio `curriculum/challenges/{lang}`. En el caso de nuestras traducciones al dothraki, sería `curriculum/challenges/dothraki`. Los archivos `.json` del cliente deberán colocarse en el directorio `client/i18n/locales/{lang}`.
Once these are in place, you should be able to run `npm run develop` to view your translated version of freeCodeCamp.
Una vez que estos esten en su lugar, deberías ser capaz de correr `npm run develop` para ver tu versión traducida de freeCodeCamp.
> [!ATTENTION] While you may perform translations locally for the purpose of testing, we remind everyone that translations should _not_ be submitted through GitHub and should only be done through Crowdin. Be sure to reset your local codebase after you are done testing.
> [!ATTENTION] Si bien puedes realizar traducciones localmente con motivos de prueba, le recordamos a todos que las traducciones _no_ deben ser enviadas a través de GitHub, estas deben ser enviadas únicamente a traves de Crowdin. Asegúrate de reestablecer tu base de código local despues de que hayas finalizado con las pruebas.

Some files were not shown because too many files have changed in this diff Show More