diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
new file mode 100644
index 00000000000000..652e5dc35e0cd6
--- /dev/null
+++ b/.devcontainer/Dockerfile
@@ -0,0 +1,30 @@
+ARG VARIANT=20.04
+FROM mcr.microsoft.com/devcontainers/base:ubuntu-${VARIANT}
+
+ARG NODE_VERSION=18
+ARG MONGODB_VERSION=6.0.4
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+RUN apt-get update && apt-get install -y sudo && \
+ curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | sudo -E bash - && \
+ sudo apt-get install -y nodejs && \
+ sudo apt-get install -y libcurl4 openssl liblzma5 && \
+ mkdir -p /tmp/mongodb && \
+ cd /tmp/mongodb && \
+ wget -qOmongodb.tgz https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu2004-${MONGODB_VERSION}.tgz && \
+ tar -zxvf mongodb.tgz && \
+ cd mongodb-* && \
+ sudo cp bin/* /usr/local/bin/ && \
+ rm -rf /tmp/mongodb && \
+ sudo mkdir -p /data/db && \
+ sudo chown vscode:vscode -R /data/db
+
+# Setup ENV
+ENV COOKIE_DOMAIN=github.dev
+ENV HOME_LOCATION=https://$CODESPACE_NAME-8000.$GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN
+ENV API_LOCATION=https://$CODESPACE_NAME-3000.$GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN
+ENV CYPRESS_BASE_URL=https://$CODESPACE_NAME-8000.$GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN
+ENV REACT_APP_CHALLENGE_EDITOR_API_LOCATION=https://$CODESPACE_NAME-3200.$GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN
+ENV CHALLENGE_EDITOR_CLIENT_LOCATION=https://$CODESPACE_NAME-3300.$GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN
+
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
new file mode 100644
index 00000000000000..3208a7fcb7c303
--- /dev/null
+++ b/.devcontainer/devcontainer.json
@@ -0,0 +1,24 @@
+{
+ "customizations": {
+ "vscode": {
+ "extensions": [
+ "dbaeumer.vscode-eslint",
+ "esbenp.prettier-vscode",
+ "freeCodeCamp.freecodecamp-dark-vscode-theme"
+ ]
+ }
+ },
+ "dockerFile": "Dockerfile",
+ "forwardPorts": [3000, 8000, 27017],
+ "portsAttributes": {
+ "8000": {
+ "label": "Learn",
+ "onAutoForward": "openPreview"
+ }
+ },
+ "postCreateCommand": "cp sample.env .env && npm ci",
+ // It is more reliable to start these processes oneself
+ // "postStartCommand": "mongod &",
+ // "postAttachCommand": "npm run develop",
+ "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}"
+}
diff --git a/.devcontainer/docs/Dockerfile b/.devcontainer/docs/Dockerfile
new file mode 100644
index 00000000000000..678e47248012f5
--- /dev/null
+++ b/.devcontainer/docs/Dockerfile
@@ -0,0 +1,6 @@
+FROM node:18-alpine
+
+# Install git
+RUN apk add --no-cache git
+
+RUN npm install -g docsify-cli prettier eslint
diff --git a/.devcontainer/docs/devcontainer.json b/.devcontainer/docs/devcontainer.json
new file mode 100644
index 00000000000000..646851488890da
--- /dev/null
+++ b/.devcontainer/docs/devcontainer.json
@@ -0,0 +1,24 @@
+{
+ "context": "../..",
+ "customizations": {
+ "codespaces": {
+ "openFiles": ["docs/how-to-work-on-the-docs-theme.md"]
+ },
+ "vscode": {
+ "extensions": [
+ "dbaeumer.vscode-eslint",
+ "esbenp.prettier-vscode",
+ "freeCodeCamp.freecodecamp-dark-vscode-theme"
+ ]
+ }
+ },
+ "dockerFile": "Dockerfile",
+ "forwardPorts": [3400],
+ "portsAttributes": {
+ "3400": {
+ "label": "Docs",
+ "onAutoForward": "openPreview"
+ }
+ },
+ "postAttachCommand": "npm run docs:serve"
+}
diff --git a/.eslintignore b/.eslintignore
index b69c5e33fcdce0..f73fb4cf88be8d 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -5,6 +5,7 @@ api-server/src/public/**
api-server/lib/**
config/i18n.js
config/certification-settings.js
+config/donation-settings.js
config/superblock-order.js
web/**
docs/**/*.md
diff --git a/.eslintrc.json b/.eslintrc.json
index d0bd51611849c8..c1349259d4ce32 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -55,12 +55,15 @@
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": [
+ "./client/tsconfig.json",
"./tsconfig.json",
+ "./api/tsconfig.json",
"./config/tsconfig.json",
"./tools/ui-components/tsconfig.json",
"./utils/tsconfig.json",
"./web/tsconfig.json",
- "./curriculum-server/tsconfig.json"
+ "./curriculum-server/tsconfig.json",
+ "./cypress/tsconfig.json"
]
},
"extends": [
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index fb4b2175b69b82..6418cf05b658b8 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -17,7 +17,7 @@
*.md
package.json
-package-lock.json
+pnpm-lock.yaml
# -------------------------------------------------
# All files in the root are owned by dev team
@@ -28,7 +28,7 @@ package-lock.json
# --- Owned by none (negate rule above) ---
/package.json
-/package-lock.json
+/pnpm-lock.yaml
# -------------------------------------------------
# Files that need attention from Staff
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 24f617ec82b415..d95ff61a37ec67 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -2,10 +2,10 @@ Checklist:
-- [] I have read [freeCodeCamp's contribution guidelines](https://contribute.freecodecamp.org).
-- [] My pull request has a descriptive title (not a vague title like `Update index.md`)
-- [] My pull request targets the `main` branch of freeCodeCamp.
-- [] I have tested these changes either locally on my machine, or GitPod.
+- [ ] I have read and followed the [contribution guidelines](https://contribute.freecodecamp.org).
+- [ ] I have read and followed the [how to open a pull request guide](https://contribute.freecodecamp.org/#/how-to-open-a-pull-request).
+- [ ] My pull request targets the `main` branch of freeCodeCamp.
+- [ ] I have tested these changes either locally on my machine, or GitPod.
diff --git a/.github/labeler.yml b/.github/labeler.yml
index cae5f5099b469a..1581cb23b3db00 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -23,4 +23,3 @@
- client/i18n/**/*
- config/crowdin/**/*
- config/i18n/**/*
- - tools/crowdin/**/*
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 122a159d1b2df3..b031dbdb42a726 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -1,13 +1,15 @@
name: CI - Run CodeQL Analysis
on:
push:
- branches: [main]
paths-ignore:
- 'docs/**'
+ branches:
+ - 'main'
pull_request:
- branches: [main]
paths-ignore:
- 'docs/**'
+ branches:
+ - 'main'
permissions:
contents: read
@@ -30,10 +32,10 @@ jobs:
language: ['javascript']
steps:
- name: Checkout repository
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
+ uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
- name: Setup CodeQL
- uses: github/codeql-action/init@b2a92eb56d8cb930006a1c6ed86b0782dd8a4297 # v2
+ uses: github/codeql-action/init@32dc499307d133bb5085bae78498c0ac2cf762d5 # v2
with:
languages: ${{ matrix.language }}
- name: Perform Analysis
- uses: github/codeql-action/analyze@b2a92eb56d8cb930006a1c6ed86b0782dd8a4297 # v2
+ uses: github/codeql-action/analyze@32dc499307d133bb5085bae78498c0ac2cf762d5 # v2
diff --git a/.github/workflows/codesee-diagram.yml b/.github/workflows/codesee-diagram.yml
index 007153cbd5aa81..5f03fb8b8bba12 100644
--- a/.github/workflows/codesee-diagram.yml
+++ b/.github/workflows/codesee-diagram.yml
@@ -9,76 +9,15 @@ on:
- 'docs/**'
types: [opened, synchronize, reopened]
+permissions: read-all
+
jobs:
- test_map_action:
+ codesee:
runs-on: ubuntu-20.04
if: ${{ github.actor != 'renovate[bot]' && github.actor != 'camperbot' }}
continue-on-error: true
- name: Run CodeSee Map Analysis
+ name: Analyze the repo with CodeSee
steps:
- - name: checkout
- id: checkout
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
- with:
- repository: ${{ github.event.pull_request.head.repo.full_name }}
- ref: ${{ github.event.pull_request.head.ref }}
- fetch-depth: 0
-
- # codesee-detect-languages has an output with id languages.
- - name: Detect Languages
- id: detect-languages
- uses: Codesee-io/codesee-detect-languages-action@latest
-
- - name: Configure JDK 16
- uses: actions/setup-java@19eeec562b37d29a1ad055b7de9c280bd0906d8d # v3
- if: ${{ fromJSON(steps.detect-languages.outputs.languages).java }}
- with:
- java-version: '16'
- distribution: 'zulu'
-
- # CodeSee Maps Go support uses a static binary so there's no setup step required.
-
- - name: Configure Node.js 16
- uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # tag=v3
- if: ${{ fromJSON(steps.detect-languages.outputs.languages).javascript }}
- with:
- node-version: '16'
-
- - name: Configure Python 3.x
- uses: actions/setup-python@13ae5bb136fac2878aff31522b9efb785519f984 # tag=v4
- if: ${{ fromJSON(steps.detect-languages.outputs.languages).python }}
- with:
- python-version: '3.x'
- architecture: 'x64'
-
- - name: Configure Ruby '3.x'
- uses: ruby/setup-ruby@v1
- if: ${{ fromJSON(steps.detect-languages.outputs.languages).ruby }}
- with:
- ruby-version: '3.0'
-
- # CodeSee Maps Rust support uses a static binary so there's no setup step required.
-
- - name: Generate Map
- id: generate-map
- uses: Codesee-io/codesee-map-action@latest
- with:
- step: map
- github_ref: ${{ github.ref }}
- languages: ${{ steps.detect-languages.outputs.languages }}
-
- - name: Upload Map
- id: upload-map
- uses: Codesee-io/codesee-map-action@latest
- with:
- step: mapUpload
- api_token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }}
- github_ref: ${{ github.ref }}
-
- - name: Insights
- id: insights
- uses: Codesee-io/codesee-map-action@latest
+ - uses: Codesee-io/codesee-action@ab0fd0985bb57b40f5c80661430b8184f5bad31e # v2
with:
- step: insights
- api_token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }}
- github_ref: ${{ github.ref }}
+ codesee-token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }}
diff --git a/.github/workflows/crowdin-download.client-ui.yml b/.github/workflows/crowdin-download.client-ui.yml
index 6a03a3f108f5dd..eb9348bb6966b0 100644
--- a/.github/workflows/crowdin-download.client-ui.yml
+++ b/.github/workflows/crowdin-download.client-ui.yml
@@ -18,7 +18,7 @@ jobs:
steps:
- name: Checkout Source Files
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
+ uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
with:
token: ${{ secrets.CROWDIN_CAMPERBOT_PAT }}
diff --git a/.github/workflows/crowdin-download.curriculum.yml b/.github/workflows/crowdin-download.curriculum.yml
index 5d82cbc62b3eba..d72cda53b62419 100644
--- a/.github/workflows/crowdin-download.curriculum.yml
+++ b/.github/workflows/crowdin-download.curriculum.yml
@@ -17,12 +17,12 @@ jobs:
runs-on: ubuntu-20.04
strategy:
matrix:
- node-version: [16.x]
+ node-version: [18.x]
fail-fast: true
steps:
- name: Checkout Source Files
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
+ uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
with:
token: ${{ secrets.CROWDIN_CAMPERBOT_PAT }}
@@ -276,9 +276,13 @@ jobs:
# Validate the Download #
# All languages should go ABOVE this. #
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v2
+ with:
+ version: 7
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # tag=v3
+ uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with:
node-version: ${{ matrix.node-version }}
@@ -290,15 +294,15 @@ jobs:
- name: Build Source Files
run: |
- echo npm version $(npm -v)
- npm ci
- npm run create:config
- npm run build:curriculum
- npm run build:server
+ echo pnpm version $(pnpm -v)
+ pnpm install
+ pnpm run create:config
+ pnpm run build:curriculum
+ pnpm run build:server
- name: Lint and Format Files
run: |
- npm run format:curriculum
+ pnpm run format:curriculum
# We do not need to run tests because they are run after the PR is created.
diff --git a/.github/workflows/crowdin-download.docs.yml b/.github/workflows/crowdin-download.docs.yml
index c1cbdce22cea7d..5008a30123d9ee 100644
--- a/.github/workflows/crowdin-download.docs.yml
+++ b/.github/workflows/crowdin-download.docs.yml
@@ -18,7 +18,7 @@ jobs:
steps:
- name: Checkout Source Files
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
+ uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
with:
token: ${{ secrets.CROWDIN_CAMPERBOT_PAT }}
diff --git a/.github/workflows/crowdin-upload.client-ui.yml b/.github/workflows/crowdin-upload.client-ui.yml
index fdf22f6bb26b6c..c1157d3243355c 100644
--- a/.github/workflows/crowdin-upload.client-ui.yml
+++ b/.github/workflows/crowdin-upload.client-ui.yml
@@ -18,7 +18,7 @@ jobs:
steps:
- name: Checkout Source Files
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
+ uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
- name: Generate Crowdin Config
uses: freecodecamp/crowdin-action@main
diff --git a/.github/workflows/crowdin-upload.curriculum.yml b/.github/workflows/crowdin-upload.curriculum.yml
index 0453108db912c8..3f1cd1c3eabc0f 100644
--- a/.github/workflows/crowdin-upload.curriculum.yml
+++ b/.github/workflows/crowdin-upload.curriculum.yml
@@ -18,7 +18,7 @@ jobs:
steps:
- name: Checkout Source Files
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
+ uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
- name: Generate Crowdin Config
uses: freecodecamp/crowdin-action@main
diff --git a/.github/workflows/crowdin-upload.docs.yml b/.github/workflows/crowdin-upload.docs.yml
index ead433d6439e06..c7eaf0ff98b5da 100644
--- a/.github/workflows/crowdin-upload.docs.yml
+++ b/.github/workflows/crowdin-upload.docs.yml
@@ -18,7 +18,7 @@ jobs:
steps:
- name: Checkout Source Files
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
+ uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
- name: Generate Crowdin Config
uses: freecodecamp/crowdin-action@main
diff --git a/.github/workflows/e2e-mobile.yml b/.github/workflows/e2e-mobile.yml
index 8e911c44f5528f..5a558be91c3d62 100644
--- a/.github/workflows/e2e-mobile.yml
+++ b/.github/workflows/e2e-mobile.yml
@@ -4,31 +4,42 @@ on:
# push:
# paths-ignore:
# - 'docs/**'
- # branches-ignore:
- # - 'renovate/**'
+ # branches:
+ # - 'main'
# pull_request:
# paths-ignore:
# - 'docs/**'
+ # branches:
+ # - 'main'
+ # - 'next-**'
jobs:
mobile-test:
name: Test curriculum for mobile app
runs-on: ubuntu-20.04
+ strategy:
+ matrix:
+ node-version: [18.x]
steps:
- name: Checkout Source Files
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
+ uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
- name: Checkout mobile
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
+ uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
with:
repository: freeCodeCamp/mobile
path: mobile
- - name: Use Node.js 16.x
- uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # tag=v3
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v2
with:
- node-version: 16.x
+ version: 7
+
+ - name: Use Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
+ with:
+ node-version: ${{ matrix.node-version }}
- name: Setup Flutter 3.3.x
uses: subosito/flutter-action@dbf1fa04f4d2e52c33185153d06cdb5443aa189d # tag=v2
@@ -44,9 +55,9 @@ jobs:
- name: Install and Build
run: |
- npm ci
- npm run create:config
- npm run build:curriculum
+ pnpm install
+ pnpm run create:config
+ pnpm run build:curriculum
- name: Generate mobile test files
run: |
diff --git a/.github/workflows/e2e-third-party.yml b/.github/workflows/e2e-third-party.yml
index 96fce5c650faac..edeb766e6ca227 100644
--- a/.github/workflows/e2e-third-party.yml
+++ b/.github/workflows/e2e-third-party.yml
@@ -5,7 +5,7 @@ name: CI - E2E - 3rd party donation tests
on:
push:
branches:
- - 'prod-*'
+ - 'prod-**'
paths-ignore:
- 'docs/**'
@@ -13,6 +13,9 @@ jobs:
do-everything:
name: Build & Test
runs-on: ubuntu-20.04
+ strategy:
+ matrix:
+ node-version: [18.x]
services:
mongodb:
image: mongo:4.4
@@ -26,18 +29,23 @@ jobs:
steps:
- name: Checkout Source Files
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
+ uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
- name: Checkout client-config
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
+ uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
with:
repository: freeCodeCamp/client-config
path: client-config
- - name: Use Node.js 16.x
- uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # tag=v3
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v2
with:
- node-version: 16.x
+ version: 7
+
+ - name: Use Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
+ with:
+ node-version: ${{ matrix.node-version }}
- name: Set freeCodeCamp Environment Variables
run: |
@@ -49,10 +57,10 @@ jobs:
- name: Install and Build
run: |
- npm ci
- npm run build
+ pnpm install
+ pnpm run build
- name: Seed Database
- run: npm run seed
+ run: pnpm run seed
- name: Move serve.json to Public Folder
run: cp client-config/serve.json client/public/serve.json
@@ -60,10 +68,10 @@ jobs:
uses: cypress-io/github-action@v4
with:
record: ${{ env.CYPRESS_RECORD_KEY != 0 }}
- start: npm run start-ci
+ start: pnpm run start-ci
wait-on: http://localhost:8000
wait-on-timeout: 1200
config: baseUrl=http://localhost:8000
browser: chrome
- spec: cypress/e2e/third-party/*.js
+ spec: cypress/e2e/third-party/*.{js,ts}
diff --git a/.github/workflows/e2e-web.yml b/.github/workflows/e2e-web.yml
index c014b5e96e2375..750e439d3bf8fa 100644
--- a/.github/workflows/e2e-web.yml
+++ b/.github/workflows/e2e-web.yml
@@ -3,42 +3,50 @@ on:
push:
paths-ignore:
- 'docs/**'
- branches-ignore:
- - 'renovate/**'
- - 'next-api'
+ branches:
+ - 'main'
pull_request:
paths-ignore:
- 'docs/**'
- branches-ignore:
- - 'next-api'
+ branches:
+ - 'main'
+ - 'next-**'
jobs:
build-client:
name: Build
runs-on: ubuntu-20.04
+ strategy:
+ matrix:
+ node-version: [18.x]
steps:
- name: Checkout Source Files
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
+ uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
- name: Checkout client-config
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
+ uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
with:
repository: freeCodeCamp/client-config
path: client-config
- - name: Use Node.js 16.x
- uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # tag=v3
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v2
+ with:
+ version: 7
+
+ - name: Use Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with:
- node-version: 16.x
+ node-version: ${{ matrix.node-version }}
- name: Set freeCodeCamp Environment Variables
run: cp sample.env .env
- name: Install and Build
run: |
- npm ci
- npm run build
+ pnpm install
+ pnpm run build
- name: Move serve.json to Public Folder
run: cp client-config/serve.json client/public/serve.json
@@ -48,13 +56,13 @@ jobs:
run: tar -cf client-artifact.tar client/public
- name: Upload Client Artifact
- uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # tag=v3
+ uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3
with:
name: client-artifact
path: client-artifact.tar
- name: Upload Webpack Stats
- uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # tag=v3
+ uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3
with:
name: webpack-stats
path: client/public/stats.json
@@ -67,14 +75,14 @@ jobs:
fail-fast: false
matrix:
browsers: [chrome, firefox, electron]
- node-version: [16.x]
+ node-version: [18.x]
include:
- browsers: electron
spec: cypress/e2e/default/learn/challenges/projects.js
- browsers: chrome
- spec: cypress/e2e/default/**/*.js
+ spec: cypress/e2e/default/**/*.{js,ts}
- browsers: firefox
- spec: cypress/e2e/default/**/*.js
+ spec: cypress/e2e/default/**/*.{js,ts}
services:
mongodb:
image: mongo:4.4
@@ -93,9 +101,9 @@ jobs:
echo "GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV
- name: Checkout Source Files
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
+ uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
- - uses: actions/download-artifact@9782bd6a9848b53b110e712e20e42d89988822b7 # tag=v3
+ - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3
with:
name: client-artifact
@@ -112,8 +120,13 @@ jobs:
sudo mv /usr/bin/firefox /usr/bin/firefox_old
sudo ln -s /opt/firefox/firefox /usr/bin/firefox
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v2
+ with:
+ version: 7
+
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # tag=v3
+ uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with:
node-version: ${{ matrix.node-version }}
@@ -122,19 +135,19 @@ jobs:
- name: Install and Build
run: |
- npm ci
- npm run create:config
- npm run build:curriculum
- npm run build:server
+ pnpm install
+ pnpm run create:config
+ pnpm run build:curriculum
+ pnpm run build:server
- name: Seed Database
- run: npm run seed
+ run: pnpm run seed
- name: Cypress run
uses: cypress-io/github-action@v4
with:
record: ${{ env.CYPRESS_RECORD_KEY != 0 }}
- start: npm run start-ci
+ start: pnpm run start-ci
wait-on: http://localhost:8000
wait-on-timeout: 1200
config: baseUrl=http://localhost:8000
diff --git a/.github/workflows/github-autoclose.yml b/.github/workflows/github-autoclose.yml
index 1f3bf8a804b2f2..152055a3223725 100644
--- a/.github/workflows/github-autoclose.yml
+++ b/.github/workflows/github-autoclose.yml
@@ -10,7 +10,7 @@ jobs:
autoclose:
runs-on: ubuntu-20.04
steps:
- - uses: actions/github-script@d556feaca394842dc55e4734bf3bb9f685482fa0 # tag=v6
+ - uses: actions/github-script@98814c53be79b1d30f795b907e553d8679345975 # v6
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
diff --git a/.github/workflows/github-no-i18n-via-prs.yml b/.github/workflows/github-no-i18n-via-prs.yml
index ba47629262e884..e50b5f7d2937ae 100644
--- a/.github/workflows/github-no-i18n-via-prs.yml
+++ b/.github/workflows/github-no-i18n-via-prs.yml
@@ -15,7 +15,7 @@ jobs:
has-translation:
runs-on: ubuntu-20.04
steps:
- - uses: actions/github-script@d556feaca394842dc55e4734bf3bb9f685482fa0 # tag=v6
+ - uses: actions/github-script@98814c53be79b1d30f795b907e553d8679345975 # v6
with:
github-token: ${{secrets.CAMPERBOT_NO_TRANSLATE}}
script: |
diff --git a/.github/workflows/github-spam.yml b/.github/workflows/github-spam.yml
index ccfe1ee42491d4..b086d0458834dd 100644
--- a/.github/workflows/github-spam.yml
+++ b/.github/workflows/github-spam.yml
@@ -8,7 +8,7 @@ jobs:
is-spam:
runs-on: ubuntu-20.04
steps:
- - uses: actions/github-script@d556feaca394842dc55e4734bf3bb9f685482fa0 # tag=v6
+ - uses: actions/github-script@98814c53be79b1d30f795b907e553d8679345975 # v6
with:
github-token: ${{secrets.CAMPERBOT_NO_TRANSLATE}}
script: |
diff --git a/.github/workflows/i18n-validate-builds.yml b/.github/workflows/i18n-validate-builds.yml
index 73dd3d33b84512..c97761262103ad 100644
--- a/.github/workflows/i18n-validate-builds.yml
+++ b/.github/workflows/i18n-validate-builds.yml
@@ -7,18 +7,20 @@ on:
jobs:
ci:
name: Validate i18n Builds
- runs-on: ubuntu-latest
-
+ runs-on: ubuntu-20.04
strategy:
matrix:
- node-version: [16.x]
+ node-version: [18.x]
steps:
- name: Checkout Source Files
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
-
- - name: Use Node.js v${{ matrix.node-version }}
- uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # tag=v3
+ uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v2
+ with:
+ version: 7
+ - name: Use Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with:
node-version: ${{ matrix.node-version }}
@@ -26,7 +28,7 @@ jobs:
run: cp sample.env .env
- name: Install Dependencies
- run: npm ci
+ run: pnpm install
- name: Validate Challenge Files
- run: npm run audit-challenges
+ run: pnpm run audit-challenges
diff --git a/.github/workflows/i18n-validate-prs.yml b/.github/workflows/i18n-validate-prs.yml
index f1068db0f1af55..c858003d5f69c5 100644
--- a/.github/workflows/i18n-validate-prs.yml
+++ b/.github/workflows/i18n-validate-prs.yml
@@ -7,19 +7,22 @@ on:
jobs:
ci:
name: Validate i18n Builds
- runs-on: ubuntu-latest
# run only on PRs that camperbot opens with title that matches the curriculum sync
if: ${{ github.event.pull_request.user.login == 'camperbot' && contains(github.event.pull_request.title, 'chore(i18n,learn)') }}
+ runs-on: ubuntu-20.04
strategy:
matrix:
- node-version: [16.x]
+ node-version: [18.x]
steps:
- name: Checkout Source Files
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
-
- - name: Use Node.js v${{ matrix.node-version }}
- uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # tag=v3
+ uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v2
+ with:
+ version: 7
+ - name: Use Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with:
node-version: ${{ matrix.node-version }}
@@ -27,16 +30,16 @@ jobs:
run: cp sample.env .env
- name: Install Dependencies
- run: npm ci
+ run: pnpm install
- name: Validate Challenge Files
id: validate
- run: npm run audit-challenges
+ run: pnpm run audit-challenges
- name: Create Comment
# Run if the validate challenge files step fails, specifically. Note that we need the failure() call for this step to trigger if the action fails.
if: ${{ failure() && steps.validate.conclusion == 'failure' }}
- uses: actions/github-script@d556feaca394842dc55e4734bf3bb9f685482fa0 # tag=v6
+ uses: actions/github-script@98814c53be79b1d30f795b907e553d8679345975 # v6
with:
github-token: ${{secrets.CAMPERBOT_NO_TRANSLATE}}
script: |
diff --git a/.github/workflows/node.js-find-unused.yml b/.github/workflows/node.js-find-unused.yml
index 3a70da8646461d..4817ee3adfa6aa 100644
--- a/.github/workflows/node.js-find-unused.yml
+++ b/.github/workflows/node.js-find-unused.yml
@@ -17,14 +17,17 @@ jobs:
strategy:
fail-fast: false
matrix:
- node-version: [16.x]
+ node-version: [18.x]
steps:
- name: Checkout Source Files
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
-
+ uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v2
+ with:
+ version: 7
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # tag=v3
+ uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with:
node-version: ${{ matrix.node-version }}
@@ -35,6 +38,6 @@ jobs:
- name: Run Checks
run: |
- echo npm version $(npm -v)
- npm ci
- npm run knip
+ echo pnpm version $(pnpm -v)
+ pnpm install
+ pnpm run knip
diff --git a/.github/workflows/node.js-tests-upcoming.yml b/.github/workflows/node.js-tests-upcoming.yml
index 8baa16f7ad37c0..7f9a1869c28765 100644
--- a/.github/workflows/node.js-tests-upcoming.yml
+++ b/.github/workflows/node.js-tests-upcoming.yml
@@ -2,14 +2,20 @@ name: CI - Node.js Test Upcoming
env:
NODE_OPTIONS: '--max_old_space_size=6144'
on:
+ # Run on push events, but only for the below branches
push:
branches:
- # Treat the below branches as special case for working on workflows
- - actions-**
- - upcoming-**
+ - 'main'
+ - 'prod-**'
+ # Run on pull requests, but only for the below targets
+ pull_request:
+ branches:
+ - 'main'
+ - 'next-**'
schedule:
# run this Action every 14 days
- cron: '0 * */14 * *'
+ # Run on demand
workflow_dispatch:
permissions:
@@ -19,18 +25,20 @@ jobs:
lint:
name: Lint
runs-on: ubuntu-20.04
-
strategy:
- fail-fast: false
matrix:
- node-version: [16.x]
+ node-version: [18.x]
+ fail-fast: false
steps:
- name: Checkout Source Files
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
-
+ uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v2
+ with:
+ version: 7
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # tag=v3
+ uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with:
node-version: ${{ matrix.node-version }}
@@ -43,12 +51,12 @@ jobs:
- name: Lint Source Files
run: |
- npm ci
- npm run create:config
+ pnpm install
+ pnpm run create:config
npm i --prefix=curriculum-server
npm i --prefix=web
- npm run build:curriculum
- npm run lint
+ pnpm run build:curriculum
+ pnpm run lint
test:
name: Test
@@ -58,14 +66,17 @@ jobs:
strategy:
fail-fast: false
matrix:
- node-version: [16.x]
+ node-version: [18.x]
steps:
- name: Checkout Source Files
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
-
+ uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v2
+ with:
+ version: 7
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # tag=v3
+ uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with:
node-version: ${{ matrix.node-version }}
@@ -78,9 +89,9 @@ jobs:
- name: Install Dependencies
run: |
- npm ci
- npm run create:config
- npm run build:curriculum
+ pnpm install
+ pnpm run create:config
+ pnpm run build:curriculum
- name: Run Tests
- run: npm test
+ run: pnpm test
diff --git a/.github/workflows/node.js-tests.yml b/.github/workflows/node.js-tests.yml
index f6d59c6ec7e439..21b8c0e498a324 100644
--- a/.github/workflows/node.js-tests.yml
+++ b/.github/workflows/node.js-tests.yml
@@ -1,14 +1,21 @@
name: CI - Node.js Test Current
env:
NODE_OPTIONS: '--max_old_space_size=6144'
+
on:
+ # Run on push events, but only for the below branches
push:
- branches-ignore:
- - 'renovate/**'
- - 'next-api'
+ branches:
+ - 'main'
+ - 'prod-**'
+ # Run on pull requests, but only for the below targets
pull_request:
- branches-ignore:
- - 'next-api'
+ branches:
+ - 'main'
+ - 'next-**'
+ # Run on Merge Queue
+ merge_group:
+ types: [checks_requested]
permissions:
contents: read
@@ -17,26 +24,30 @@ jobs:
lint:
name: Lint
runs-on: ubuntu-20.04
-
strategy:
- fail-fast: false
matrix:
- node-version: [16.x]
+ node-version: [18.x]
+ fail-fast: false
steps:
- name: Checkout Source Files
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
+ uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
- name: Check number of lockfiles
run: |
- if [ $(find . -name 'package-lock.json' | grep -vc -e 'node_modules') -gt 1 ]
+ if [ $(find . -name 'package-lock.json' | grep -vc -e 'node_modules') -gt 0 ]
then
- echo 'Error: found too many lockfiles in the repository'
+ echo -e 'Error: found package-lock files in the repository.\nWe use pnpm workspaces to manage packages so all dependencies should be added via pnpm add'
exit 1
fi
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v2
+ with:
+ version: 7
+
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # tag=v3
+ uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with:
node-version: ${{ matrix.node-version }}
@@ -50,13 +61,13 @@ jobs:
# currently, built as workspaces.
- name: Lint Source Files
run: |
- echo npm version $(npm -v)
- npm ci
- npm run create:config
+ echo pnpm version $(pnpm -v)
+ pnpm install
+ pnpm run create:config
npm i --prefix=curriculum-server
npm i --prefix=web
- npm run build:curriculum
- npm run lint
+ pnpm run build:curriculum
+ pnpm run lint
test:
name: Test
@@ -66,14 +77,19 @@ jobs:
strategy:
fail-fast: false
matrix:
- node-version: [16.x]
+ node-version: [18.x]
steps:
- name: Checkout Source Files
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
+ uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
+
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v2
+ with:
+ version: 7
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # tag=v3
+ uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with:
node-version: ${{ matrix.node-version }}
@@ -84,13 +100,13 @@ jobs:
- name: Install Dependencies
run: |
- echo npm version $(npm -v)
- npm ci
- npm run create:config
- npm run build:curriculum
+ echo pnpm version $(pnpm -v)
+ pnpm install
+ pnpm run create:config
+ pnpm run build:curriculum
- name: Run Tests
- run: npm test
+ run: pnpm test
test-upcoming:
name: Test Upcoming Changes
@@ -100,14 +116,19 @@ jobs:
strategy:
fail-fast: false
matrix:
- node-version: [16.x]
+ node-version: [18.x]
steps:
- name: Checkout Source Files
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
+ uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
+
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v2
+ with:
+ version: 7
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # tag=v3
+ uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with:
node-version: ${{ matrix.node-version }}
@@ -119,13 +140,13 @@ jobs:
- name: Install Dependencies
run: |
- echo npm version $(npm -v)
- npm ci
- npm run create:config
- npm run build:curriculum
+ echo pnpm version $(pnpm -v)
+ pnpm install
+ pnpm run create:config
+ pnpm run build:curriculum
- name: Run Tests
- run: npm test
+ run: pnpm test
test-localization:
name: Localize
@@ -135,15 +156,20 @@ jobs:
strategy:
fail-fast: false
matrix:
- node-version: [16.x]
+ node-version: [18.x]
locale: [chinese, espanol]
steps:
- name: Checkout Source Files
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
+ uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
+
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v2
+ with:
+ version: 7
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # tag=v3
+ uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with:
node-version: ${{ matrix.node-version }}
@@ -157,13 +183,13 @@ jobs:
CURRICULUM_LOCALE: ${{ matrix.locale }}
CLIENT_LOCALE: ${{ matrix.locale }}
run: |
- echo npm version $(npm -v)
- npm ci
- npm run create:config
- npm run build:curriculum
+ echo pnpm version $(pnpm -v)
+ pnpm install
+ pnpm run create:config
+ pnpm run build:curriculum
- name: Run Tests
env:
CURRICULUM_LOCALE: ${{ matrix.locale }}
CLIENT_LOCALE: ${{ matrix.locale }}
- run: npm test
+ run: pnpm test
diff --git a/.github/workflows/update-license.yaml b/.github/workflows/update-license.yaml
new file mode 100644
index 00000000000000..0c59424e025213
--- /dev/null
+++ b/.github/workflows/update-license.yaml
@@ -0,0 +1,24 @@
+name: Update copyright year(s) in license file
+
+on:
+ workflow_dispatch:
+ schedule:
+ - cron: '0 3 1 1 *'
+
+jobs:
+ run:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
+ with:
+ fetch-depth: 0
+ - uses: FantasticFiasco/action-update-license-year@26ffac173f956c25f7467aa8e6f750eed24a1b7a # v2
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ path: |
+ README.md
+ LICENSE
+ commitTitle: 'docs: update copyright years'
+ prTitle: 'docs: update copyright years'
+ prBody: It's that time of the year, let's update the license
+ labels: 'status: waiting review'
diff --git a/.gitignore b/.gitignore
index 4c468c511bb9ce..60a4aafe9c9f09 100644
--- a/.gitignore
+++ b/.gitignore
@@ -165,6 +165,7 @@ config/client/test-evaluator.json
config/curriculum.json
config/i18n.js
config/certification-settings.js
+config/donation-settings.js
config/superblock-order.js
config/superblock-order.test.js
@@ -174,6 +175,10 @@ utils/block-nameify.test.js
utils/slugs.js
utils/slugs.test.js
utils/index.js
+utils/get-lines.js
+utils/get-lines.test.js
+utils/validate.js
+utils/validate.test.js
### vim ###
# Swap
@@ -213,6 +218,10 @@ client/static/_redirects
client/static/mobile
client/static/curriculum-data
client/i18n/locales/**/trending.json
+client/src/components/Donation/types.js
### UI Components ###
tools/ui-components/dist
+
+### API ###
+api/**/*.js
diff --git a/.gitpod.Dockerfile b/.gitpod.Dockerfile
new file mode 100644
index 00000000000000..54b67b14d533c1
--- /dev/null
+++ b/.gitpod.Dockerfile
@@ -0,0 +1,8 @@
+FROM gitpod/workspace-mongodb:latest
+
+# from https://www.gitpod.io/docs/introduction/languages/javascript#node-versions
+RUN bash -c 'VERSION="lts/*" \
+ && source $HOME/.nvm/nvm.sh && nvm install $VERSION \
+ && nvm use $VERSION && nvm alias default $VERSION'
+
+RUN echo "nvm use default &>/dev/null" >> ~/.bashrc.d/51-nvm-fix
diff --git a/.gitpod.yml b/.gitpod.yml
index d69ba77091ed03..4d8161af73e58e 100644
--- a/.gitpod.yml
+++ b/.gitpod.yml
@@ -1,4 +1,5 @@
-image: gitpod/workspace-mongodb
+image:
+ file: .gitpod.Dockerfile
ports:
- port: 27017 # mongodb
onOpen: ignore
@@ -43,28 +44,28 @@ tasks:
# so we should put all the heavy initialization here
init: >
cp sample.env .env &&
- npm ci &&
- gp sync-done npm-ci &&
+ pnpm install &&
+ gp sync-done pnpm-install &&
gp ports await 27017 &&
- npm run seed &&
+ pnpm run seed &&
mongo --eval "db.fsyncLock(); db.fsyncUnlock()"
command: >
- npm run create:config &&
- npm run build:curriculum &&
+ pnpm run create:config &&
+ pnpm run build:curriculum &&
gp ports await 27017 &&
- npm run develop:server
+ pnpm run develop:server
- name: client
before: export HOME_LOCATION=$(gp url 8000) && export API_LOCATION=$(gp url 3000) && export CYPRESS_BASE_URL=$(gp url 8000)
init: >
cd ./client &&
- gp sync-await npm-ci &&
- npm run predevelop &&
+ gp sync-await pnpm-install &&
+ pnpm run predevelop &&
cd ..
command: >
gp ports await 3000 &&
cd ./client &&
- npm run develop -- -H '0.0.0.0'
+ pnpm run develop -- -H '0.0.0.0'
openMode: split-right
github:
diff --git a/.lintstagedrc.js b/.lintstagedrc.js
index 9e057a416e9f1b..c32ba6ed2127d8 100644
--- a/.lintstagedrc.js
+++ b/.lintstagedrc.js
@@ -43,7 +43,7 @@ module.exports = {
if (files.length > 10) {
completedStages.add('markdown');
- return 'npm run lint:challenges';
+ return 'pnpm run lint:challenges';
} else {
return files.map(
filename => `node ./tools/scripts/lint/index.js '${filename}'`
diff --git a/.npmrc b/.npmrc
index 9ce0b728d94416..9483f4e6f49d15 100644
--- a/.npmrc
+++ b/.npmrc
@@ -1 +1,5 @@
-CYPRESS_INSTALL_BINARY=0
+auto-install-peers=true
+strict-peer-dependencies=true
+# TODO: consider reworking the scripts to avoid usage of pre/post scripts
+enable-pre-post-scripts=true
+use-node-version=18.14.2
diff --git a/.prettierignore b/.prettierignore
index 2d392969792346..4ba5da92add66d 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -8,6 +8,7 @@ curriculum/challenges/**/*
config/**/*.json
config/i18n.js
config/certification-settings.js
+config/donation-settings.js
config/superblock-order.js
config/superblock-order.test.js
utils/block-nameify.js
@@ -15,7 +16,12 @@ utils/block-nameify.test.js
utils/slugs.js
utils/slugs.test.js
utils/index.js
-**/package-lock.json
+utils/get-lines.js
+utils/get-lines.test.js
+utils/validate.js
+utils/validate.test.js
+pnpm-lock.yaml
web/.next
curriculum-server/data/curriculum.json
docs/**/*.md
+client/src/components/Donation/types.js
diff --git a/LICENSE.md b/LICENSE.md
index 12e9c3b39b3ed5..6eadad76438d3d 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,6 +1,6 @@
BSD 3-Clause License
-Copyright (c) 2022, freeCodeCamp.
+Copyright (c) 2023, freeCodeCamp.
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/README.md b/README.md
index 773490dac9ba12..c71509e222edcb 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@
## freeCodeCamp.org's open-source codebase and curriculum
-[freeCodeCamp.org](https://www.freecodecamp.org) is a friendly community where you can learn to code for free. It is run by a [donor-supported 501(c)(3) nonprofit](https://www.freecodecamp.org/donate) to help millions of busy adults transition into tech. Our community has already helped more than 40,000 people get their first developer job.
+[freeCodeCamp.org](https://www.freecodecamp.org) is a friendly community where you can learn to code for free. It is run by a [donor-supported 501(c)(3) charity](https://www.freecodecamp.org/donate) to help millions of busy adults transition into tech. Our community has already helped more than 40,000 people get their first developer job.
Our full-stack web development and machine learning curriculum is completely free and self-paced. We have thousands of interactive coding challenges to help you expand your skills.
@@ -190,7 +190,7 @@ The general platform status for all our applications is available at [`status.fr
### License
-Copyright © 2022 freeCodeCamp.org
+Copyright © 2023 freeCodeCamp.org
The content of this repository is bound by the following licenses:
diff --git a/api-server/ecosystem.config.js b/api-server/ecosystem.config.js
index 42c4ff402d148e..d5f8d082bfd07a 100644
--- a/api-server/ecosystem.config.js
+++ b/api-server/ecosystem.config.js
@@ -3,13 +3,14 @@ const path = require('path');
const dotenv = require('dotenv');
-const filePath = path.resolve('..', '.env');
+const filePath = path.resolve(__dirname, '..', '.env');
const env = dotenv.parse(fs.readFileSync(filePath));
module.exports = {
apps: [
{
script: `./lib/production-start.js`,
+ cwd: __dirname,
env,
max_memory_restart: '600M',
instances: 'max',
diff --git a/api-server/package.json b/api-server/package.json
index 7be433231a72d9..060280b2c282f4 100644
--- a/api-server/package.json
+++ b/api-server/package.json
@@ -6,7 +6,7 @@
"private": true,
"engines": {
"node": ">=16",
- "npm": ">=8"
+ "pnpm": "7"
},
"repository": {
"type": "git",
@@ -29,7 +29,8 @@
},
"dependencies": {
"@freecodecamp/loopback-component-passport": "1.2.0",
- "@sentry/node": "6.19.7",
+ "@sentry/node": "7.37.1",
+ "@sentry/tracing": "7.37.1",
"accepts": "1.3.8",
"axios": "0.23.0",
"bad-words": "3.0.4",
@@ -45,6 +46,7 @@
"dedent": "0.7.0",
"dotenv": "6.2.0",
"express-flash": "0.0.2",
+ "express-rate-limit": "^6.7.0",
"express-session": "1.17.3",
"express-validator": "6.14.1",
"helmet": "3.23.3",
@@ -60,12 +62,14 @@
"mongodb": "3.6.9",
"morgan": "1.10.0",
"nanoid": "3.3.4",
+ "node-fetch": "^2.6.7",
"nodemailer-ses-transport": "1.5.1",
"passport": "0.4.1",
"passport-auth0": "1.4.2",
"passport-local": "1.0.0",
"passport-mock-strategy": "2.0.0",
"query-string": "6.14.0",
+ "rate-limit-mongo": "^2.3.2",
"rx": "4.1.0",
"stripe": "8.205.0",
"uuid": "3.4.0",
diff --git a/api-server/src/common/models/user.js b/api-server/src/common/models/user.js
index 31efb6a04d5fc3..028ffcc7dc96ee 100644
--- a/api-server/src/common/models/user.js
+++ b/api-server/src/common/models/user.js
@@ -162,6 +162,8 @@ export default function initializeUser(User) {
User.definition.properties.rand.default = getRandomNumber;
// increase user accessToken ttl to 900 days
User.settings.ttl = 900 * 24 * 60 * 60 * 1000;
+ // Sets ttl to 900 days for mobile login created access tokens
+ User.settings.maxTTL = 900 * 24 * 60 * 60 * 1000;
// username should not be in blocklist
User.validatesExclusionOf('username', {
@@ -341,6 +343,21 @@ export default function initializeUser(User) {
);
};
+ User.prototype.mobileLoginByRequest = function mobileLoginByRequest(
+ req,
+ res
+ ) {
+ return new Promise((resolve, reject) =>
+ this.createAccessToken({}, (err, accessToken) => {
+ if (err) {
+ return reject(err);
+ }
+ setAccessTokenToResponse({ accessToken }, req, res);
+ return resolve(accessToken);
+ })
+ );
+ };
+
User.afterRemote('logout', function ({ req, res }, result, next) {
removeCookies(req, res);
next();
diff --git a/api-server/src/development-start.js b/api-server/src/development-start.js
index 356650780918a9..4b11c906447dfb 100644
--- a/api-server/src/development-start.js
+++ b/api-server/src/development-start.js
@@ -30,7 +30,7 @@ if (process.env.WEBHOOK_PROXY_URL) {
nodemon({
ext: 'js json',
// --silent squashes an ELIFECYCLE error when the server exits
- exec: 'npm run --silent babel-dev-server',
+ exec: 'pnpm run --silent babel-dev-server',
watch: path.resolve(__dirname, './server'),
spawn: true,
env: {
diff --git a/api-server/src/server/boot/authentication.js b/api-server/src/server/boot/authentication.js
index b55a90cdc49340..c7589da53cefc5 100644
--- a/api-server/src/server/boot/authentication.js
+++ b/api-server/src/server/boot/authentication.js
@@ -2,10 +2,9 @@ import dedent from 'dedent';
import { check } from 'express-validator';
import jwt from 'jsonwebtoken';
import passport from 'passport';
+import fetch from 'node-fetch';
import { isEmail } from 'validator';
-
import { jwtSecret } from '../../../../config/secrets';
-
import { decodeEmail } from '../../common/utils';
import {
createPassportCallbackAuthenticator,
@@ -14,7 +13,11 @@ import {
} from '../component-passport';
import { wrapHandledError } from '../utils/create-handled-error.js';
import { removeCookies } from '../utils/getSetAccessToken';
-import { ifUserRedirectTo, ifNoUserRedirectHome } from '../utils/middleware';
+import {
+ ifUserRedirectTo,
+ ifNoUserRedirectHome,
+ ifNotMobileRedirect
+} from '../utils/middleware';
import { getRedirectParams } from '../utils/redirection';
import { createDeleteUserToken } from '../middlewares/user-token';
@@ -34,6 +37,7 @@ module.exports = function enableAuthentication(app) {
// enable loopback access control authentication. see:
// loopback.io/doc/en/lb2/Authentication-authorization-and-permissions.html
app.enableAuth();
+ const ifNotMobile = ifNotMobileRedirect();
const ifUserRedirect = ifUserRedirectTo();
const ifNoUserRedirect = ifNoUserRedirectHome();
const devSaveAuthCookies = devSaveResponseAuthCookies();
@@ -87,6 +91,8 @@ module.exports = function enableAuthentication(app) {
createGetPasswordlessAuth(app)
);
+ api.get('/mobile-login', ifNotMobile, ifUserRedirect, mobileLogin(app));
+
app.use(api);
};
@@ -188,3 +194,53 @@ function createGetPasswordlessAuth(app) {
);
};
}
+
+function mobileLogin(app) {
+ const {
+ models: { User }
+ } = app;
+ return async function getPasswordlessAuth(req, res, next) {
+ try {
+ const auth0Res = await fetch(
+ `https://${process.env.AUTH0_DOMAIN}/userinfo`,
+ {
+ headers: { Authorization: req.headers.authorization }
+ }
+ );
+
+ if (!auth0Res.ok) {
+ return next(
+ wrapHandledError(new Error('Invalid Auth0 token'), {
+ type: 'danger',
+ message: 'We could not log you in, please try again in a moment.',
+ status: auth0Res.status
+ })
+ );
+ }
+
+ const { email } = await auth0Res.json();
+
+ if (!isEmail(email)) {
+ return next(
+ wrapHandledError(new TypeError('decoded email is invalid'), {
+ type: 'danger',
+ message: 'The email is incorrectly formatted',
+ status: 400
+ })
+ );
+ }
+
+ User.findOne$({ where: { email } })
+ .do(async user => {
+ if (!user) {
+ user = await User.create({ email });
+ }
+ await user.mobileLoginByRequest(req, res);
+ res.end();
+ })
+ .subscribe(() => {}, next);
+ } catch (err) {
+ next(err);
+ }
+ };
+}
diff --git a/api-server/src/server/boot/explorer.js b/api-server/src/server/boot/explorer.js
index a78447e3475ef6..8de921c416ed7c 100644
--- a/api-server/src/server/boot/explorer.js
+++ b/api-server/src/server/boot/explorer.js
@@ -14,7 +14,7 @@ module.exports = function mountLoopBackExplorer(app) {
// Do not print any message when the project is used as a component.
app.once('started', function () {
log(
- 'Run `npm install loopback-component-explorer` to enable ' +
+ 'Run `pnpm add loopback-component-explorer` to enable ' +
'the LoopBack explorer'
);
});
diff --git a/api-server/src/server/boot/settings.js b/api-server/src/server/boot/settings.js
index d1a4b4006cf6e1..e93f32dff8327b 100644
--- a/api-server/src/server/boot/settings.js
+++ b/api-server/src/server/boot/settings.js
@@ -281,12 +281,6 @@ function handleInvalidUpdate(res) {
function updateUserFlag(req, res, next) {
const { user, body: update } = req;
const allowedKeys = [
- 'theme',
- 'sound',
- 'keyboardShortcuts',
- 'isHonest',
- 'portfolio',
- 'sendQuincyEmail',
'isGithub',
'isLinkedIn',
'isTwitter',
diff --git a/api-server/src/server/boot/user.js b/api-server/src/server/boot/user.js
index 9d11ea2459fa06..339dd258e28cfc 100644
--- a/api-server/src/server/boot/user.js
+++ b/api-server/src/server/boot/user.js
@@ -93,22 +93,21 @@ function deleteUserTokenResponse(req, res) {
}
function createReadSessionUser(app) {
- const { Donation } = app.models;
+ const { Donation, UserToken } = app.models;
return async function getSessionUser(req, res, next) {
const queryUser = req.user;
- const userTokenArr = await queryUser.userTokens({
- userId: queryUser.id
- });
-
- const userToken = userTokenArr[0]?.id;
- let encodedUserToken;
+ const userId = queryUser?.id;
+ const userToken = userId
+ ? await UserToken.findOne({
+ where: { userId }
+ })
+ : null;
- // only encode if a userToken was found
- if (userToken) {
- encodedUserToken = encodeUserToken(userToken);
- }
+ const encodedUserToken = userToken
+ ? encodeUserToken(userToken.id)
+ : undefined;
const source =
queryUser &&
diff --git a/api-server/src/server/index.js b/api-server/src/server/index.js
index 6c350cf2cfbedb..f696000d86c192 100644
--- a/api-server/src/server/index.js
+++ b/api-server/src/server/index.js
@@ -2,6 +2,7 @@ const path = require('path');
require('dotenv').config({ path: path.resolve(__dirname, '../../../.env') });
const Sentry = require('@sentry/node');
+// const Tracing = require('@sentry/tracing');
const createDebugger = require('debug');
const _ = require('lodash');
const loopback = require('loopback');
@@ -14,15 +15,6 @@ const { setupPassport } = require('./component-passport');
const log = createDebugger('fcc:server');
const reqLogFormat = ':date[iso] :status :method :response-time ms - :url';
-if (sentry.dsn === 'dsn_from_sentry_dashboard') {
- log('Sentry reporting disabled unless DSN is provided.');
-} else {
- Sentry.init({
- dsn: sentry.dsn
- });
- log('Sentry initialized');
-}
-
const app = loopback();
app.set('state namespace', '__fcc__');
@@ -62,6 +54,7 @@ db.on(
'connected',
_.once(() => log('db connected'))
);
+
app.start = _.once(function () {
const server = app.listen(app.get('port'), function () {
app.emit('started');
@@ -89,6 +82,25 @@ app.start = _.once(function () {
});
});
+if (sentry.dsn === 'dsn_from_sentry_dashboard') {
+ log('Sentry reporting disabled unless DSN is provided.');
+} else {
+ Sentry.init({
+ dsn: sentry.dsn
+ // integrations: [
+ // new Sentry.Integrations.Http({ tracing: true }),
+ // new Tracing.Integrations.Express({
+ // app
+ // })
+ // ],
+ // // Capture 20% of transactions to avoid
+ // // overwhelming Sentry and remain within
+ // // the usage quota
+ // tracesSampleRate: 0.2
+ });
+ log('Sentry initialized');
+}
+
module.exports = app;
if (require.main === module) {
diff --git a/api-server/src/server/middleware.json b/api-server/src/server/middleware.json
index 69a47f44021f0c..df8d4ae9ff8b91 100644
--- a/api-server/src/server/middleware.json
+++ b/api-server/src/server/middleware.json
@@ -39,7 +39,10 @@
"./middlewares/constant-headers": {},
"./middlewares/csp": {},
"./middlewares/flash-cheaters": {},
- "./middlewares/passport-login": {}
+ "./middlewares/passport-login": {},
+ "./middlewares/rate-limit": {
+ "paths": ["/mobile-login"]
+ }
},
"files": {},
"final:after": {
diff --git a/api-server/src/server/middlewares/rate-limit.js b/api-server/src/server/middlewares/rate-limit.js
new file mode 100644
index 00000000000000..b461039a12c58b
--- /dev/null
+++ b/api-server/src/server/middlewares/rate-limit.js
@@ -0,0 +1,23 @@
+import rateLimit from 'express-rate-limit';
+import MongoStore from 'rate-limit-mongo';
+
+const url = process.env.MONGODB || process.env.MONGOHQ_URL;
+
+// Rate limit for mobile login
+// 10 requests per 15 minute windows
+export default function rateLimitMiddleware() {
+ return rateLimit({
+ windowMs: 15 * 60 * 1000,
+ max: 10,
+ standardHeaders: true,
+ legacyHeaders: false,
+ keyGenerator: req => {
+ return req.headers['x-forwarded-for'] || 'localhost';
+ },
+ store: new MongoStore({
+ collectionName: 'UserRateLimit',
+ uri: url,
+ expireTimeMs: 15 * 60 * 1000
+ })
+ });
+}
diff --git a/api-server/src/server/middlewares/request-authorization.js b/api-server/src/server/middlewares/request-authorization.js
index 93d27911884657..f8907c3c9324ae 100644
--- a/api-server/src/server/middlewares/request-authorization.js
+++ b/api-server/src/server/middlewares/request-authorization.js
@@ -35,6 +35,7 @@ const updateHooksRE = /^\/hooks\/update-paypal$/;
// note: this would be replaced by webhooks later
const donateRE = /^\/donate\/charge-stripe$/;
const submitCoderoadChallengeRE = /^\/coderoad-challenge-completed$/;
+const mobileLoginRE = /^\/mobile-login\/?$/;
const _pathsAllowedREs = [
authRE,
@@ -50,7 +51,8 @@ const _pathsAllowedREs = [
unsubscribeRE,
updateHooksRE,
donateRE,
- submitCoderoadChallengeRE
+ submitCoderoadChallengeRE,
+ mobileLoginRE
];
export function isAllowedPath(path, pathsAllowedREs = _pathsAllowedREs) {
diff --git a/api-server/src/server/middlewares/sentry-tracing-handler.js b/api-server/src/server/middlewares/sentry-tracing-handler.js
new file mode 100644
index 00000000000000..41a04e306a9e6c
--- /dev/null
+++ b/api-server/src/server/middlewares/sentry-tracing-handler.js
@@ -0,0 +1,8 @@
+import { Handlers } from '@sentry/node';
+import { sentry } from '../../../../config/secrets';
+
+export default function sentryRequestHandler() {
+ return sentry.dsn === 'dsn_from_sentry_dashboard'
+ ? (req, res, next) => next()
+ : Handlers.tracingHandler();
+}
diff --git a/api-server/src/server/utils/donation.js b/api-server/src/server/utils/donation.js
index a47d1889429355..d3d9f86b1118b2 100644
--- a/api-server/src/server/utils/donation.js
+++ b/api-server/src/server/utils/donation.js
@@ -217,7 +217,7 @@ export async function createStripeCardDonation(req, res, stripe) {
* if user is already donating and the donation isn't one time only,
* throw error
*/
- if (user.isDonating && duration !== 'onetime') {
+ if (user.isDonating && duration !== 'one-time') {
throw {
message: `User already has active recurring donation(s).`,
type: 'AlreadyDonatingError'
diff --git a/api-server/src/server/utils/middleware.js b/api-server/src/server/utils/middleware.js
index 52f5551fc85fb3..61144fae64b2be 100644
--- a/api-server/src/server/utils/middleware.js
+++ b/api-server/src/server/utils/middleware.js
@@ -77,6 +77,20 @@ export function ifUserRedirectTo(status) {
};
}
+export function ifNotMobileRedirect() {
+ return (req, res, next) => {
+ //
+ // Todo: Use the below check once we have done more research on usage
+ //
+ // const isMobile = /(iPhone|iPad|Android)/.test(req.headers['user-agent']);
+ // if (!isMobile) {
+ // res.json({ error: 'not from mobile' });
+ // } else {
+ // next();
+ // }
+ next();
+ };
+}
// for use with express-validator error formatter
export const createValidatorErrorHandler =
(...args) =>
diff --git a/api-server/src/server/utils/stripeHelpers.js b/api-server/src/server/utils/stripeHelpers.js
index c64e44ce618b2b..ae0938d4145732 100644
--- a/api-server/src/server/utils/stripeHelpers.js
+++ b/api-server/src/server/utils/stripeHelpers.js
@@ -9,7 +9,7 @@ export function validStripeForm(amount, duration, email) {
return isEmail('' + email) &&
isNumeric('' + amount) &&
durationKeysConfig.includes(duration) &&
- duration === 'onetime'
+ duration === 'one-time'
? donationOneTimeConfig.includes(amount)
: donationSubscriptionConfig.plans[duration];
}
diff --git a/api/db/index.ts b/api/db/index.ts
new file mode 100644
index 00000000000000..cfc364a88fb412
--- /dev/null
+++ b/api/db/index.ts
@@ -0,0 +1,14 @@
+import fastifyPlugin from 'fastify-plugin';
+import fastifyMongo from '@fastify/mongodb';
+import { FastifyInstance } from 'fastify';
+
+import { MONGOHQ_URL } from '../utils/env';
+
+async function connect(fastify: FastifyInstance) {
+ fastify.log.info(`Connecting to Mongodb`);
+ await fastify.register(fastifyMongo, {
+ url: MONGOHQ_URL
+ });
+}
+
+export const dbConnector = fastifyPlugin(connect);
diff --git a/api/index.ts b/api/index.ts
new file mode 100644
index 00000000000000..b80cc69849018b
--- /dev/null
+++ b/api/index.ts
@@ -0,0 +1,48 @@
+import fastifyAuth0 from 'fastify-auth0-verify';
+import Fastify from 'fastify';
+import middie from '@fastify/middie';
+
+import jwtAuthz from './plugins/fastify-jwt-authz';
+import { testRoutes } from './routes/test';
+import { dbConnector } from './db';
+import { auth0Verify, testMiddleware } from './middleware';
+import { AUTH0_AUDIENCE, AUTH0_DOMAIN, NODE_ENV, PORT } from './utils/env';
+
+const fastify = Fastify({
+ logger: { level: NODE_ENV === 'development' ? 'debug' : 'fatal' }
+});
+
+fastify.get('/', async (_request, _reply) => {
+ return { hello: 'world' };
+});
+
+const start = async () => {
+ // NOTE: Awaited to ensure `.use` is registered on `fastify`
+ await fastify.register(middie);
+
+ // Auth0 plugin
+ void fastify.register(fastifyAuth0, {
+ domain: AUTH0_DOMAIN,
+ audience: AUTH0_AUDIENCE
+ });
+ void fastify.register(jwtAuthz);
+
+ void fastify.use('/test', testMiddleware);
+
+ // Hooks
+ void fastify.addHook('preValidation', auth0Verify);
+
+ void fastify.register(dbConnector);
+ void fastify.register(testRoutes);
+
+ try {
+ const port = Number(PORT);
+ fastify.log.info(`Starting server on port ${port}`);
+ await fastify.listen({ port });
+ } catch (err) {
+ fastify.log.error(err);
+ process.exit(1);
+ }
+};
+
+void start();
diff --git a/api/middleware/index.ts b/api/middleware/index.ts
new file mode 100644
index 00000000000000..59fb5108041612
--- /dev/null
+++ b/api/middleware/index.ts
@@ -0,0 +1,25 @@
+import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify';
+import type { NextFunction, NextHandleFunction } from '@fastify/middie';
+
+export async function auth0Verify(
+ this: FastifyInstance,
+ request: FastifyRequest,
+ reply: FastifyReply
+): Promise {
+ await this.authenticate(request, reply);
+}
+
+type MiddieRequest = Parameters[0];
+type MiddieResponse = Parameters[1];
+
+export function testMiddleware(
+ req: MiddieRequest,
+ res: MiddieResponse,
+ next: NextFunction
+): void {
+ console.log('Test middleware running');
+ console.log(req.headers);
+ console.log(req.query);
+ res.setHeader('X-Test-Header', 'test');
+ next();
+}
diff --git a/api/package.json b/api/package.json
new file mode 100644
index 00000000000000..9505aea973c2b5
--- /dev/null
+++ b/api/package.json
@@ -0,0 +1,43 @@
+{
+ "author": "freeCodeCamp ",
+ "bugs": {
+ "url": "https://github.com/freeCodeCamp/freeCodeCamp/issues"
+ },
+ "dependencies": {
+ "@fastify/middie": "8.1",
+ "@fastify/mongodb": "6.2.0",
+ "fastify": "4.14.0",
+ "fastify-auth0-verify": "^1.0.0",
+ "fastify-plugin": "^4.3.0",
+ "nodemon": "2.0.21"
+ },
+ "description": "The freeCodeCamp.org open-source codebase and curriculum",
+ "engines": {
+ "node": ">=18",
+ "npm": ">=8"
+ },
+ "homepage": "https://github.com/freeCodeCamp/freeCodeCamp#readme",
+ "license": "BSD-3-Clause",
+ "main": "none",
+ "name": "@freecodecamp/api",
+ "nodemonConfig": {
+ "env": {
+ "NODE_ENV": "development"
+ },
+ "ignore": [
+ "**/*.js"
+ ]
+ },
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/freeCodeCamp/freeCodeCamp.git"
+ },
+ "scripts": {
+ "build": "tsc",
+ "develop": "nodemon index.ts",
+ "start": "NODE_ENV=production node index.js",
+ "test": "node --test -r ts-node/register **/*.test.ts"
+ },
+ "version": "0.0.1"
+}
diff --git a/api/plugins/fastify-jwt-authz.test.ts b/api/plugins/fastify-jwt-authz.test.ts
new file mode 100644
index 00000000000000..9067266ae928c1
--- /dev/null
+++ b/api/plugins/fastify-jwt-authz.test.ts
@@ -0,0 +1,292 @@
+/*
+MIT License
+
+Copyright (c) 2018 Ethan Arrowood
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+import assert from 'node:assert';
+// eslint-disable-next-line import/no-unresolved
+import { describe, it } from 'node:test';
+import Fastify from 'fastify';
+import jwtAuthz from './fastify-jwt-authz';
+
+interface ErrorResponse {
+ statusCode: number;
+ error: string;
+ message: string;
+}
+
+describe('fastify-jwt-authz', { only: true }, () => {
+ it('should decorate request instance with jwtAuthz method', async () => {
+ const fastify = Fastify();
+ await fastify.register(jwtAuthz);
+
+ fastify.get('/test', function (request) {
+ assert(request.jwtAuthz);
+ return { foo: 'bar' };
+ });
+
+ fastify.listen({ port: 0 }, function () {
+ fastify.server.unref();
+ });
+
+ const res = await fastify.inject({
+ method: 'GET',
+ url: '/test'
+ });
+
+ assert.strictEqual(res.statusCode, 200);
+ });
+
+ it('should throw an error "Scopes cannot be empty" with an empty scopes parameter', async () => {
+ const fastify = Fastify();
+ await fastify.register(jwtAuthz);
+
+ fastify.get(
+ '/test2',
+ {
+ preHandler: function (request, _reply, done) {
+ void request.jwtAuthz([], done);
+ }
+ },
+ function () {
+ return { foo: 'bar' };
+ }
+ );
+
+ fastify.listen({ port: 0 }, function () {
+ fastify.server.unref();
+ });
+
+ const res = await fastify.inject({
+ method: 'GET',
+ url: '/test2'
+ });
+ const resData: ErrorResponse = res.json();
+
+ assert.strictEqual(res.statusCode, 500);
+ assert.strictEqual(resData.message, 'Scopes cannot be empty');
+ });
+
+ it('should throw an error "request.user does not exist" non existing request.user', async () => {
+ const fastify = Fastify();
+ await fastify.register(jwtAuthz);
+
+ fastify.get(
+ '/test3',
+ {
+ preHandler: function (request, _reply, done) {
+ void request.jwtAuthz(['baz'], done);
+ }
+ },
+ function () {
+ return { foo: 'bar' };
+ }
+ );
+
+ fastify.listen({ port: 0 }, function () {
+ fastify.server.unref();
+ });
+
+ const res = await fastify.inject({
+ method: 'GET',
+ url: '/test3'
+ });
+ const resData: ErrorResponse = res.json();
+
+ assert.strictEqual(res.statusCode, 500);
+ assert.strictEqual(resData.message, 'request.user does not exist');
+ });
+
+ it('should throw an error "request.user.scope must be a string"', async () => {
+ const fastify = Fastify();
+ await fastify.register(jwtAuthz);
+
+ fastify.get(
+ '/test4',
+ {
+ preHandler: function (request, _reply, done) {
+ request.user = {
+ name: 'sample',
+ scope: 123
+ };
+ void request.jwtAuthz(['baz'], done);
+ }
+ },
+ function () {
+ return { foo: 'bar' };
+ }
+ );
+
+ fastify.listen({ port: 0 }, function () {
+ fastify.server.unref();
+ });
+
+ const res = await fastify.inject({
+ method: 'GET',
+ url: '/test4'
+ });
+ const resData: ErrorResponse = res.json();
+
+ assert.strictEqual(res.statusCode, 500);
+ assert.strictEqual(resData.message, 'request.user.scope must be a string');
+ });
+
+ it('should throw an error "Insufficient scope"', async () => {
+ const fastify = Fastify();
+ await fastify.register(jwtAuthz);
+
+ fastify.get(
+ '/test5',
+ {
+ preHandler: function (request, _reply, done) {
+ request.user = {
+ name: 'sample',
+ scope: 'baz'
+ };
+ void request.jwtAuthz(['foo'], done);
+ }
+ },
+ function () {
+ return { foo: 'bar' };
+ }
+ );
+
+ fastify.listen({ port: 0 }, function () {
+ fastify.server.unref();
+ });
+
+ const res = await fastify.inject({
+ method: 'GET',
+ url: '/test5'
+ });
+ const resData: ErrorResponse = res.json();
+
+ assert.strictEqual(res.statusCode, 500);
+ assert.strictEqual(resData.message, 'Insufficient scope');
+ });
+
+ it('should verify user scope', async () => {
+ const fastify = Fastify();
+ await fastify.register(jwtAuthz);
+
+ fastify.get(
+ '/test6',
+ {
+ preHandler: function (request, _reply, done) {
+ request.user = {
+ name: 'sample',
+ scope: 'user manager'
+ };
+ void request.jwtAuthz(['user'], done);
+ }
+ },
+ function () {
+ return { foo: 'bar' };
+ }
+ );
+
+ fastify.listen({ port: 0 }, function () {
+ fastify.server.unref();
+ });
+
+ const res = await fastify.inject({
+ method: 'GET',
+ url: '/test6'
+ });
+
+ const resData: { foo: string } = res.json();
+
+ assert.strictEqual(res.statusCode, 200);
+ assert.strictEqual(resData.foo, 'bar');
+ });
+
+ it('should throw an error when there is no callback', async () => {
+ const fastify = Fastify();
+ await fastify.register(jwtAuthz);
+
+ fastify.get(
+ '/test7',
+ {
+ preHandler: function (request, _reply, done) {
+ request.user = {
+ name: 'sample',
+ scope: 123
+ };
+
+ request.jwtAuthz(['baz']);
+ done();
+ }
+ },
+ function () {
+ return { foo: 'bar' };
+ }
+ );
+
+ fastify.listen({ port: 0 }, function () {
+ fastify.server.unref();
+ });
+
+ const res = await fastify.inject({
+ method: 'GET',
+ url: '/test7'
+ });
+ const resData: ErrorResponse = res.json();
+
+ assert.strictEqual(res.statusCode, 500);
+ assert.strictEqual(resData.message, 'request.user.scope must be a string');
+ });
+
+ it('should verify user scope when there is no callback', async () => {
+ const fastify = Fastify();
+ await fastify.register(jwtAuthz);
+
+ fastify.get(
+ '/test8',
+ {
+ preHandler: function (request, _reply, done) {
+ request.user = {
+ name: 'sample',
+ scope: 'user manager'
+ };
+ request.jwtAuthz(['user']);
+ done();
+ }
+ },
+ function () {
+ return { foo: 'bar' };
+ }
+ );
+
+ fastify.listen({ port: 0 }, function () {
+ fastify.server.unref();
+ });
+
+ const res = await fastify.inject({
+ method: 'GET',
+ url: '/test8'
+ });
+ const resData: { foo: string } = res.json();
+
+ assert.strictEqual(res.statusCode, 200);
+ assert.strictEqual(resData.foo, 'bar');
+ });
+});
diff --git a/api/plugins/fastify-jwt-authz.ts b/api/plugins/fastify-jwt-authz.ts
new file mode 100644
index 00000000000000..388d42bfb25729
--- /dev/null
+++ b/api/plugins/fastify-jwt-authz.ts
@@ -0,0 +1,72 @@
+/*
+MIT License
+
+Copyright (c) 2018 Ethan Arrowood
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+import { FastifyPluginCallback, FastifyRequest } from 'fastify';
+import fp from 'fastify-plugin';
+
+interface UserObject {
+ scope?: string;
+}
+
+interface JwtAuthz {
+ (scopes: string[], callback?: (err?: Error) => void): void;
+}
+
+const fastifyJwtAuthz: FastifyPluginCallback = (fastify, _opts, done) => {
+ fastify.decorateRequest('jwtAuthz', jwtAuthz);
+
+ function checkScopes(user: UserObject, scopes: string[]) {
+ if (scopes.length === 0) return Error('Scopes cannot be empty');
+
+ if (!user) return Error('request.user does not exist');
+
+ if (typeof user.scope !== 'string')
+ return Error('request.user.scope must be a string');
+
+ const userScopes = user.scope.split(' ');
+ const sufficientScope = scopes.some(scope => userScopes.includes(scope));
+
+ if (!sufficientScope) return Error('Insufficient scope');
+ }
+
+ function jwtAuthz(
+ this: FastifyRequest,
+ scopes: string[],
+ callback?: (err?: Error) => void
+ ) {
+ const err = checkScopes(this.user as UserObject, scopes);
+ if (callback) return callback(err);
+ if (err) throw err;
+ }
+
+ done();
+};
+
+declare module 'fastify' {
+ interface FastifyRequest {
+ jwtAuthz: JwtAuthz;
+ }
+}
+
+export default fp(fastifyJwtAuthz);
diff --git a/api/routes/test.ts b/api/routes/test.ts
new file mode 100644
index 00000000000000..73b313d764c545
--- /dev/null
+++ b/api/routes/test.ts
@@ -0,0 +1,57 @@
+import { FastifyPluginCallback, FastifyRequest } from 'fastify';
+
+export const testRoutes: FastifyPluginCallback = (fastify, _options, done) => {
+ const collection = fastify.mongo.db?.collection('user');
+
+ fastify.get('/test', async (_request, _reply) => {
+ if (!collection) {
+ return { error: 'No collection' };
+ }
+ const user = await collection?.findOne({ email: 'bar@bar.com' });
+ return { user };
+ });
+
+ fastify.put(
+ '/update-privacy-terms',
+ {
+ preHandler: [
+ function (
+ req: FastifyRequest<{ Body: { quincyEmails: boolean } }>,
+ _res,
+ done
+ ) {
+ void req.jwtAuthz(['write:user'], done);
+ }
+ ],
+ schema: {
+ body: {
+ required: ['quincyEmails'],
+ properties: {
+ quincyEmails: { type: 'boolean' }
+ }
+ }
+ }
+ },
+ (req, res) => {
+ const {
+ body: { quincyEmails }
+ } = req;
+
+ const update = {
+ acceptedPrivacyTerms: true,
+ sendQuincyEmail: !!quincyEmails
+ };
+
+ return collection
+ ?.updateOne({ email: 'bar@bar.com' }, { $set: update })
+ .then(() => {
+ void res.code(200).send({ msg: 'Successfully updated' });
+ })
+ .catch(err => {
+ fastify.log.error(err);
+ void res.code(500).send({ msg: 'Something went wrong' });
+ });
+ }
+ );
+ done();
+};
diff --git a/api/tsconfig.json b/api/tsconfig.json
new file mode 100644
index 00000000000000..adfcc0f8660776
--- /dev/null
+++ b/api/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "compilerOptions": {
+ "target": "es2022",
+ "module": "CommonJS",
+ "allowJs": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "esModuleInterop": true,
+ "resolveJsonModule": true,
+ "typeRoots": ["../node_modules/@types", "../node_modules/@fastify"]
+ }
+}
diff --git a/api/utils/env.ts b/api/utils/env.ts
new file mode 100644
index 00000000000000..a54e35c9c8174a
--- /dev/null
+++ b/api/utils/env.ts
@@ -0,0 +1,35 @@
+import assert from 'node:assert';
+import path from 'node:path';
+import { config } from 'dotenv';
+
+const envPath = path.resolve(__dirname, '../../.env');
+const { error } = config({ path: envPath });
+
+if (error) {
+ console.warn(`
+ ----------------------------------------------------
+ Warning: .env file not found.
+ ----------------------------------------------------
+ Please copy sample.env to .env
+
+ You can ignore this warning if using a different way
+ to setup this environment.
+ ----------------------------------------------------
+ `);
+}
+
+assert.ok(process.env.NODE_ENV);
+assert.ok(process.env.AUTH0_DOMAIN);
+assert.ok(process.env.AUTH0_AUDIENCE);
+
+if (process.env.NODE_ENV !== 'development') {
+ assert.ok(process.env.PORT);
+ assert.ok(process.env.MONGOHQ_URL);
+}
+
+export const MONGOHQ_URL =
+ process.env.MONGOHQ_URL || 'mongodb://localhost:27017/freecodecamp';
+export const NODE_ENV = process.env.NODE_ENV;
+export const AUTH0_DOMAIN = process.env.AUTH0_DOMAIN;
+export const AUTH0_AUDIENCE = process.env.AUTH0_AUDIENCE;
+export const PORT = process.env.PORT || '3000';
diff --git a/api/utils/index.test.ts b/api/utils/index.test.ts
new file mode 100644
index 00000000000000..6b6eb6bff5240c
--- /dev/null
+++ b/api/utils/index.test.ts
@@ -0,0 +1,18 @@
+import assert from 'node:assert';
+// eslint-disable-next-line import/no-unresolved
+import { describe, it } from 'node:test';
+import { base64URLEncode, challenge, verifier } from '.';
+
+describe('utils', { only: true }, () => {
+ it('base64URLEncode', () => {
+ assert.strictEqual(base64URLEncode(Buffer.from('test')), 'dGVzdA');
+ });
+ it('verifier', () => {
+ const v = verifier;
+ assert.strictEqual(v.length, 43);
+ });
+ it('challenge', () => {
+ const c = challenge;
+ assert.strictEqual(c.length, 43);
+ });
+});
diff --git a/api/utils/index.ts b/api/utils/index.ts
new file mode 100644
index 00000000000000..fbe8447a59cf95
--- /dev/null
+++ b/api/utils/index.ts
@@ -0,0 +1,15 @@
+import { randomBytes, createHash } from 'crypto';
+
+export function base64URLEncode(buf: Buffer): string {
+ return buf
+ .toString('base64')
+ .replace(/\+/g, '-')
+ .replace(/\//g, '_')
+ .replace(/=/g, '');
+}
+export const verifier = base64URLEncode(randomBytes(32));
+
+function sha256(buf: Buffer) {
+ return createHash('sha256').update(buf).digest();
+}
+export const challenge = base64URLEncode(sha256(Buffer.from(verifier)));
diff --git a/client/gatsby-browser.js b/client/gatsby-browser.js
index 513cc8d8a55d9f..f93c9c10a26755 100644
--- a/client/gatsby-browser.js
+++ b/client/gatsby-browser.js
@@ -6,7 +6,7 @@ import { Provider } from 'react-redux';
import i18n from './i18n/config';
import AppMountNotifier from './src/components/app-mount-notifier';
-import { createStore } from './src/redux/createStore';
+import { createStore } from './src/redux/create-store';
import layoutSelector from './utils/gatsby/layout-selector';
import GrowthBookProvider from './src/components/growth-book/growth-book-wrapper';
diff --git a/client/gatsby-config.js b/client/gatsby-config.js
index acc2d255106291..4a9e48b6619b87 100644
--- a/client/gatsby-config.js
+++ b/client/gatsby-config.js
@@ -22,6 +22,7 @@ module.exports = {
},
pathPrefix: pathPrefix,
plugins: [
+ 'gatsby-plugin-pnpm',
{
resolve: '@sentry/gatsby',
options: {
diff --git a/client/gatsby-node.js b/client/gatsby-node.js
index 736fa2ff580f8c..9e5b6d157723a0 100644
--- a/client/gatsby-node.js
+++ b/client/gatsby-node.js
@@ -270,6 +270,8 @@ exports.onCreatePage = async ({ page, actions }) => {
}
};
+// Take care to QA the challenges when modifying this. It has broken certain
+// types of challenge in the past.
exports.createSchemaCustomization = ({ actions }) => {
const { createTypes } = actions;
const typeDefs = `
@@ -280,6 +282,7 @@ exports.createSchemaCustomization = ({ actions }) => {
challengeFiles: [FileContents]
notes: String
url: String
+ assignments: [String]
}
type FileContents {
fileKey: String
@@ -293,44 +296,3 @@ exports.createSchemaCustomization = ({ actions }) => {
`;
createTypes(typeDefs);
};
-
-// TODO: this broke the React challenges, not sure why, but I'll investigate
-// further and reimplement if it's possible and necessary (Oliver)
-// I'm still not sure why, but the above schema seems to work.
-// Typically the schema can be inferred, but not when some challenges are
-// skipped (at time of writing the Chinese only has responsive web design), so
-// this makes the missing fields explicit.
-// exports.createSchemaCustomization = ({ actions }) => {
-// const { createTypes } = actions;
-// const typeDefs = `
-// type ChallengeNode implements Node {
-// question: Question
-// videoId: String
-// required: ExternalFile
-// files: ChallengeFile
-// }
-// type Question {
-// text: String
-// answers: [String]
-// solution: Int
-// }
-// type ChallengeFile {
-// indexhtml: FileContents
-// indexjs: FileContents
-// indexjsx: FileContents
-// }
-// type ExternalFile {
-// link: String
-// src: String
-// }
-// type FileContents {
-// key: String
-// ext: String
-// name: String
-// contents: String
-// head: String
-// tail: String
-// }
-// `;
-// createTypes(typeDefs);
-// };
diff --git a/client/gatsby-ssr.js b/client/gatsby-ssr.js
index e7995a365d0cae..c0f6e4237c6604 100644
--- a/client/gatsby-ssr.js
+++ b/client/gatsby-ssr.js
@@ -4,7 +4,7 @@ import { I18nextProvider } from 'react-i18next';
import { Provider } from 'react-redux';
import i18n from './i18n/config';
-import { createStore } from './src/redux/createStore';
+import { createStore } from './src/redux/create-store';
import layoutSelector from './utils/gatsby/layout-selector';
import { getheadTagComponents, getPostBodyComponents } from './utils/tags';
import GrowthBookProvider from './src/components/growth-book/growth-book-wrapper';
diff --git a/client/i18n/locales/arabic/intro.json b/client/i18n/locales/arabic/intro.json
index fddcb6cdd83aa2..26f9fd200aa1fa 100644
--- a/client/i18n/locales/arabic/intro.json
+++ b/client/i18n/locales/arabic/intro.json
@@ -3,23 +3,23 @@
"title": "تراث تصميم مواقع الويب المتجاوبة",
"intro": [
"في شهادة تصميم الويب المستجيب هذه، ستتعلم اللغات التي يستخدمها المطورين لبناء صفحات الويب: HTML (Hypertext Markup Language) للمحتوى، و CSS (Cascading Style Sheets) للتصميم.",
- "أولاً، سوف تقوم ببناء تطبيق صورة القطة لتعلم أساسيات HTML و CSS. لاحقاً، سوف تتعلم التقنيات الحديثة مثل متغيرات CSS عن طريق بناء بطريق، وأفضل الممارسات في اتاحة الوصول (accessibility) عن طريق بناء نموذج ويب.",
- "أخيراً، سوف تتعلم كيف تنشئ صفحات ويب تستجيب لأحجام الشاشات المختلفة من خلال بناء بطاقة تويتر باستخدام Flexbox، وتخطيط معقد لمدونة باستخدام CSS Grid."
+ "أولاً، سوف تبني تطبيق صورة قطة لتتعلم أساسيات HTML و CSS. لاحقاً، سوف تتعلم التقنيات الحديثة مثل متغيرات CSS عن طريق بناء بِطْرِيق، وأفضل الممارسات في إتاحة الوصول (accessibility) عن طريق بناء نموذج ويب.",
+ "أخيراً، سوف تتعلم كيف تنشئ صفحات ويب تستجيب لأحجام الشاشات المختلفة عندما تبني بطاقة تويتر باستخدام Flexbox، وتخطيط معقد لمدونة باستخدام CSS Grid."
],
- "note": "ملاحظة: بعض إضافات المتصفح, مثل Ad-blockers وإضافات الوضع الليلي قد تتصادم مع نتائج الاختبارات, إذا واجهت مشاكل, ننصحك بتعطيل الإضافات التي قد تؤثر أو تعدل على مخطط الصفحات, أثناء حضورك للدورة.",
+ "note": "ملاحظة: بعض إضافات المتصفح, مثل Ad-blockers وإضافات الوضع الليلي قد تتصادم مع نتائج الاختبارات, إذا واجهت مشكلات, ننصحك بتعطيل الإضافات التي قد تؤثر أو تعدل على مخطط الصفحات في أثناء حضورك للدورة.",
"blocks": {
"basic-html-and-html5": {
"title": "أساسيات HTML و HTML5",
"intro": [
- "HTML هي لغة ترميز تستخدم سياق خاص أو رموز لوصف الهيكل الخاص بصفحة الويب للمتصفح، عناصر HTML عادة لديها وسم فتح واغلاق تحيط المحتوى وتضيف معنى له. على سبيل المثال، عناصر مختلفة بامكانها وصف النص كعنوان أو فقرة أو عنصر من قائمة.",
- "في هذه الدورة، ستبني تطبيق صورة القطة لتعلم بعض من أكثر عناصر الـ HTML شيوعاً، كتل البناء لأي صفحة على الويب."
+ "HTML هي لغة ترميز تستخدم سياق خاص أو رموز لوصف الهيكل الخاص بصفحة الويب للمتصفح، عناصر HTML عادة لديها علامة فتح وإغلاق تحيط المحتوى وتضيف معنى له. على سبيل المثال، عناصر مختلفة بإمكانها وصف النص كعنوان أو فَقَرة أو عنصر من قائمة.",
+ "في هذه الدورة، ستبني تطبيق صورة القطة لتتعلم بعض من أكثر عناصر لغة HTML شيوعاً، وهي كتل البناء لأي صفحة على الويب."
]
},
"basic-css": {
"title": "أساسيات CSS",
"intro": [
- "CSS أو Cascading Style Sheets تخبر المتصفح كيف يعرض النص والعناصر الأخرى التي قمت بكتابتها في ملف الـ HTML، مع CSS تستطيع التحكم باللون والخط والحجم والمسافة والكثير من الأوجه المختلفة لعناصر HTML.",
- "الآن بعد أن وصفت بنية تطبيق صورة القطة الخاص بك، أضف له بعض التصاميم باستخدام CSS."
+ "CSS أو Cascading Style Sheets تخبر المتصفح كيف يعرض النص والعناصر الأخرى الذي قمت بكتابتها في مِلَفّ HTML. و بواسطة CSS تستطيع التحكم باللون والخط والحجم والمسافة والكثير من الأوجه المختلفة لعناصر HTML.",
+ "الآن بعد أن وصفت بنية تطبيق صورة القطة الخاصة بك، أضف له بعض التصاميم باستخدام CSS."
]
},
"applied-visual-design": {
@@ -32,7 +32,7 @@
"applied-accessibility": {
"title": "امكانية الوصول المطبقة",
"intro": [
- "في تطوير المواقع، اماكنية الوصول تشير إلى محتوى ويب وواجهة مستخدم يمكن فهمها والتنقل بها والتفاعل معها من قبل جمهور عريض. هذا يتضمن أشخاص مصابين بإعاقات بصرية أو سمعية أو حركية أو ادراكية.",
+ "في تطوير المواقع، إماكنية الوصول تشير إلى محتوى ويب وواجهة مستخدم (UI - User Interface) يمكن فهمها والتنقل بها والتفاعل معها من قبل جَمهور عريض. هذا يتضمن أشخاص مصابين بإعاقات بصرية أو سمعية أو حركية أو إدراكية.",
"في هذه الدورة، ستتعلم أفضل الممارسات لبناء صفحات الويب التي يمكن للجميع الوصول إليها وفهمها."
]
},
@@ -76,80 +76,80 @@
"note": "ملاحظة: بعض إضافات المتصفح, مثل Ad-blockers وإضافات الوضع الليلي قد تتصادم مع نتائج الاختبارات, إذا واجهت مشاكل, ننصحك بتعطيل الإضافات التي قد تؤثر أو تعدل على مخطط الصفحات, أثناء حضورك للدورة.",
"blocks": {
"build-a-tribute-page-project": {
- "title": "صفحة الإشادة",
+ "title": "صفحة الثناء",
"intro": [
"هذا هو أحد المشاريع المطلوبة للحصول على شهادتك.",
- "في هذا المشروع، سوف تقوم ببناء صفحة ثناء لموضوع من اختيارك سواء كان الموضوع من وحي خيالك أو حقيقي."
+ "في هذا المشروع، سوف تنشئ صفحة إثناء لموضوع من اختيارك سواء كان الموضوع من وحي خيالك أو حقيقي."
]
},
"build-a-personal-portfolio-webpage-project": {
- "title": "صفحه الويب لعرض نموذجات الأعمال الشخصية",
+ "title": "معرضا لأعمالك الخاصة",
"intro": [
- "هذا هو أحد المشاريع المطلوبة للحصول على شهادتك.",
- "في هذا المشروع، سوف تقوم ببناء صفحة ويب لعرض نماذج الاعمال الشخصية الخاصة بك."
+ "هذا هو أحد المشروعات المطلوبة للحصول على شهادتك.",
+ "في هذا المشروع، سوف تتشئ صفحة ويب معرضا لأعمالك الخاصة."
]
},
"build-a-product-landing-page-project": {
- "title": "صفحة الهبوط للمنتج",
+ "title": "صفحة لعرض المنتج",
"intro": [
- "هذا هو أحد المشاريع المطلوبة للحصول على شهادتك.",
- "في هذا المشروع، سوف تقوم ببناء صفحة هبوط لمنتج من اختيارك للتسويق له."
+ "هذا هو أحد المشروعات المطلوبة للحصول على شهادتك.",
+ "في هذا المشروع، ستنشئ صفحة لعرض المنتج من اختيارك للتسويق له."
]
},
"build-a-survey-form-project": {
"title": "نموذج استطلاع رأي",
"intro": [
- "هذا هو أحد المشاريع المطلوبة للحصول على شهادتك.",
- "في هذا المشروع، سوف تقوم ببناء نموذج الدراسة الاستقصائية لجمع بيانات من المستخدمين."
+ "هذا هو أحد المشروعات المطلوبة للحصول على شهادتك.",
+ "في هذا المشروع، سوف تنشئ نموذج استطلاع رأي لجمع بيانات من مستخدميك."
]
},
"build-a-technical-documentation-page-project": {
- "title": "صفحة الوثائق التقنية",
+ "title": "صفحة التوثيق التقنية",
"intro": [
- "هذا هو أحد المشاريع المطلوبة للحصول على شهادتك.",
- "في هذا المشروع، ستنشئ صفحة التوثيق التقني لتكون بمثابة تعليمات أو مرجع لموضوع ما."
+ "هذا هو أحد المشروعات المطلوبة للحصول على شهادتك.",
+ "في هذا المشروع، ستنشئ صفحة نموذج استطلاع رأي لتقوم مقام التعليمات أو المرجع لموضوع ما."
]
},
"learn-html-by-building-a-cat-photo-app": {
"title": "تعلم HTML عن طريق بناء تطبيق صورة القطة",
"intro": [
"تعطي وسوم HTML صفحة الويب هيكلها. يمكنك استخدام وسوم HTML لإضافة الصور والأزرار والعناصر الأخرى إلى صفحة الويب الخاصة بك.",
- "في هذه الدورة، ستتعلم وسوم HTML الأكثر شيوعاً عن طريق بناء تطبيقك لصورة القطة."
+ "في هذه الدورة، ستتعلم وسوم HTML الأكثر شيوعاً عن طريق بناء تطبيقك صورة القطة."
]
},
"learn-basic-css-by-building-a-cafe-menu": {
"title": "تعلم اساسيات CSS عن طريق بناء قائمة مقهى",
"intro": [
- "CSS يخبر المتصفح كيفية عرض صفحة الويب الخاصة بك. يمكنك استخدام CSS لتعيين اللون والخطوط والحجم والجوانب الأخرى لعناصر HTML.",
- "في هذه الدورة، سوف تتعلم CSS عن طريق تصميم صفحة قائمة لصفحة ويب لمقهي."
+ "يخبر CSS المتصفح كيف تعرض صفحتك الويب. يمكنك استخدام CSS لتعيين اللون والخطوط والحجم والجوانب الأخرى لعناصر HTML.",
+ "في هذه الدورة، سوف تتعلم CSS عن طريق تصميم صفحة قائمة لصفحة ويب لمقهى."
]
},
"learn-the-css-box-model-by-building-a-rothko-painting": {
"title": "تعلم CSS Box Model عن طريق بناء رسم لـRothko",
"intro": [
- "كل عنصر من عناصر HTML هو صندوق خاص به - مع مساحته الخاصة وحدوده. وهذا يسمى نموذج Box Model.",
- "في هذه الدورة، ستستخدم CSS و Box Model لإنشاء قطع فنية مستطيلة على نمط Rothko-الخاص بك."
+ "كل عنصر من عناصر HTML هو صندوقه - مع مساحته الخاصة وحدوده. وهذا يسمى نموذج الصندوق Box Model.",
+ "في هذه الدورة، ستستخدم CSS و Box Model لإنشاء قطع فنية مستطيلة على تصممك لوحة روثكو."
]
},
"learn-css-variables-by-building-a-city-skyline": {
- "title": "تعلم متغيرات CSS عن طريق بناء خط افق المدينة",
+ "title": "تعلم متغيرات CSS عن طريق أنشئ ناطحة السحاب بالمدينة",
"intro": [
- "تساعدك متغيرات CSS على تنظيم الأنماط الخاصة بك وإعادة استخدامها.",
- "في هذه الدورة، ستبني خط افق المدينة. ستتعلم كيفية تهيئة متغيرات CSS حتى تتمكن من إعادة استخدامها كلما أردت."
+ "تساعدك متغيرات CSS على تنظيم تصميماتك وإعادة استخدامها.",
+ "في هذه الدورة، ستبني ناطحة سحب بالمدينة. ستتعلم كيفية إعداد متغيرات CSS حتى تتمكن من إعادة استخدامها كلما أردت."
]
},
"learn-html-forms-by-building-a-registration-form": {
- "title": "تعلم نماذج HTML عن طريق بناء نموذج تسجيل",
+ "title": "تعلم نموذجات HTML عن طريق بناء نموذج تسجيل",
"intro": [
- "يمكنك استخدام نماذج HTML لجمع المعلومات من الأشخاص الذين يزورون صفحة الويب الخاصة بك.",
+ "يمكنك استخدام نموذجات HTML لجمع المعلومات من الأشخاص الذين يزورون صفحتك الويب.",
"في هذه الدورة، ستتعلم نماذج HTML عن طريق بناء صفحة التسجيل. ستتعلم كيفية التحكم في أنواع البيانات التي يمكن للناس كتابتها في النموذج، وبعض أدوات CSS الجديدة لتصميم صفحتك."
]
},
"learn-accessibility-by-building-a-quiz": {
- "title": "تعلم إمكانية الوصول Accessibility عن طريق بناء اختبار",
+ "title": "تعلم تسهيل المنال Accessibility عن طريق بناء اختبار",
"intro": [
- "إمكانية الوصول تجعل صفحة الويب الخاصة بك سهلة الاستخدام لجميع الناس - حتى الأشخاص ذوي الإعاقة.",
- "في هذه الدورة، ستبني صفحة ويب لاختبار. ستتعلم أدوات الوصول مثل اختصارات لوحة المفاتيح، سمات ARIA وأفضل الممارسات في التصميم."
+ "الاهتمام بتسهيل المنال إلى صفحتك الويب سهلة الاستخدام لجميع الناس - حتى الأشخاص ذوي الإعاقة.",
+ "في هذه الدورة، ستبني صفحة ويب لاختبار. ستتعلم أدوات تسهل المنال مثل اختصارات لوحة المفاتيح، سمات ARIA وأفضل الممارسات في التصميم."
]
},
"learn-intermediate-css-by-building-a-picasso-painting": {
@@ -159,31 +159,31 @@
]
},
"learn-responsive-web-design-by-building-a-piano": {
- "title": "تعلم تصميم الويب المتجاوب Responsive Web Design عن طريق بناء بيانو",
+ "title": "تعلم تصميم الويب المستجيب Responsive Web Design عن طريق بناء بيانو",
"intro": [
- "التصميم المستجيب يخبر صفحة الويب الخاصة بك كيف ينبغي أن تبدو على شاشات مختلفة الحجم.",
+ "يخبر التصميم المستجيب صفحتك الويب كيف ينبغي أن تبدو على شاشات مختلفة الحجم.",
"في هذه الدورة، ستستخدم CSS والتصميم المستجيب لبرمجة وبناء بيانو. كما ستتعلم المزيد عن media queries و pseudo selectors."
]
},
"learn-css-flexbox-by-building-a-photo-gallery": {
"title": "تعلم CSS Flexbox من خلال بناء معرض للصور",
"intro": [
- "يساعدك Flexbox في تصميم صفحة الويب الخاصة بك بحيث تبدو جيدة على أي حجم شاشة.",
+ "يساعدك Flexbox في تصميم صفحتك الويب بحيث تبدو جيدة على أي حجم شاشة.",
"في هذه الدورة، ستستخدم Flexbox لإنشاء موقع ويب مستجيب Responsive لمعرض صور."
]
},
"learn-css-grid-by-building-a-magazine": {
"title": "تعلم CSS Grid عن طريق بناء مجلة",
"intro": [
- "تمنحك CSS Grid التحكم في صفوف وأعمدة تصميم صفحة الويب الخاصة بك.",
+ "تمنحك CSS Grid التحكم في صفوف وأعمدة تصميم صفحتك الويب.",
"في هذه الدورة، ستقوم ببناء مقال في مجلة. ستتعلم كيفية استخدام CSS Grid، بما في ذلك مفاهيم مثل صفوف الشبكة Grid rows وأعمدة الشبكة Grid columns."
]
},
"learn-typography-by-building-a-nutrition-label": {
"title": "تعلم الطباعة Typography عن طريق بناء علامة التغذية",
"intro": [
- "التيبوغرافي هو فن تصميم النص الخاص بك ليكون سهل القراءة ويناسب الغرض منه.",
- "في هذه الدورة، ستستخدم typography لإنشاء صفحة ويب لتسمية التغذية. ستتعلم كيفية تغيير نمط النص، وتعديل ارتفاع الخط line-height، و تغيير وضع position نصك باستخدام CSS."
+ "إن تشكيل الخط فن لتصميم نصك ليسهل قراءة ويلائم غرضه.",
+ "في هذه الدورة، ستستخدم typography لإنشاء صفحة ويب لتسمية التغذية. ستتعلم كيفية تغيير تشكيل النص، وتعديل ارتفاع الخط line-height، و تغيير وضع position نصك باستخدام CSS."
]
},
"learn-css-transforms-by-building-a-penguin": {
@@ -204,7 +204,7 @@
"title": "تعلم المزيد عن Selectors Pseudo في CSS عن طريق بناء كشف ميزانية",
"intro": [
"يمكنك استخدام CSS pseudo selectors لتغيير عناصر HTML محددة.",
- "في هذه الدورة ، ستبني ميزانية عامة باستخدام pseudo selectors. سوف تتعلم كيفية تغيير نمط عنصر ما عندما تحوم فوقه بالماوس الخاص بك، وتفعيل أحداث أخرى على صفحة الويب الخاصة بك."
+ "في هذه الدورة، ستبني ميزانية عامة باستخدام المنتقات الزائفة pseudo selectors. سوف تتعلم كيفية تغيير تصميم عنصر ما عندما تحوم فوقه بماوسك، وتفعيل أحداث أخرى على صفحتك الويب."
]
},
"learn-css-colors-by-building-a-set-of-colored-markers": {
@@ -219,7 +219,7 @@
"javascript-algorithms-and-data-structures": {
"title": "الخوارزميات وهياكل البيانات في JavaScript",
"intro": [
- "في حين أن HTML و CSS يتحكمان في محتوى الصفحة ونمط الصفحة، يتم استخدام Javascript لجعلها تفاعلية. في شهادة الخوارزميات وهياكل البيانات في JavaScript، ستتعلم أساسيات JavaScript بما في ذلك المتغيرات والمصفوفات Arrays والكائنات Objects والحلقات Loops والدوال.",
+ "في حين أن HTML و CSS يتحكمان في محتوى الصفحة وتصميم الصفحة، يستخدم Javascript لجعلها تفاعلية. في شهادة الخوارزميات وهياكل البيانات في JavaScript، ستتعلم أساسيات JavaScript بما في ذلك المتغيرات variables, والقوائم arrays, والكائنات objects والحلقات loops, والوظائف functions.",
"بمجرد أن يكون لديك الأساسيات، ستطبق تلك المعرفة عن طريق إنشاء خوارزميات للتلاعب بالسلاسل strings، تحديد الأعداد، بل وحساب مدار محطة الفضاء الدولية.",
"في هذا المشوار ستتعلم أيضًا أسلوبين أو نموذجين مهمين للبرمجة: البرمجة كائنية التوجه (OOP) ، والبرمجة الوظيفية (FP)."
],
@@ -228,8 +228,8 @@
"basic-javascript": {
"title": "أساسيات JavaScript",
"intro": [
- "JavaScript هي لغة برمجة يمكنك استخدامها لجعل صفحات الويب تفاعلية. إنها إحدى التكنولوجيات الأساسية للويب، إلى جانب HTML و CSS، وهي مدعومة بجميع المتصفحات الحديثة.",
- "في هذه الدورة ، ستتعلم مفاهيم البرمجة الأساسية في Javascript. ستبدأ بهياكل البيانات الأساسية مثل الأرقام والنصوص. ثم سوف تتعلم العمل مع المصفوفات والكائنات والدوال والحلقات والشروط وأكثر من ذلك."
+ "إن JavaScript لغة برمجة يمكنك استخدامها لجعل صفحات الويب تفاعلية. إنها إحدى التكنولوجيات الأساسية للويب، إلى جانب HTML و CSS، وهي مدعومة بجميع المتصفحات الحديثة.",
+ "في هذه الدورة، ستتعلم مفاهيم البرمجة الأساسية في Javascript. ستبدأ بهياكل البيانات الأساسية مثل الأرقام والنصوص. ثم سوف تتعلم العمل مع الكائنات والقوائم والوظائف والحلقات والشروط وتعبيرات if/else وأكثر من ذلك."
]
},
"es6": {
@@ -241,9 +241,9 @@
]
},
"regular-expressions": {
- "title": "التعبيرات العادية Regular Expressions",
+ "title": "العبارات العادية Regular Expressions",
"intro": [
- "التعبيرات العادية Regular expressions، غالباً ما تسمي \"regex\" أو \"regexp\"، هي أنماط تساعد المبرمجين على المطابقة والبحث واستبدال النص. التعابير العادية قوية جداً، ولكن يمكن أن يكون من الصعب قراءتها لأنها تستخدم رموز خاصة لعمل مطابقات أكثر تعقيداً ومرونة.",
+ "العبارات العادية Regular expressions، غالباً ما تسمي \"regex\" أو \"regexp\"، هي أنماط تساعد المبرمجين على المطابقة والبحث واستبدال النص. التعابير العادية قوية جداً، ولكن يمكن أن يكون من الصعب قراءتها لأنها تستخدم رموز خاصة لعمل مطابقات أكثر تعقيداً ومرونة.",
"في هذه الدورة، ستتعلم كيفية استخدام الرموز الخاصة، التقاط المجموعات، النظرات الإيجابية والسلبية، وتقنيات أخرى لمطابقة أي نص تريده."
]
},
@@ -258,8 +258,8 @@
"basic-data-structures": {
"title": "هياكل البيانات الأساسية",
"intro": [
- "يمكن تخزين البيانات والوصول إليها بعدة طرق. أنت تعرف بالفعل بعض هياكل بيانات javascript الشائعة - المصفوفات والكائنات.",
- "في هذه الدورة لهياكل البيانات الأساسية، ستتعلم المزيد عن الاختلافات بين المصفوفات والكائنات، وعن كيفية استخدامها في أوضاع مختلفة. سوف تتعلم أيضاً كيفية استخدام أساليب Javascript المفيدة مثل splice()
و Object.keys()
للوصول إلى البيانات والتلاعب بها."
+ "يمكن تخزين البيانات والوصول إليها بعدة طرق. أنت تعرف بالفعل بعض هياكل بيانات javascript الشائعة - القوائم والكائنات.",
+ "في هذه الدورة لهياكل البيانات الأساسية، ستتعلم المزيد عن الاختلافات بين القوائم والكائنات، وعن كيفية استخدامها في أوضاع مختلفة. سوف تتعلم أيضاً كيفية استخدام أساليب Javascript المفيدة مثل splice()
و Object.keys()
للوصول إلى البيانات والتلاعب بها."
]
},
"basic-algorithm-scripting": {
@@ -267,7 +267,7 @@
"intro": [
"الخوارزمية هي سلسلة من التعليمات خطوة بخطوة تصف كيفية القيام بشيء ما.",
"يساعدك تفكيك المشكلة إلى أجزاء أصغر والتفكير بعناية حول كيفية حل كل جزء علي حدي بواسطة الكود البرمجي على كتابة خوارزميات اكثر فاعلية.",
- "في هذه الدورة، ستتعلم أساسيات التفكير الخوارزمي عن طريق كتابة الخوارزميات التي تفعل كل شيء من تحويل درجات الحرارة إلى التعامل مع المصفوفات ثنائية الأبعاد 2D arrays المعقدة."
+ "في هذه الدورة، ستتعلم أساسيات التفكير الخوارزمي عن طريق كتابة خوارزميات تفعل كل شيء من تحويل درجات الحرارة إلى التعامل مع القوائم ثنائية الأبعاد 2D arrays المعقدة."
]
},
"object-oriented-programming": {
@@ -280,8 +280,8 @@
"functional-programming": {
"title": "البرمجة الوظيفية Functional Programming",
"intro": [
- "البرمجة الوظيفية هي نهج شائع آخر لتطوير البرمجيات. في البرمجة الوظيفية، يتم تنظيم الكود في وظائف أصغر وأساسية يمكن الجمع بينها لبناء برامج معقدة.",
- "في هذه الدورة، ستتعلم المفاهيم الأساسية للبرمجة الوظيفية بما في ذلك الدوال العادية، كيفية تجنب الطفرات وكيفية كتابة كود أنظف مع أساليب مثل .map()
و .filter()
."
+ "إن البرمجة الوظيفية نهج شائع آخر لتطوير البرمجيات. في البرمجة الوظيفية، ينظم الكود في وظائف أصغر وأساسية يمكن الجمع بينها لبناء برامج معقدة.",
+ "في هذه الدورة، ستتعلم المفاهيم الأساسية للبرمجة الوظيفية بما في تلك الوظيفة العادية، كيفية تجنب الطفرات وكيفية كتابة كود أنظف مع أساليب مثل .map()
و .filter()
."
]
},
"intermediate-algorithm-scripting": {
@@ -305,23 +305,23 @@
"note": "",
"blocks": {
"build-a-caesars-cipher-project": {
- "title": "بناء مشروع Caesars Cipher",
+ "title": "بناء مشروع شفرة قيصر",
"intro": ["", ""]
},
"build-a-cash-register-project": {
- "title": "بناء مشروع Cash Register",
+ "title": "بناء مشروع مكنة لتسجيل النقود",
"intro": ["", ""]
},
"build-a-palindrome-checker-project": {
- "title": "بناء مشروع Palindrome Checker",
+ "title": "أنشئ مشروع مدقق لمعاكس المقطع النصي",
"intro": ["", ""]
},
"build-a-roman-numeral-converter-project": {
- "title": "بناء مشروع Roman Numeral Converter",
+ "title": "أنشئ مشروع محول للأرقام الرومانية",
"intro": ["", ""]
},
"build-a-telephone-number-validator-project": {
- "title": "بناء مشروع Telephone Number Validator",
+ "title": "بناء مشروع مدقق الأرقام الهواتف",
"intro": ["", ""]
},
"learn-basic-javascript-by-building-a-role-playing-game": {
@@ -335,6 +335,10 @@
"learn-functional-programming-by-building-a-spreadsheet": {
"title": "تعلم البرمجة الوظيفية عن طريق بناء Spreadsheet",
"intro": ["", ""]
+ },
+ "learn-advanced-array-methods-by-building-a-statistics-calculator": {
+ "title": "Learn Advanced Array Methods by Building a Statistics Calculator",
+ "intro": ["", ""]
}
}
},
@@ -372,7 +376,7 @@
"react": {
"title": "React",
"intro": [
- "React هي مكتبة شائعة من مكتبات JavaScript لبناء واجهة مستخدم قابلة لإعادة البناء اعتماداً على المكون لصفحات الويب أو التطبيقات.",
+ "إن React مكتبة شائعة من مكتبات JavaScript لبناء واجهة مستخدم قابلة لإعادة البناء اعتماداً على المكون لصفحات الويب أو التطبيقات.",
"يجمع React بين الـ HTML ووظائف الـ JavaScript في لغة ترميز خاصة به تدعى JSX. كما أن React يجعل من السهل إدارة تدفق البيانات في التطبيق.",
"في هذه الدورة ، ستتعلم كيفية إنشاء مكونات مختلفة من React وإدارة البيانات في شكل State و Props و استخدام أساليب دورة الحياة المختلفة مثل componentDidMount
، وأكثر من ذلك بكثير."
]
@@ -389,13 +393,13 @@
"title": "React and Redux",
"intro": [
"كثيرا ما يُشار إلى React و Redux معاً، ولسبب وجيه. المطور الذي أنشأ Redux كان مطور لـ React و اراد أن يسهل مشاركة البيانات عبر المكونات المختلفة.",
- "الآن بعد أن عرفت كيفية إدارة تدفق البيانات المشتركة مع Redux، حان الوقت للجمع بين تلك المعرفة و React. في دورات React و Redux، ستبني مكون React وتتعلم كيفية إدارة الحالة state محلياً على مستوى المكون. وعبر التطبيق باكمله مع Redux."
+ "الآن بعد أن عرفت كيفية إدارة تدفق البيانات المشتركة مع Redux، حان الوقت للجمع بين تلك المعرفة و React. في دورات React و Redux، ستبني مكون React وتتعلم كيفية إدارة الحالة state محلياً على مستوى المكون. وعبر التطبيق برمته مع Redux."
]
},
"front-end-development-libraries-projects": {
"title": "مشاريع مكتبات تطوير واجهة المستخدم",
"intro": [
- "حان الوقت لوضع مهاراتك في مكتبات تطوير واجهات المستخدم للاختبار، استخدم Bootstrap, jQuery, Sass, React و Redux لبناء 5 مشاريع لتختبر كل ما تعلمته حتى هذه النقطة.",
+ "حان الوقت لوضع مهاراتك في مكتبات تطوير واجهات المستخدم للاختبار. استخدم Bootstrap, و jQuery, و Sass, و React, و Redux لبناء 5 مشروعات لتختبر ما تعلمته حتى هذه النقطة.",
"أكمل جميع المشاريع الخمسة، وستحصل على شهادة في مكتبات تطوير واجهة المستخدم."
]
}
@@ -551,9 +555,9 @@
"back-end-development-and-apis": {
"title": "تطوير الواجهات الخلفية للمواقع و واجهات برمجة التطبيقات - Back End Development and APIs",
"intro": [
- "حتى هذه النقطة، لقد استخدمت JavaScript فقط في الواجهة الأمامية لإضافة تفاعل إلى صفحة، أو حل تحديات الخوارزميات، أو بناء SPA. ولكن يمكن أيضاً استخدام JavaScript في الواجهة الخلفية back end، أو الخادم، لبناء تطبيقات ويب بأكملها.",
+ "حتى هذه النقطة، لقد استخدمت JavaScript فقط في الواجهة الأمامية لإضافة تفاعل إلى صفحة، أو حل تحديات الخوارزميات، أو بناء SPA. ولكن يمكن أيضاً استخدام JavaScript في الواجهة الخلفية back end، أو السيرفر، لبناء تطبيقات ويب برمتها.",
"واليوم، فإن إحدى الطرق الشائعة لبناء التطبيقات هي من خلال الخدمات المصّغرة microservices، وهي تطبيقات صغيرة ومحددة تعمل معاً لتشًكل وحدة اكبر.",
- "في شهادة واجهة برمجة التطبيقات والـAPIs، ستتعلم كيفية انشاء تطبيقات back end جاهزة باستخدام Node.js و npm. سوف تقوم أيضا ببناء تطبيقات ويب باستخدام إطار Express وبناء microservice لـ People Finder باستخدام MongoDB ومكتبة Mongoose."
+ "في شهادة تطوير واجهات الBack End و الAPIs، سوف تتعلم كيف تنشئ تطبيقات back end باستخدام Node.js و npm. سوف تقوم أيضا ببناء تطبيقات الويب باستخدام إطار العمل Express، و بناء microservice لإيجاد الأفراد باستخدام MongoDB ومكتبة Mongoose."
],
"note": "",
"blocks": {
@@ -584,7 +588,7 @@
"back-end-development-and-apis-projects": {
"title": "مشاريع تطوير الواجهات الخلفية للمواقع و واجهات برمجة التطبيقات APIs",
"intro": [
- "لقد عملت مع واجهة برمجة التطبيقات APIs من قبل، ولكن الآن بعد أن عرفت npm، وNode, Express، وMongoDB وMongoose، حان الوقت لبناء API بنفسك، بالاعتماد على كل ما تعلمته حتى هذه النقطة لإنشاء 5 خدمات مصغّرة microservices مختلفة، وهي تطبيقات أصغر محدودة النطاق.",
+ "لقد عملت مع واجهة برمجة التطبيقات APIs من قبل، ولكن الآن بعد أن عرفت npm، و Node, و Express، و MongoDB، و Mongoose، حان الوقت لبناء API بنفسك، بالاعتماد على ما تعلمته حتى هذه النقطة لإنشاء 5 خدمات مصغّرة microservices مختلفة، وهي تطبيقات أصغر محدودة النطاق.",
"بعد إنشاء هذه البرمجيات، سيكون لديك 5 APIs رائعة للخدمات الصغرى يمكنك عرضها للأصدقاء والعائلة وأصحاب العمل المحتملين، وستحصل أيضًا على شهادة تطوير الواجهة الخلفية وواجهات برمجة التطبيقات."
]
}
@@ -628,7 +632,7 @@
"title": "الحوسبة العلمية باستخدام Python",
"intro": [
"Python هي واحدة من لغات البرمجة الأكثر شعبية ومرونة اليوم. يمكنك استخدامها لكل شيء من البرمجة النصية الأساسية إلى تعلم الآلة.",
- "في شهادة الحوسبة العلمية باستخدام Python، ستتعلم أساسيات Python مثل المتغيرات والحلقات والشروط والدوال. ثم ستصل بسرعة إلى هياكل البيانات المعقدة، والربط الشبكي Networking، وقواعد البيانات العلائقية، وتصوّر البيانات."
+ "في شهادة الحوسبة العلمية باستخدام Python، ستتعلم أساسيات Python مثل المتغيرات والحلقات والشروط والوظيفة. ثم ستصل بسرعة إلى هياكل البيانات المعقدة، والربط الشبكي Networking، وقواعد البيانات العلائقية، وتصوّر البيانات."
],
"note": "",
"blocks": {
@@ -787,6 +791,24 @@
}
}
},
+ "the-odin-project": {
+ "title": "مشروع أودين",
+ "intro": [
+ "The Odin Project is one of those \"What I wish I had when I was learning\" resources. ",
+ "Not everyone has access to a computer science education or the funds to attend an intensive coding school and neither of those is right for everyone anyway.",
+ "This project is designed to fill in the gap for people who are trying to hack it on their own but still want a high quality education."
+ ],
+ "blocks": {
+ "top-learn-html-foundations": {
+ "title": "Learn HTML Foundations",
+ "intro": ["A description is to be determined"]
+ },
+ "top-build-a-recipe-project": {
+ "title": "Learn HTML Foundations by Building a Recipe Page",
+ "intro": ["A description is to be determined"]
+ }
+ }
+ },
"misc-text": {
"certification": "شهادة {{cert}}",
"browse-other": "تصفح الشهادات المجانية الأخرى\n(نوصي بالقيام بها بالترتيب)",
diff --git a/client/i18n/locales/arabic/links.json b/client/i18n/locales/arabic/links.json
index d1b675b924c2e4..c86b1892e839e5 100644
--- a/client/i18n/locales/arabic/links.json
+++ b/client/i18n/locales/arabic/links.json
@@ -2,7 +2,7 @@
"help-translate-link-url": "https://contribute.freecodecamp.org/#/how-to-translate-files",
"top-contributors": "https://www.freecodecamp.org/news/freecodecamp-top-contributors/",
"footer": {
- "about-url": "https://www.freecodecamp.org/news/about/",
+ "about-url": "https://www.freecodecamp.org/arabic/news/about/",
"shop-url": "https://www.freecodecamp.org/shop/",
"support-url": "https://www.freecodecamp.org/arabic/news/support/",
"sponsors-url": "https://www.freecodecamp.org/news/sponsors/",
diff --git a/client/i18n/locales/arabic/motivation.json b/client/i18n/locales/arabic/motivation.json
index ef2f8304ce8f70..ec5ed1d86e6e6f 100644
--- a/client/i18n/locales/arabic/motivation.json
+++ b/client/i18n/locales/arabic/motivation.json
@@ -1,864 +1,142 @@
{
"compliments": [
- "Over the top!",
- "Down the rabbit hole we go!",
- "Bring that rain!",
- "Target acquired.",
- "Feel that need for speed!",
- "You've got guts!",
- "We have liftoff!",
- "To infinity and beyond!",
- "Encore!",
- "Onward!",
- "Challenge destroyed!",
- "It's on like Donkey Kong!",
- "Power level? It's over 9000!",
- "Coding spree!",
- "Code long and prosper.",
- "The crowd goes wild!",
- "One for the Guinness book!",
- "Flawless victory!",
- "Most efficient!",
- "You've got the touch!",
- "You're on fire!",
- "The town is now red!",
- "To the nines!",
- "To the Batmobile!",
- "Pull out all the stops!",
- "You're a wizard, Harry!",
- "You're an all star!",
- "Way to go!",
- "Outta sight!",
- "You're crushing it!",
- "What sorcery is this?",
- "The world rejoices!",
- "That's the way it's done!",
- "You rock!",
- "Woo-hoo!",
- "We knew you could do it!",
- "Hyper Combo Finish!",
- "Nothing but net!",
- "Boom-shakalaka!",
- "You're a shooting star!",
- "You're unstoppable!",
- "Way cool!",
- "Walk on that sunshine!",
- "Keep on trucking!",
- "Off the charts!",
- "There is no spoon!",
- "Cranked it up to 11!",
- "Escape velocity reached!",
- "You make this look easy!",
- "Passed with flying colors!",
- "You've got this!",
- "Happy, happy, joy, joy!",
- "Tomorrow, the world!",
- "Your powers combined!",
- "It's alive. It's alive!",
- "Sonic Boom!",
- "Here's looking at you, Code!",
- "Ride like the wind!",
- "Legen - wait for it - dary!",
- "Ludicrous Speed! Go!",
- "Most triumphant!",
- "One loop to rule them all!",
- "By the power of Grayskull!",
- "You did it!",
- "Storm that castle!",
- "Face-melting guitar solo!",
- "Checkmate!",
- "Bodacious!",
- "Tubular!",
- "You're outta sight!",
- "Keep calm and code on!",
- "Even sad panda smiles!",
- "Even grumpy cat approves!",
- "Kool Aid Man says oh yeah!",
- "Bullseye!",
- "Far out!",
- "You're heating up!",
- "Standing ovation!",
- "Nice one!",
- "All right!",
- "Hasta la vista, challenge!",
- "Terminated.",
- "Off the hook!",
- "Thundercats, Hooo!",
- "Shiver me timbers!",
- "Raise the roof!",
- "Bingo!",
- "Even Honey Badger cares!",
- "Helm, Warp Nine. Engage!",
- "Gotta code 'em all!",
- "Spool up the FTL drive!",
- "Cool beans!",
- "They're in another castle.",
- "Power UP!",
- "Pikachu chooses you!",
- "I gotta have more cowbell.",
- "Gotta go fast!",
- "Yippee!",
- "Cowabunga!",
- "Moon Prism Power!",
- "Plus Ultra!",
- "Everything's coming up Milhouse!"
+ "ياي! روعة!",
+ "!جزاك الله خير",
+ "!فعلا أحسنت",
+ "!ربنا يسعد قلبك",
+ "!صبرت ونلت",
+ "!عبقري ياناس",
+ "!برافو",
+ "!ما شاء الله",
+ "!ياواد ياشاطر",
+ "!إيه الشطارة دي ياناس",
+ "!مقطع السمكة وديلها",
+ "!مبروك التفوق",
+ "!تحية كبيرة",
+ "!عشت يا باشا",
+ "!مفيش زيك بجد",
+ "!هو حلم ولا علم",
+ "!قمة الروعة",
+ "!طلعت برا المريخ",
+ "!أدي الكلام ولا بلاش",
+ "!مفيش حد أدك"
],
"motivationalQuotes": [
{
- "quote": "Whatever you are, be a good one.",
- "author": "Abraham Lincoln"
+ "quote": "ليست السعادة في أن تعمل دائمًا ما تريد بل في أن تريد ما تعمله.",
+ "author": "جان-بول سارتر"
},
{
- "quote": "A change in perspective is worth 80 IQ points.",
- "author": "Alan Kay"
+ "quote": "لا يوجد رجل فاشل ولكن يوجد رجل بدأ من القاع وبقي فيه.",
+ "author": "فولتير"
},
{
- "quote": "The best way to predict the future is to invent it.",
- "author": "Alan Kay"
+ "quote": "الرجل القوي يعمل والضعيف يتمنى.",
+ "author": "جورج برنارد شو"
},
{
- "quote": "The future is not laid out on a track. It is something that we can decide, and to the extent that we do not violate any known laws of the universe, we can probably make it work the way that we want to.",
- "author": "Alan Kay"
+ "quote": "قليل من العلم مع العمل به أنفع من كثير من العلم مع قلة العمل به.",
+ "author": "أفلاطون"
},
{
- "quote": "We can only see a short distance ahead, but we can see plenty there that needs to be done.",
- "author": "Alan Turing"
+ "quote": "العمل المتواصل هو الأساس للنجاح.",
+ "author": "فادي عزام"
},
{
- "quote": "In the depth of winter, I finally learned that within me there lay an invincible summer.",
- "author": "Albert Camus"
+ "quote": "التعلم أفضل من النجاح، فالنجاح يأتي بعد التعلم.",
+ "author": "الحسن البصري"
},
{
- "quote": "A person who never made a mistake never tried anything new.",
- "author": "Albert Einstein"
+ "quote": "لا تخاف من الإختبار، لأن الإختبار هو الطريق الوحيد للإكتشاف.",
+ "author": "علي أحمد سعيد إسبر"
},
{
- "quote": "Creativity is intelligence having fun.",
- "author": "Albert Einstein"
+ "quote": "كل من يعمل بجد يحصل على ما يريد.",
+ "author": "عبد الرحمن الأبنودي"
},
{
- "quote": "I have no special talents. I am only passionately curious.",
- "author": "Albert Einstein"
+ "quote": "خذ من اليوم عبرة، وخذ من الأمس خبرة.",
+ "author": "سلمان العودة"
},
{
- "quote": "Life is like riding a bicycle. To keep your balance, you must keep moving.",
- "author": "Albert Einstein"
+ "quote": "الفارق بين المستحيل و الممكن يتوقف على عزيمة المرء و اصراره.",
+ "author": "محمد علي كلاي"
},
{
- "quote": "Make everything as simple as possible, but not simpler.",
- "author": "Albert Einstein"
+ "quote": "اعطني اذنك اعطك صوتاً .. اعطني عقلك اعطك فكرة.",
+ "author": "أبو جعفر المنصور"
},
{
- "quote": "Never memorize something that you can look up.",
- "author": "Albert Einstein"
+ "quote": "أينما ركزت الانتباه تدفقت الطاقة و ظهرت النتيجة.",
+ "author": "إبراهيم الفقي"
},
{
- "quote": "Once we accept our limits, we go beyond them.",
- "author": "Albert Einstein"
+ "quote": "تضعك المعرفة في صفوف الحكماء .. و يضعك العمل في صفوف الناجحين .. و يضعك التفاهم في صفوف السعداء.",
+ "author": "إبراهيم الفقي"
},
{
- "quote": "Play is the highest form of research.",
- "author": "Albert Einstein"
+ "quote": "الذكي يعرف من اجاباته ، والحكيم يعرف من اسئلته.",
+ "author": "نجيب محفوظ"
},
{
- "quote": "We cannot solve our problems with the same thinking we used when we created them.",
- "author": "Albert Einstein"
+ "quote": "أكتبوا أحسن ما تسمعون، و احفـظوا أحسن ما تكتبون، و تحدثوا بأحسن ما تسمعون.",
+ "author": "عبد الله بن المقفع"
},
{
- "quote": "Wisdom is not a product of schooling but of the lifelong attempt to acquire it.",
- "author": "Albert Einstein"
+ "quote": "الإنسان في كل مرحلة من مراحل حياته .. مازال يولد.",
+ "author": "مصطفى السباعي"
},
{
- "quote": "Your imagination is your preview of life's coming attractions.",
- "author": "Albert Einstein"
+ "quote": "من لم يحتمل ذل التعلم ساعة ، بقي في ذل الجهل أبداً .",
+ "author": "الاصمعي"
},
{
- "quote": "There is only one corner of the universe you can be certain of improving, and that's your own self.",
- "author": "Aldous Huxley"
+ "quote": "طوبى لمن جمع بين همة الشباب وحكمة الشيوخ.",
+ "author": "طه حسين"
},
{
- "quote": "I am thankful for my struggle because, without it, I wouldn't have stumbled across my strength.",
- "author": "Alex Elle"
+ "quote": "إياك والرضى عن نفسك فإنه يضطرك إلى الخمول، وإياك والعجب فإنه يورطك في الحمق، وإياك والغرور فإنه يظهر للناس نقائصك كلها ولا يخفيها.",
+ "author": "طه حسين"
},
{
- "quote": "The most common way people give up their power is by thinking they don't have any.",
- "author": "Alice Walker"
+ "quote": "السعادة هي ذلك الإحساس الغريب الذي يراودنا حينما تشغلنا ظروف الحياة عن أن نكون أشقياء.",
+ "author": "طه حسين"
},
{
- "quote": "Follow your inner moonlight. Don't hide the madness.",
- "author": "Allen Ginsberg"
+ "quote": "يقول لك المرشدون : اقرأ ما ينفعك ، و لكني أقول : بل انتفع بما تقرأ.",
+ "author": "عباس محمود العقاد"
},
{
- "quote": "The most difficult thing is the decision to act. The rest is merely tenacity.",
- "author": "Amelia Earhart"
+ "quote": "من غير تحديد الأهداف بوضوح يصعب الحديث عن قرارات جيدة.",
+ "author": "خولة القزويني"
},
{
- "quote": "Life shrinks or expands in proportion with one's courage.",
- "author": "Anaïs Nin"
+ "quote": "لتكن أعمالك مصغية دائماً إلى صوت هدفك الأسمى.",
+ "author": "خولة القزويني"
},
{
- "quote": "Weeks of programming can save you hours of planning.",
- "author": "Unknown"
+ "quote": "الضعيف هو الغبى الذى لا يعرف سر قوته.",
+ "author": "نجيب محفوظ"
},
{
- "quote": "Quality is not an act, it is a habit.",
- "author": "Aristotle"
+ "quote": "على المرء أن يختار أفكاره كما يختار ملابسه و كتبه و أصدقاءه و مسكنه.",
+ "author": "كفاح فياض"
},
{
- "quote": "Start where you are. Use what you have. Do what you can.",
- "author": "Arthur Ashe"
+ "quote": "قد تكون أفضل الطرق أصعبها و لكن عليك دائما اتباعها ، إذ أن الاعتياد عليها سيجعل الامور تبدو سهلة.",
+ "author": "أبو الطيب المتنبي"
},
{
- "quote": "Nothing is impossible, the word itself says \"I'm possible\"!",
- "author": "Audrey Hepburn"
+ "quote": "من المحتمل ألا تستطيع التحكم في الظروف ، و لكنك تستـطيع التحكم في أفكارك ، فالتفكير الايجابي يؤدي الى الفعل الايجابي و النتائج الايجابية.",
+ "author": "إبراهيم الفقي"
},
{
- "quote": "Every strike brings me closer to the next home run.",
- "author": "Babe Ruth"
+ "quote": "الفكرة باختصار : ضع هدفاً ، و لا تتخل عنه حتى تحققه.",
+ "author": "خولة القزويني"
},
{
- "quote": "By failing to prepare, you are preparing to fail.",
- "author": "Benjamin Franklin"
- },
- {
- "quote": "Tell me and I forget. Teach me and I remember. Involve me and I learn.",
- "author": "Benjamin Franklin"
- },
- {
- "quote": "Well done is better than well said.",
- "author": "Benjamin Franklin"
- },
- {
- "quote": "There are no short cuts to any place worth going.",
- "author": "Beverly Sills"
- },
- {
- "quote": "Controlling complexity is the essence of computer programming.",
- "author": "Brian Kernighan"
- },
- {
- "quote": "I fear not the man who has practiced 10,000 kicks once, but I fear the man who has practiced one kick 10,000 times.",
- "author": "Bruce Lee"
- },
- {
- "quote": "There are far, far better things ahead than any we leave behind.",
- "author": "C.S. Lewis"
- },
- {
- "quote": "We are what we believe we are.",
- "author": "C.S. Lewis"
- },
- {
- "quote": "With the possible exception of the equator, everything begins somewhere.",
- "author": "C.S. Lewis"
- },
- {
- "quote": "You are never too old to set another goal, or to dream a new dream.",
- "author": "C.S. Lewis"
- },
- {
- "quote": "Somewhere, something incredible is waiting to be known.",
- "author": "Carl Sagan"
- },
- {
- "quote": "When you have a dream, you've got to grab it and never let go.",
- "author": "Carol Burnett"
- },
- {
- "quote": "If you're not making mistakes, then you're not making decisions.",
- "author": "Catherine Cook"
- },
- {
- "quote": "Find what you love and let it kill you.",
- "author": "Charles Bukowski"
- },
- {
- "quote": "What matters most is how well you walk through the fire.",
- "author": "Charles Bukowski"
- },
- {
- "quote": "It is not the strongest of the species that survive, nor the most intelligent, but the one most responsive to change.",
- "author": "Charles Darwin"
- },
- {
- "quote": "The details are not the details. They make the design.",
- "author": "Charles Eames"
- },
- {
- "quote": "Creativity is more than just being different. Anybody can plan weird. That's easy. What's hard is to be as simple as Bach. Making the simple, awesomely simple, that's creativity.",
- "author": "Charles Mingus"
- },
- {
- "quote": "Life is 10% what happens to you and 90% how you react to it.",
- "author": "Charles R. Swindoll"
- },
- {
- "quote": "You will do foolish things, but do them with enthusiasm.",
- "author": "Colette"
- },
- {
- "quote": "It does not matter how slowly you go as long as you do not stop.",
- "author": "Confucius"
- },
- {
- "quote": "Real knowledge is to know the extent of one's ignorance.",
- "author": "Confucius"
- },
- {
- "quote": "The past cannot be changed. The future is yet in your power.",
- "author": "Confucius"
- },
- {
- "quote": "Looking at code you wrote more than two weeks ago is like looking at code you are seeing for the first time.",
- "author": "Dan Hurvitz"
- },
- {
- "quote": "Someday is not a day of the week.",
- "author": "Denise Brennan-Nelson"
- },
- {
- "quote": "UNIX is simple. It just takes a genius to understand its simplicity.",
- "author": "Dennis Ritchie"
- },
- {
- "quote": "The way I see it, if you want the rainbow, you gotta put up with the rain!",
- "author": "Dolly Parton"
- },
- {
- "quote": "Computers are good at following instructions, but not at reading your mind.",
- "author": "Donald Knuth"
- },
- {
- "quote": "A good programmer is someone who always looks both ways before crossing a one-way street.",
- "author": "Doug Linder"
- },
- {
- "quote": "Creativity is a wild mind and a disciplined eye.",
- "author": "Dorothy Parker"
- },
- {
- "quote": "Tough times never last, but tough people do.",
- "author": "Dr. Robert Schuller"
- },
- {
- "quote": "If things start happening, don't worry, don't stew, just go right along and you'll start happening too.",
- "author": "Dr. Seuss"
- },
- {
- "quote": "Do not go gentle into that good night. Rage, rage against the dying of the light.",
- "author": "Dylan Thomas"
- },
- {
- "quote": "The question of whether computers can think is like the question of whether submarines can swim.",
- "author": "E.W. Dijkstra"
- },
- {
- "quote": "Any code of your own that you haven't looked at for six or more months might as well have been written by someone else.",
- "author": "Eagleson's Law"
- },
- {
- "quote": "Do one thing every day that scares you.",
- "author": "Eleanor Roosevelt"
- },
- {
- "quote": "With the new day comes new strength and new thoughts.",
- "author": "Eleanor Roosevelt"
- },
- {
- "quote": "You must do the things you think you cannot do.",
- "author": "Eleanor Roosevelt"
- },
- {
- "quote": "Light tomorrow with today.",
- "author": "Elizabeth Barrett Browning"
- },
- {
- "quote": "If your dreams do not scare you, they are not big enough.",
- "author": "Ellen Johnson Sirleaf"
- },
- {
- "quote": "Forever is composed of nows.",
- "author": "Emily Dickinson"
- },
- {
- "quote": "Computer science education cannot make anybody an expert programmer any more than studying brushes and pigment can make somebody an expert painter.",
- "author": "Eric Raymond"
- },
- {
- "quote": "If you don't risk anything, you risk even more.",
- "author": "Erica Jong"
- },
- {
- "quote": "The world breaks everyone, and afterward, many are strong at the broken places.",
- "author": "Ernest Hemingway"
- },
- {
- "quote": "There is nothing noble in being superior to your fellow man; true nobility is being superior to your former self.",
- "author": "Ernest Hemingway"
- },
- {
- "quote": "Never confuse a single defeat with a final defeat.",
- "author": "F. Scott Fitzgerald"
- },
- {
- "quote": "I attribute my success to this - I never gave or took any excuse.",
- "author": "Florence Nightingale"
- },
- {
- "quote": "The best revenge is massive success.",
- "author": "Frank Sinatra"
- },
- {
- "quote": "The only limit to our realization of tomorrow, will be our doubts of today.",
- "author": "Franklin D. Roosevelt"
- },
- {
- "quote": "Right or wrong, it's very pleasant to break something from time to time.",
- "author": "Fyodor Dostoevsky"
- },
- {
- "quote": "The harder I work, the luckier I get.",
- "author": "Gary Player"
- },
- {
- "quote": "Giving up is the only sure way to fail.",
- "author": "Gena Showalter"
- },
- {
- "quote": "The only truly secure system is one that is powered off, cast in a block of concrete and sealed in a lead-lined room with armed guards.",
- "author": "Gene Spafford"
- },
- {
- "quote": "A life spent making mistakes is not only more honorable, but more useful than a life spent doing nothing.",
- "author": "George Bernard Shaw"
- },
- {
- "quote": "First learn computer science and all the theory. Next develop a programming style. Then forget all that and just hack.",
- "author": "George Carrette"
- },
- {
- "quote": "Discovering the unexpected is more important than confirming the known.",
- "author": "George Box"
- },
- {
- "quote": "We only see what we know.",
- "author": "Goethe"
- },
- {
- "quote": "Without hard work, nothing grows but weeds.",
- "author": "Gordon B. Hinckley"
- },
- {
- "quote": "The function of good software is to make the complex appear to be simple.",
- "author": "Grady Booch"
- },
- {
- "quote": "When you know that you're capable of dealing with whatever comes, you have the only security the world has to offer.",
- "author": "Harry Browne"
- },
- {
- "quote": "Pain is inevitable. Suffering is optional.",
- "author": "Haruki Murakami"
- },
- {
- "quote": "Optimism is the faith that leads to achievement. Nothing can be done without hope and confidence.",
- "author": "Helen Keller"
- },
- {
- "quote": "The price of anything is the amount of life you exchange for it.",
- "author": "Henry David Thoreau"
- },
- {
- "quote": "Whether you think you can or think you can't, you're right.",
- "author": "Henry Ford"
- },
- {
- "quote": "The most exciting phrase to hear in science, the one that heralds discoveries, is not 'Eureka!' but 'Now that's funny…'",
- "author": "Isaac Asimov"
- },
- {
- "quote": "What you do makes a difference. And you have to decide what kind of difference you want to make.",
- "author": "Jane Goodall"
- },
- {
- "quote": "We are all failures. At least the best of us are.",
- "author": "J.M. Barrie"
- },
- {
- "quote": "You can't wait for inspiration. You have to go after it with a club.",
- "author": "Jack London"
- },
- {
- "quote": "Don't wish it were easier, wish you were better.",
- "author": "Jim Rohn"
- },
- {
- "quote": "By seeking and blundering we learn.",
- "author": "Johann Wolfgang von Goethe"
- },
- {
- "quote": "Knowing is not enough; we must apply. Wishing is not enough; we must do.",
- "author": "Johann Wolfgang von Goethe"
- },
- {
- "quote": "We first make our habits, then our habits make us.",
- "author": "John Dryden"
- },
- {
- "quote": "The power of imagination makes us infinite.",
- "author": "John Muir"
- },
- {
- "quote": "May you live every day of your life.",
- "author": "Jonathan Swift"
- },
- {
- "quote": "Perseverance is failing 19 times and succeeding the 20th.",
- "author": "Julie Andrews"
- },
- {
- "quote": "The work of today is the history of tomorrow, and we are its makers.",
- "author": "Juliette Gordon Low"
- },
- {
- "quote": "If you reveal your secrets to the wind, you should not blame the wind for revealing them to the trees.",
- "author": "Kahlil Gibran"
- },
- {
- "quote": "Optimism is an occupational hazard of programming; feedback is the treatment.",
- "author": "Kent Beck"
- },
- {
- "quote": "Opportunity does not knock, it presents itself when you beat down the door.",
- "author": "Kyle Chandler"
- },
- {
- "quote": "To iterate is human, to recurse divine.",
- "author": "Peter Deutsch"
- },
- {
- "quote": "A good traveler has no fixed plans and is not intent on arriving.",
- "author": "Lao Tzu"
- },
- {
- "quote": "An ant on the move does more than a dozing ox.",
- "author": "Lao Tzu"
- },
- {
- "quote": "Do the difficult things while they are easy and do the great things while they are small. A journey of a thousand miles must begin with a single step.",
- "author": "Lao Tzu"
- },
- {
- "quote": "That's the thing about people who think they hate computers. What they really hate is lousy programmers.",
- "author": "Larry Niven"
- },
- {
- "quote": "It had long since come to my attention that people of accomplishment rarely sat back and let things happen to them. They went out and happened to things.",
- "author": "Leonardo da Vinci"
- },
- {
- "quote": "If you're any good at all, you know you can be better.",
- "author": "Lindsay Buckingham"
- },
- {
- "quote": "If people never did silly things, nothing intelligent would ever get done.",
- "author": "Ludwig Wittgenstein"
- },
- {
- "quote": "You only live once, but if you do it right, once is enough.",
- "author": "Mae West"
- },
- {
- "quote": "Live as if you were to die tomorrow. Learn as if you were to live forever.",
- "author": "Mahatma Gandhi"
- },
- {
- "quote": "Strength does not come from physical capacity. It comes from an indomitable will.",
- "author": "Mahatma Gandhi"
- },
- {
- "quote": "One person's 'paranoia' is another person's 'engineering redundancy'.",
- "author": "Marcus J. Ranum"
- },
- {
- "quote": "Nothing in life is to be feared, it is only to be understood. Now is the time to understand more, so that we may fear less.",
- "author": "Marie Curie"
- },
- {
- "quote": "If you have everything under control, you're not moving fast enough.",
- "author": "Mario Andretti"
- },
- {
- "quote": "Education: the path from cocky ignorance to miserable uncertainty.",
- "author": "Mark Twain"
- },
- {
- "quote": "It ain't what you don't know that gets you into trouble. It's what you know for sure that just ain't so.",
- "author": "Mark Twain"
- },
- {
- "quote": "The secret of getting ahead is getting started.",
- "author": "Mark Twain"
- },
- {
- "quote": "The two most important days in your life are the day you are born and the day you find out why.",
- "author": "Mark Twain"
- },
- {
- "quote": "Twenty years from now you will be more disappointed by the things that you didn't do than by the ones you did do. So throw off the bowlines. Sail away from the safe harbor. Catch the trade winds in your sails.",
- "author": "Mark Twain"
- },
- {
- "quote": "Any fool can write code that a computer can understand. Good programmers write code that humans can understand.",
- "author": "Martin Fowler"
- },
- {
- "quote": "I know, somehow, that only when it is dark enough can you see the stars.",
- "author": "Martin Luther King Jr."
- },
- {
- "quote": "It is never too late to be what you might have been.",
- "author": "Mary Anne Evans"
- },
- {
- "quote": "Nothing will work unless you do.",
- "author": "Maya Angelou"
- },
- {
- "quote": "You can't use up creativity. The more you use, the more you have.",
- "author": "Maya Angelou"
- },
- {
- "quote": "We delight in the beauty of the butterfly, but rarely admit the changes it has gone through to achieve that beauty.",
- "author": "Maya Angelou"
- },
- {
- "quote": "We may encounter many defeats, but we must not be defeated.",
- "author": "Maya Angelou"
- },
- {
- "quote": "Everybody has talent, but ability takes hard work.",
- "author": "Michael Jordan"
- },
- {
- "quote": "I've missed more than 9,000 shots during my career. I've lost almost 300 games. 26 times, I've been trusted to take the game winning shot and missed. I've failed over and over and over again in my life. And that is why I succeed.",
- "author": "Michael Jordan"
- },
- {
- "quote": "Impossible is just a big word thrown around by small men who find it easier to live in the world they've been given than to explore the power they have to change it. Impossible is not a fact. It's an opinion. Impossible is not a declaration. It's a dare. Impossible is potential. Impossible is temporary. Impossible is nothing.",
- "author": "Muhammad Ali"
- },
- {
- "quote": "A winner is a dreamer who never gives up.",
- "author": "Nelson Mandela"
- },
- {
- "quote": "It always seems impossible until it's done.",
- "author": "Nelson Mandela"
- },
- {
- "quote": "Failure will never overtake me if my determination to succeed is strong enough.",
- "author": "Og Mandino"
- },
- {
- "quote": "I am not young enough to know everything.",
- "author": "Oscar Wilde"
- },
- {
- "quote": "There is only one thing that makes a dream impossible to achieve: the fear of failure.",
- "author": "Paulo Coelho"
- },
- {
- "quote": "Never go to bed mad. Stay up and fight.",
- "author": "Phyllis Diller"
- },
- {
- "quote": "You can't cross the sea merely by standing and staring at the water.",
- "author": "Rabindranath Tagore"
- },
- {
- "quote": "The only person you are destined to become is the person you decide to be.",
- "author": "Ralph Waldo Emerson"
- },
- {
- "quote": "What you do speaks so loudly that I cannot hear what you say.",
- "author": "Ralph Waldo Emerson"
- },
- {
- "quote": "People who are crazy enough to think they can change the world, are the ones who do.",
- "author": "Rob Siltanen"
- },
- {
- "quote": "The best way out is always through.",
- "author": "Robert Frost"
- },
- {
- "quote": "Today's accomplishments were yesterday's impossibilities.",
- "author": "Robert H. Schuller"
- },
- {
- "quote": "Don't be satisfied with stories, how things have gone with others. Unfold your own myth.",
- "author": "Rumi"
- },
- {
- "quote": "Forget safety. Live where you fear to live. Destroy your reputation. Be notorious.",
- "author": "Rumi"
- },
- {
- "quote": "Sell your cleverness and buy bewilderment.",
- "author": "Rumi"
- },
- {
- "quote": "The cure for pain is in the pain.",
- "author": "Rumi"
- },
- {
- "quote": "Have no fear of perfection - you'll never reach it.",
- "author": "Salvador Dalí"
- },
- {
- "quote": "Don't watch the clock. Do what it does. Keep going.",
- "author": "Sam Levenson"
- },
- {
- "quote": "Ever Tried. Ever failed. No matter. Try again. Fail again. Fail better.",
- "author": "Samuel Beckett"
- },
- {
- "quote": "The more you know, the more you realize you know nothing.",
- "author": "Socrates"
- },
- {
- "quote": "The greatest enemy of knowledge is not ignorance, it is the illusion of knowledge.",
- "author": "Stephen Hawking"
- },
- {
- "quote": "The universe doesn't allow perfection.",
- "author": "Stephen Hawking"
- },
- {
- "quote": "Whether you want to uncover the secrets of the universe, or you want to pursue a career in the 21st century, basic computer programming is an essential skill to learn.",
- "author": "Stephen Hawking"
- },
- {
- "quote": "The scariest moment is always just before you start.",
- "author": "Stephen King"
- },
- {
- "quote": "You can, you should, and if you're brave enough to start, you will.",
- "author": "Stephen King"
- },
- {
- "quote": "Arise, Awake and Stop not until the goal is reached.",
- "author": "Swami Vivekananda"
- },
- {
- "quote": "It is said that your life flashes before your eyes just before you die. That is true, it's called Life.",
- "author": "Terry Pratchett"
- },
- {
- "quote": "Believe you can and you're halfway there.",
- "author": "Theodore Roosevelt"
- },
- {
- "quote": "I have not failed. I've just found 10,000 ways that won't work.",
- "author": "Thomas A. Edison"
- },
- {
- "quote": "Our greatest weakness lies in giving up. The most certain way to succeed is always to try just one more time.",
- "author": "Thomas A. Edison"
- },
- {
- "quote": "The harder the conflict, the more glorious the triumph.",
- "author": "Thomas Paine"
- },
- {
- "quote": "The Web as I envisaged it, we have not seen it yet. The future is still so much bigger than the past.",
- "author": "Tim Berners-Lee"
- },
- {
- "quote": "Failure is the condiment that gives success its flavor.",
- "author": "Truman Capote"
- },
- {
- "quote": "Those who says it cannot be done should not interrupt the person doing it.",
- "author": "Unknown"
- },
- {
- "quote": "Look at usual things with unusual eyes.",
- "author": "Vico Magistetti"
- },
- {
- "quote": "Even if you fall on your face, you're still moving forward.",
- "author": "Victor Kiam"
- },
- {
- "quote": "It's not whether you get knocked down, it's whether you get up.",
- "author": "Vince Lombardi"
- },
- {
- "quote": "I dream my painting and I paint my dream.",
- "author": "Vincent van Gogh"
- },
- {
- "quote": "Great things are done by a series of small things brought together.",
- "author": "Vincent van Gogh"
- },
- {
- "quote": "Let us cultivate our garden.",
- "author": "Voltaire"
- },
- {
- "quote": "Aim for the moon. If you miss, you may hit a star.",
- "author": "W. Clement Stone"
- },
- {
- "quote": "The way to get started is to quit talking and begin doing.",
- "author": "Walt Disney"
- },
- {
- "quote": "You miss 100% of the shots you don't take.",
- "author": "Wayne Gretzky"
- },
- {
- "quote": "Don't let yesterday take up too much of today.",
- "author": "Will Rogers"
- },
- {
- "quote": "Even if you're on the right track, you'll get run over if you just sit there.",
- "author": "Will Rogers"
- },
- {
- "quote": "Do not wait to strike till the iron is hot; but make it hot by striking.",
- "author": "William Butler Yeats"
- },
- {
- "quote": "You cannot swim for new horizons until you have courage to lose sight of the shore.",
- "author": "William Faulkner"
- },
- {
- "quote": "Be not afraid of greatness. Some are born great, some achieve greatness, and others have greatness thrust upon them.",
- "author": "William Shakespeare"
- },
- {
- "quote": "We know what we are, but not what we may be.",
- "author": "William Shakespeare"
- },
- {
- "quote": "In theory there is no difference between theory and practice. In practice there is.",
- "author": "Yogi Berra"
- },
- {
- "quote": "You can see a lot by just looking.",
- "author": "Yogi Berra"
- },
- {
- "quote": "There is no elevator to success, you have to take the stairs.",
- "author": "Zig Ziglar"
- },
- {
- "quote": "You don't have to be great to start, but you have to start to be great.",
- "author": "Zig Ziglar"
+ "quote": "سر النجاح في الحياة أن تواجه مصاعبها بثبات الطير في ثورة العاصفة.",
+ "author": "مصطفى السباعي"
}
]
}
diff --git a/client/i18n/locales/arabic/translations.json b/client/i18n/locales/arabic/translations.json
index 8ef010ee660f6c..a0bba047beb9c2 100644
--- a/client/i18n/locales/arabic/translations.json
+++ b/client/i18n/locales/arabic/translations.json
@@ -1,7 +1,7 @@
{
"buttons": {
- "logged-in-cta-btn": "ابدأ (مجاني)",
- "logged-out-cta-btn": "قم بتسجيل الدخول لحفظ تقدّمك (مجاني)",
+ "logged-in-cta-btn": "ابدأ (بالمجان)",
+ "logged-out-cta-btn": "سجل الدخول لحفظ تقدّمك (بالمجان)",
"view-curriculum": "عرض المنهج الدراسي",
"first-lesson": "انتقل إلى الدرس الأول",
"close": "أغلق",
@@ -11,11 +11,12 @@
"view": "عرض",
"view-code": "أظهار الكود",
"view-project": "إظهار المشروع",
+ "view-cert-title": "عرض {{certTitle}}",
"show-cert": "عرض الشهادة",
"claim-cert": "المطالبة بالشهادة",
"save-progress": "حفظ التقدم",
- "accepted-honesty": "لقد قبلت سياسة الصدق الأكاديمي الخاصة بنا.",
- "agree": "موافق",
+ "accepted-honesty": "لقد وافقت على سياستنا للصدق الأكاديمي.",
+ "agree-honesty": "أوافق على سياسة freeCodeCamp للصدق الأكاديمي.",
"save-portfolio": "حفظ عنصر الحافظة هذا",
"remove-portfolio": "إزالة عنصر الحافظة هذا",
"add-portfolio": "إضافة عنصر حافظة جديد",
@@ -34,7 +35,7 @@
"news": "الأخبار",
"donate": "تبرّع",
"update-settings": "تحديث إعدادات حسابي",
- "sign-me-out": "قم بتسجيل خروجي من freeCodeCamp",
+ "sign-me-out": "سجل خروجي من freeCodeCamp",
"flag-user": "الإبلاغ عن حساب هذا المستخدم لسوء الاستخدام",
"current-challenge": "انتقل إلى التحدي الحالي",
"try-again": "حاول مرة أخرى",
@@ -46,13 +47,13 @@
"ask-for-help": "طلب المساعدة",
"create-post": "إنشاء منشور مساعدة في المنتدى",
"cancel": "إلغاء",
- "reset-lesson": "إعادة تعيين هذا الدرس",
+ "reset-lesson": "أعد الدرس ألى حالته الأولية",
"run": "تشغيل",
"run-test": "تشغيل الاختبارات (Ctrl + Enter)",
"check-code": "تيقن من كودك (Ctrl + Enter)",
"check-code-2": "تيقن من كودك",
"reset": "إعادة ضبط",
- "reset-code": "إعادة تعيين كل الكود",
+ "reset-step": "إعادة الخطوة إلى حالتها الأولية",
"help": "مساعدة",
"get-help": "الحصول على المساعدة",
"watch-video": "شاهد الفيديو",
@@ -88,24 +89,24 @@
"shawn": {
"location": "شون وانغ في سنغافورة",
"occupation": "مهندس برمجيات في أمازون ",
- "testimony": "\"من المخيف تغيير الحياة المهنية. لقد اكتسبت الثقة فقط بأنني أستطيع البرمجة من خلال العمل على مئات الساعات من الدروس المجانية على freeCodeCamp. في غضون عام كان لدي وظيفة من ستة أرقام كمهندس برمجيات. freeCodeCampغيّر حياتي. \""
+ "testimony": "\"من المخيف تغيير الحياة المهنية. لقد اكتسبت الثقة بأنني أستطيع البرمجة بممارسة مئات الساعات من الدروس المجانية في freeCodeCamp فقط. في غضون عام كان لدي وظيفة بمرتب ذات ست أرقام كمهندس برمجيات. freeCodeCampغيّر حياتي. \""
},
"sarah": {
"location": "سارة شيما في نيجيريا",
"occupation": "مهندس برمجيات في ChatDesk ",
- "testimony": "freeCodeCampكان المدخل إلى مهنتي كمطور برمجيات. المنهج الدراسي الجيد والتنظيم أخذ معرفتي البرمجية من مستوى مبتدئ إلى مستوى واثق جداً. كان كل ما أحتاجه للحصول على أول وظيفة لي في شركة مدهشة.\""
+ "testimony": "\"كان freeCodeCamp المدخل إلى مهنتي كمطور برمجيات. المنهج الدراسي الجيد والتنظيم أخذ معرفتي البرمجية من مستوى مبتدئ إلى مستوى واثق جداً. كان كل ما احتاجه للحصول على أول وظيفة لي في شركة مدهشة.\""
},
"emma": {
"location": "إيما بوستيان في السويد",
"occupation": "مهندس برمجيات في Spotify ",
- "testimony": "\"لقد ناضلت دائمًا لتعلم JavaScript. لقد أخذت العديد من الدورات ولكن دورة freeCodeCamp's كانت تلك العالقة. إن دراسة JavaScript وكذلك هياكل البيانات والخوارزميات على freeCodeCamp أعطتني المهارات والثقة التي كنت بحاجة إليها لإبراز عملي كمهندس برمجيات في Spotify.\""
+ "testimony": "\"لقد ناضلت دائمًا لتعلم JavaScript. لقد أخذت العديد من الدورات ولكن دورة freeCodeCamp التي دامت. إن دراسة JavaScript وكذلك هياكل البيانات والخوارزميات على freeCodeCamp أعطتني المهارات والثقة التي كنت بحاجة إليها لإبراز عملي كمهندس برمجيات في Spotify.\""
}
},
"certification-heading": "احصل على شهادات معتمدة مجانية في:"
},
"settings": {
"share-projects": "شارك مشاريعك غير التي بـ freeCodeCamp أو مقالاتك أو الـ pull requests الخاصه بك.",
- "privacy": "الإعدادات في هذا القسم تمكنك من التحكم في ما يظهر في حافظة حسابك العامة على freeCodeCamp. أضغت على زر أحفظ لحفظ تغيراتك.",
+ "privacy": "الإعدادات في هذا القسم تمكنك من التحكم في ما يظهر في portfolio العامة على freeCodeCamp. أضغت على زر أحفظ لحفظ تغيراتك.",
"data": "لمعرفة البيانات التي نحتفظ بها على حسابك، انقر فوق الزر \"تحميل بياناتك\" أدناه",
"disabled": "سيتم إخفاء شهاداتك، إذا تم تعيينها إلى خاصّة.",
"private-name": "اسمك لن يظهر على شهاداتك، إذا تم التعيين إلى شخصي.",
@@ -142,7 +143,7 @@
"my-location": "موقعي",
"my-about": "عني",
"my-points": "نقاطي",
- "my-heatmap": "خريطتي الحرارية",
+ "my-heatmap": "أوقات نشاطي",
"my-certs": "شهاداتي",
"my-portfolio": "حافظتي",
"my-timeline": "خطي الزمني",
@@ -157,12 +158,13 @@
"honesty": "سياسة الصدق الأكاديمي",
"internet": "حضورك على الإنترنت",
"portfolio": "إعدادات المحفظة",
- "privacy": "إعدادات الخصوصية"
+ "privacy": "إعدادات الخصوصية",
+ "personal-info": "البيانات الشخصية"
},
"danger": {
"heading": "منطقة الخطر",
"be-careful": "يرجى توخي الحذر. التغييرات في هذا القسم دائمة.",
- "reset": "إعادة تعيين كل تقدمي",
+ "reset": "أعد تقدمي ألى حالته الأولية",
"delete": "حذف حسابي",
"delete-title": "حذف حسابي",
"delete-p1": "سيؤدي هذا حقًا إلى حذف جميع بياناتك، بما في ذلك جميع معلومات تقدمك وحسابك.",
@@ -170,11 +172,11 @@
"delete-p3": "إذا كان هناك شيء يمكننا فعله بشكل أفضل، ارسل لنا رسالة بريد إلكتروني بدلاً من ذلك وسنقوم بأفضل ما لدينا: <0>{{email}}0>",
"nevermind": "لا أريد حذف حسابي",
"certain": "أنا متأكد 100٪. احذف كل ما يتعلق بهذا الحساب",
- "reset-heading": "إعادة تعيين تقدمي",
+ "reset-heading": "أعد تقدمي ألى حالته الأولية",
"reset-p1": "سيؤدي هذا بالفعل إلى حذف كل تقدمك، نقاطك، التحديات المكتملة، سجلاتنا لمشاريعك، أي شهادات لديك، كل شيء.",
"reset-p2": "لن نكون قادرين على استرجاع أي منها لك في وقت لاحق، حتى لو غيّرت رأيك.",
"nevermind-2": "لا داعي للقلق ، لا أريد حذف كل تقدمي",
- "reset-confirm": "إعادة تعيين كل شيء. أريد أن أبدأ من البداية"
+ "reset-confirm": "أعد كل شيء ألى حالته الأولية. أريد أن أبدأ من البداية"
},
"email": {
"missing": "ليس لديك بريد إلكتروني مرتبط بهذا الحساب.",
@@ -222,7 +224,6 @@
"total-points_plural": "مُجمل النقاط {{count}}",
"points": "{{count}} نقطة في {{date}}",
"points_plural": "{{count}} نقاط في {{date}}",
- "screen-shot": "لقطة شاشة لـ{{title}}",
"page-number": "{{pageNumber}} من {{totalPages}}"
},
"footer": {
@@ -231,7 +232,7 @@
"donation-initiatives": "التبرعات لـ freeCodeCamp تذهب لمبادراتنا التعليمية، وتساعد في دفع تكاليف الخوادم، والخدمات، والموظفين.",
"donate-text": "يمكنك <1>تقديم تبرع قابل للخصم الضريبي هنا 1>.",
"trending-guides": "أدلة إرشادية",
- "our-nonprofit": "منظمتنا الخيرية",
+ "our-nonprofit": "مؤسستنا الخيرية",
"links": {
"about": "حول",
"alumni": "شبكة الخريجين",
@@ -249,6 +250,7 @@
},
"learn": {
"heading": "مرحباً بكم في منهج freeCodeCamp.",
+ "skip-to-content": "Skip to content",
"welcome-1": "مرحباً بعودتك، {{name}}.",
"welcome-2": "مرحباً بك في freeCodeCamp.org",
"start-at-beginning": "إذا كنت جديداً على البرمجة، ننصحك على <0>البدء من البداية0>.",
@@ -272,6 +274,9 @@
"add-subtitles": "المساعدة في تحسين أو إضافة ترجمات",
"wrong-answer": "عذراً، هذه ليست الإجابة الصحيحة. قم بالمحاولة مرة أخرى؟",
"check-answer": "انقر على الزر أدناه للتحقق من إجابتك.",
+ "assignment-not-complete": "يرجى إنهاء المهام",
+ "assignments": "Assignments",
+ "question": "Question",
"solution-link": "رابط الحل",
"github-link": "رابط Github",
"submit-and-go": "أرسل وانتقل إلى التحدي التالي",
@@ -288,8 +293,8 @@
"tried-rsa": "إذا كنت قد جربت طريقة <0>اقرأ-ابحث-اسأل0>، فيمكنك طلب المساعدة في منتدى freeCodeCamp.",
"rsa": "اقرأ ، ابحث ، اسأل",
"rsa-forum": "قبل إجراء موضوع جديدة يرجى الاطلاع على ما إذا كان سؤالك <0> قد تم الإجابة عليه فعلًا في المنتدى 0>.",
- "reset": "إعادة تعيين هذا الدرس؟",
- "reset-warn": "هل أنت متأكد من رغبتك في إعادة تعيين هذا الدرس؟ سيتم إعادة تعيين المحرر والاختبارات.",
+ "reset": "أعد الدرس ألى حالته الأولية؟",
+ "reset-warn": "هل أنت متأكد من رغبتك في إعادة الدرس ألى حالته الأولية؟ سيتم إعادة المحرر والاختبارات إلى حالتهما الأولية.",
"reset-warn-2": "لا يمكن التراجع عن هذا",
"scrimba-tip": "نصيحة: إذا كان المتصفح المصغر يغطي الكود البرمجي ، انقر واسحب لتحريكه. كذلك لا تتردد في إيقاف وتعديل التعليمات البرمجية في الفيديو في أي وقت.",
"chal-preview": "معاينة التحدي",
@@ -297,7 +302,6 @@
"certs": "شهادة {{title}}"
},
"editor-tabs": {
- "info": "معلومات",
"code": "الكود",
"tests": "الاختبارات",
"restart": "أعد التشغيل",
@@ -307,6 +311,10 @@
"notes": "ملاحظات",
"preview": "معاينة"
},
+ "editor-alerts": {
+ "tab-trapped": "الضغط على زر tab سيدرج الآن رمز التباعد",
+ "tab-free": "الضغط على زر tab سينقل تركيز على عنصر إلى العنصر التالي الذي يمكن التركيز عليه الآن"
+ },
"help-translate": "ما زلنا نترجم الشهادات التالية.",
"help-translate-link": "ساعدنا على الترجمة.",
"project-preview-title": "إليك معاينة لما ستقوم ببناؤه",
@@ -332,7 +340,7 @@
"if-help-university": "لقد حققنا قدرا كبيرا من التقدم بالفعل. أدعم منظمتنا الخيرية بالطريق الطويل الذي أمامنا."
},
"donate": {
- "title": "ادعم منظمتنا الخيرية",
+ "title": "ادعم مؤسستنا الخيرية",
"processing": "نحن نقوم بمعالجة تبرعك.",
"redirecting": "جارٍ إعادة توجيهك...",
"thanks": "شكرا على التبرع",
@@ -357,7 +365,6 @@
"become-supporter": "أصبح داعماً",
"duration": "كن داعماً لمرة واحدة لمنظمتنا الخيرية.",
"duration-2": "كن داعماً شهريا لمنظمتنا الخيرية.",
- "duration-3": "كن داعماً سنويا لمنظمتنا الخيرية",
"duration-4": "كن داعماً لمنظمتنا الخيرية",
"nicely-done": "ممتاز، لقد انتهيت لتوك من {{block}}.",
"credit-card": "بطاقة ائتمان",
@@ -372,8 +379,8 @@
"email-receipt": "البريد الإلكتروني (سوف نرسل لك إيصال تبرع قابل للخصم من الضرائب):",
"need-help": "بحاجة إلى مساعدة مع تبرعاتك الحالية أو السابقة؟",
"forward-receipt": "إعادة توجيه نسخة من إيصال التبرع الخاص بك إلى donors@freecodecamp.org وإخبارنا كيف يمكننا المساعدة.",
- "efficiency": "freeCodeCamp هي مؤسسة تعليمية خيرية عالية الكفاءة.",
- "why-donate-1": "عندما تتبرع لـ freeCodeCamp ، فإنك تساعد الناس على تعلم مهارات جديدة وإعالة عائلاتهم.",
+ "efficiency": "إن freeCodeCamp مؤسسة تعليمية خيرية عالية الكفاءة.",
+ "why-donate-1": "عندما تتبرع إلى freeCodeCamp، فإنك تساعد الناس على تعلم مهارات جديدة وإعالة عائلاتهم.",
"why-donate-2": "كما تساعدنا ايضا على إنشاء موارد جديدة لك لاستخدامها لتوسيع مهاراتك التكنولوجية الخاصة.",
"bigger-donation": "هل ترغب في تقديم تبرع أكبر لمرة واحدة، أو إرسال شيكًا بالبريد الإلكتروني، أو التبرع بطرق أخرى؟",
"other-ways": "فيما يلي العديد من <0>الطرق الأخرى الذي يمكنك بها دعم مهمتنا الخيرية0>.",
@@ -383,14 +390,14 @@
"expiration": "تاريخ انتهاء الصلاحية:",
"secure-donation": "التبرع الآمن",
"faq": "الأسئلة الشائعة",
- "only-you": "أنت فقط من يمكنه رؤية هذه الرسالة. تهانينا لحصولك على هذه الشهادة. إنها ليست مهمة سهلة. أدارة freeCodeCamp ليس سهلاً أيضًا. وهي إلى ذلك ليست بمهمة رخيصة الثمن. ساعدنا على مساعدتك أنت والعديد من الأشخاص الآخرين حول العالم. قدم تبرع دعمي معفى من الضرائب لمنظمتنا الخيرية اليوم.",
+ "only-you": "أنت فقط من يمكنه رؤية هذه الرسالة. تهانينا لحصولك على هذه الشهادة. إنه ليس بالأمر اليسير. أدارة freeCodeCamp ليس بالأمر اليسير أيضًا. وإلى ذلك ليست بالأمر زهيد. ساعدنا على مساعدتك والعديد من الأشخاص الآخرين حول العالم. قدم تبرع دعمي معفى من الضرائب لمؤسستنا الخيرية اليوم.",
"get-help": "كيف يمكنني الحصول على المساعدة في تبرعاتي؟",
"how-transparent": "ما مدى شفافية freeCodeCamp.org؟",
"very-transparent": "نحن نملك تصنيف بلاتينيوم للشفافية من GuideStar.org.",
"download-irs": "يمكنك <0>تنزيل رسالة تحديد الـ IRS الخاصة بنا هنا 0>.",
"download-990": "يمكنك <0>تنزيل أحدث 990 (التقرير الضريبي السنوي) هنا 0>.",
"how-efficient": "ما مدى كفاءة freeCodeCamp؟",
- "fcc-budget": "ميزانية freeCodeCamp أصغر بكثير من معظم المنظمات خيرية المماثلة. نحن لم نجلب جامعي أموال محترفين. بدلاً من ذلك، Quincy يفعل كل شيء بنفسه.",
+ "fcc-budget": "ميزانية freeCodeCamp أصغر بكثير من معظم المؤسسات خيرية المماثلة. نحن لم نجلب جامعي أموال محترفين. بدلاً من ذلك، Quincy يفعل كل شيء بنفسه.",
"help-millions": "ومع ذلك، وبميزانية لا تتجاوز بضع مئات الآلاف من الدولارات سنويا، تمكنا من مساعدة ملايين الناس.",
"how-one-time": "كيف يمكنني تقديم تبرع لمرة واحدة؟",
"one-time": "إذا كنت تفضل تقديم تبرعات لمرة واحدة، يمكنك دعم مهمة freeCodeCamp كلما كان لديك lمقدار من المال لا تحتاجه. يمكنك استخدام <0>هذا الرابط للتبرع بأي مبلغ ترغب به من خلال PayPal0>.",
@@ -400,23 +407,23 @@
"can-check": "هل يمكنني إرسال شيك مادي؟",
"yes-check": "نعم، نحن نقبل بالشيكات. يمكنك إرساله إلينا على:",
"how-matching-gift": "كيف يمكنني إعداد الهدايا المطابقة من رب العمل لدي، أو خصم الرواتب؟",
- "employers-vary": "هذا يختلف من صاحب عمل إلى صاحب عمل، ومنظمتنا الخيرية مدرجة فعلًا في العديد من قواعد البيانات الكبيرة المطابقة للتبرعات.",
+ "employers-vary": "هذا يختلف من صاحب عمل إلى صاحب عمل، ومؤسستنا الخيرية مدرجة فعلًا في العديد من قواعد البيانات الكبيرة والمتطابقة للتبرعات.",
"some-volunteer": "بعض الناس قادرون على التطوع في freeCodeCamp وأرباب عملهم يتطابقون من خلال التبرع بمبلغ ثابت في الساعة يعادل وقت التطوع. أما أرباب العمل الآخرون فسيضاهون أي تبرعات يقدمها المتبرعون لحد معين",
"help-matching-gift": "إذا كنت بحاجة إلى مساعدة في ذلك، يرجى إرسال بريد إلكتروني مباشر: Quincy@freecodecamp.org",
- "how-endowment": "كيف يمكنني اعداد هدية منح لـ freeCodeCamp.org؟",
+ "how-endowment": "كيف يمكنني إعداد هدية منح إلى freeCodeCamp.org؟",
"endowment": "هذه ستكون مساعدة هائلة. بما أن هذه عملية يدوية أكثر، يمكن لـ Quincy أن يساعدك فيها شخصيا. يرجى مراسلته مباشرة على Quincy@freecodecamp.org.",
- "how-legacy": "كيف يمكنني اعداد هدية مستقبلية لـ freeCodeCamp.org؟",
+ "how-legacy": "كيف يمكنني إعداد هدية مستقبلية إلى freeCodeCamp.org؟",
"we-honored": "سيشرفنا أن نضع مثل هذه الهدية في الاستخدام الجيد لمساعدة الناس في جميع أنحاء العالم على تعلم البرمجة. وتبعا لمكان سكنك، قد يكون هذا معفيا من الضرائب.",
"legacy-gift-message": "أعطي وأوريث [مبلغ _____ دولار أمريكي (أو عملة أخرى) أو _____ في المائة من الباقي وبقايا تركتي] إلى freeCodeCamp.org (رقم التعريف الضريبي لشركة Free Code Camp، Inc. 82-0779546) ، وهي مؤسسة خيرية بموجب قوانين ولاية ديلاوير، الولايات المتحدة، وتقع حاليًا في 3905 Hedgcoxe Rd، PO Box 250352، Plano، Texas، 75025 United States، لاستخدامها في أغراضها الخيرية العامة وفقًا لتقديرها.",
"thank-wikimedia": "ونود أن نشكر مؤسسة ويكيميديا على توفير هذه اللغة الرسمية لنا لكي نستخدمها.",
"legacy-gift-questions": "إذا كان لديك أي أسئلة حول هذه العملية، يرجى إرسال بريد الإلكتروني إلى Quincy@freecodecamp.org.",
- "how-stock": "كيف يمكنني التبرع بالاسهم لـ freeCodeCamp.org؟",
+ "how-stock": "كيف يمكنني التبرع بالأسهم إلى freeCodeCamp.org؟",
"welcome-stock": "نحن نرحب بتبرعاتك للأسهم. يرجى إرسال بريد إلكتروني مباشر إلى Quincy ويمكنه مساعدتك في ذلك، ومشاركة تفاصيل حساب الوساطة الخاص بالمؤسسة الخيرية: Quincy@freecodecamp.org.",
"how-receipt": "هل يمكنني الحصول على إيصال تبرع حتى يمكنني خصم تبرعي من ضرائبي؟",
"just-forward": "بالتأكيد. فقط أرسل الإيصال من معاملتك إلى donors@freecodecamp.org، أخبرنا بأنك تريد إيصال وأي تعليمات خاصة قد تكون لديك، وسنرد مع إيصال لك.",
"how-update": "لقد قمت بإعداد تبرع شهري، ولكن أحتاج إلى تحديث أو إيقاف تكرار ذلك شهريا. كيف يمكنني القيام بذلك؟",
"take-care-of-this": "فقط قم بإرسال واحد من إيصالاتك الشهرية للتبرع إلى donors@freecodecamp.org و أخبرنا بما تريد منا أن نفعل. سنعتني بهذا من أجلك ونرسل لك تأكيدات.",
- "anything-else": "هل هناك أي شيء آخر يمكنني معرفته حول التبرع لـ freeCodeCamp.org؟",
+ "anything-else": "هل هناك أي شيء آخر يمكنني معرفته حول التبرع إلى freeCodeCamp.org؟",
"other-support": "إذا كانت هناك طريقة أخرى غير مدرجة هنا ترغب بها في دعم منظمتنا الخيرية ومهمتها، أو إذا كان لديك أي أسئلة على الإطلاق، فيرجى إرسال بريد إلكتروني إلى Quincy على العنوان quincy@freecodecamp.org."
},
"report": {
@@ -460,7 +467,8 @@
"iframe-preview": "معاينة {{title}}",
"iframe-alert": "عادة هذا الرابط من شأنه أن يجلبك إلى موقع آخر! إنه يعمل. هذا رابط: {{externalLink}}",
"iframe-form-submit-alert": "عادة سيتم تقديم هذا النموذج! إنه يعمل. سيتم إرسال هذا إلى: {{externalLink}}",
- "document-notfound": "لم يوجد المستند"
+ "document-notfound": "لم يوجد المستند",
+ "slow-load-msg": "يبدو أن هذا يستغرق وقتاً أطول من المعتاد، الرجاء محاولة تحديث الصفحة."
},
"icons": {
"gold-cup": "كأس الذهب",
@@ -475,10 +483,11 @@
"hint": "تلميح",
"heart": "Heart",
"initial": "مبدئي",
+ "input-reset": "حذف مصطلحات البحث",
"info": "معلومات المقدمة",
"spacer": "فاصل",
"toggle": "تبديل علامة التحقق",
- "magnifier": "عدسه مكبرة"
+ "magnifier": "إرسال مصطلحات البحث"
},
"aria": {
"fcc-curriculum": "منهج freeCodeCamp",
@@ -504,15 +513,16 @@
"step": "الخطوة",
"steps": "الخطوات",
"steps-for": "خطوات {{blockTitle}}",
- "code-example": "{{codeName}} code example"
+ "code-example": "{{codeName}} مثال على الكود",
+ "opens-new-window": "فتح في نافذة جديدة"
},
"flash": {
- "honest-first": "للمطالبة بشهادة ، يجب عليك أولاً قبول سياسة الصدق الأكاديمي الخاصة بنا",
+ "honest-first": "للمطالبة بشهادة، يجب عليك أولاً الموافقة على سياسة للصدق الأكاديمي",
"really-weird": "حدث شيء غريب حقاً، إذا حدث مرة أخرى، يرجى النظر في الإبلاغ عنها على https://github.com/freeCodeCamp/freeCodeCamp/issues/new",
"not-right": "يبدو ان هناك خطأ ما. لقد تم إنشاء تقرير وتم إخطار فريق freeCodeCamp.org",
"went-wrong": "حدث خطأ ما، الرجاء التحقق والمحاولة مرة أخرى",
"account-deleted": "تم حذف حسابك بنجاح",
- "progress-reset": "تم إعادة تعيين تقدمك",
+ "progress-reset": "تم إعادة تقدمك ألى حالته الأولية",
"not-authorized": "غير مصرح لك بالمتابعة على هذا المسار",
"could-not-find": "لم نتمكن من العثور على ما كنت تبحث عنه. الرجاء التحقق والمحاولة مرة أخرى",
"wrong-updating": "حدث خطأ ما في تحديث حسابك. الرجاء التحقق والمحاولة مرة أخرى",
@@ -586,7 +596,8 @@
"editor-url": "تذكر أن تقدم رابط التطبيق المباشر.",
"http-url": "لا يمكن استخدام عنوان URL غير آمن (http).",
"own-work-url": "تذكر أن تقدم عملك الخاص.",
- "publicly-visible-url": "تذكر أن ترسل عنوان URL للتطبيق متاح للجميع."
+ "publicly-visible-url": "تذكر أن ترسل عنوان URL للتطبيق متاح للجميع.",
+ "path-url": "You probably want to submit the root path i.e. https://example.com, not https://example.com/path"
},
"certification": {
"executive": "المدير التنفيذي، freeCodeCamp.org",
@@ -601,10 +612,10 @@
"source": "المصدر",
"footnote": "إذا كنت تشك في أن أيا من هذه المشاريع ينتهك <2>سياسة الأمانة الأكاديمية2>، يرجى <5>إبلاغ فريقنا بهذا 5>.",
"title": {
- "Build a Personal Portfolio Webpage": "قم ببناء مشروع صفحة ويب لعرض نماذج الاعمال الشخصية",
+ "Build a Personal Portfolio Webpage": "أنشئ معرضا لأعمالك الخاصة",
"Build a Random Quote Machine": "بناء آلة عرض اقتباسات عشوائية",
"Build a 25 + 5 Clock": "بناء ساعة 25 + 5",
- "Build a JavaScript Calculator": "بناء حاسبة بإستخدام JavaScript",
+ "Build a JavaScript Calculator": "بناء آلة حاسبة باستخدام JavaScript",
"Show the Local Weather": "إظهار الطقس المحلي",
"Use the TwitchTV JSON API": "استخدام TwitchTV JSON API",
"Stylize Stories on Camper News": "نسق قصص على أخبار Camper",
@@ -638,14 +649,14 @@
"Anonymous Message Board": "لوحة الرسائل المجهولة",
"Build a Tribute Page": "بناء مشروع صفحة الثناء",
"Build a Survey Form": "بناء مشروع نموذج الدراسة الاستقصائية",
- "Build a Product Landing Page": "بناء صفحة هبوط لمنتج",
+ "Build a Product Landing Page": "أنشئ صفحة لعرض المنتج",
"Build a Technical Documentation Page": "بناء مشروع صفحة التوثيق التقني",
"Palindrome Checker": "مدقق باليندروم",
"Roman Numeral Converter": "تحويل الأرقام الرومانية",
"Caesars Cipher": "Caesars Cipher",
"Telephone Number Validator": "مدقق رقم الهاتف",
"Cash Register": "سجل النقدية",
- "Build a Drum Machine": "بناء آلة الدرامز",
+ "Build a Drum Machine": "أنشئ آلة الطبول",
"Visualize Data with a Choropleth Map": "التصوير المرئي للبيانات باستخدام خريطة التمثيل اللوني",
"Visualize Data with a Treemap Diagram": "التصوير المرئي للبيانات باستخدام الخريطة الشجرية",
"Exercise Tracker": "متعقب التمارين",
@@ -668,8 +679,49 @@
"Cat and Dog Image Classifier": "مصنف صور القطط والكلاب",
"Book Recommendation Engine using KNN": "محرك توصية للكتب باستخدام KNN",
"Linear Regression Health Costs Calculator": "حاسبة التكاليف الصحية بالانحدار الخطي",
- "Neural Network SMS Text Classifier": "مصنف الرسائل SMS بالشبكة العصبية"
+ "Neural Network SMS Text Classifier": "مصنف الرسائل SMS بالشبكة العصبية",
+ "Celestial Bodies Database": "قاعدة بيانات الأحجام الهائلة",
+ "World Cup Database": "قاعدة بيانات كأس العالم",
+ "Salon Appointment Scheduler": "جدولة مواعيد الصالون",
+ "Periodic Table Database": "قاعدة بيانات قائمة العناصر الكيميائية",
+ "Number Guessing Game": "لُعْبَة تخمين العدد",
+ "Build a freeCodeCamp Forum Homepage": "بناء صفحة لمنتدى freeCodeCamp"
}
+ },
+ "title": {
+ "Responsive Web Design": "تصميم مواقع الويب المتجاوبة",
+ "responsive-web-design": "شهادة تصميم مواقع الويب المتجاوبة",
+ "JavaScript Algorithms and Data Structures": "الخوارزميات وهياكل البيانات في JavaScript",
+ "javascript-algorithms-and-data-structures": "شهادة الخوارزميات وهياكل البيانات في JavaScript",
+ "Front End Development Libraries": "مكتبات تطوير واجهة المستخدم",
+ "front-end-development-libraries": "شهادة مكتبات تطوير واجهة المستخدم",
+ "Data Visualization": "التصوير المرئي للبيانات",
+ "data-visualization": "شهادة التصوير المرئي للبيانات",
+ "Relational Database": "قاعدة البيانات ذات علاقات",
+ "relational-database-v8": "شهادة قاعدة البيانات ذات علاقات",
+ "Back End Development and APIs": "تطوير الواجهات الخلفية للمواقع و APIs",
+ "back-end-development-and-apis": "شهادة تطوير الواجهات الخلفية للمواقع و APIs",
+ "Quality Assurance": "ضمان الجودة",
+ "quality-assurance-v7": "شهادة ضمان الجودة",
+ "Scientific Computing with Python": "الحساب العلمي باستخدام Python",
+ "scientific-computing-with-python-v7": "شهادة الحساب العلمي مع Python",
+ "Data Analysis with Python": "تحليل البيانات باستخدام Python",
+ "data-analysis-with-python-v7": "شهادة تحليل البيانات باستخدام Python",
+ "Information Security": "أمن المعلومات",
+ "information-security-v7": "شهادة امن المعلومات",
+ "Machine Learning with Python": "تعلم الآلة باستخدام Python",
+ "machine-learning-with-python-v7": "مشاريع تعلم الآله باستخدام Python",
+ "Legacy Front End": "الواجهة الأمامية التراثية",
+ "legacy-front-end": "شهادة الواجهة الأمامية التراثية",
+ "Legacy Back End": "الواجهة الخلفية التراثية",
+ "legacy-back-end": "شهادة الواجهة الخلفية التراثية",
+ "Legacy Data Visualization": "التصوير المرئي للبيانات التراثي",
+ "legacy-data-visualization": "شهادة التصوير المرئي للبيانات",
+ "Legacy Information Security and Quality Assurance": "أمن المعلومات وشهادة ضمان الجودة التراثية",
+ "information-security-and-quality-assurance": "شهادة أمن المعلومات وشهادة ضمان الجودة",
+ "Legacy Full Stack Certification": "شهادة الشامل الخلفية التراثية",
+ "Legacy Full Stack": "الشامل الخلفية التراثية",
+ "full-stack": "شهادة الشامل الخلفية"
}
},
"certification-card": {
diff --git a/client/i18n/locales/chinese-traditional/intro.json b/client/i18n/locales/chinese-traditional/intro.json
index cf1d7d845108e4..cec79b3a46b3db 100644
--- a/client/i18n/locales/chinese-traditional/intro.json
+++ b/client/i18n/locales/chinese-traditional/intro.json
@@ -335,6 +335,10 @@
"learn-functional-programming-by-building-a-spreadsheet": {
"title": "通過構建電子表格學習函數式編程",
"intro": ["", ""]
+ },
+ "learn-advanced-array-methods-by-building-a-statistics-calculator": {
+ "title": "Learn Advanced Array Methods by Building a Statistics Calculator",
+ "intro": ["", ""]
}
}
},
@@ -553,7 +557,7 @@
"intro": [
"在這之前,你只是在前端使用 JavaScript 來給頁面添加交互、解決算法挑戰,或構建一個 SPA(單頁應用程序)。但 JavaScript 也可以用於後端或者服務器來構建整個 web 應用程序。",
"今天,構建應用軟件的廣受歡迎的方法之一是微服務,這些微服務是一種小型模塊化的應用,能夠共同形成一個更大的整體。",
- "在後端開發和 APIs 認證中,你將學習如何使用 Node.js 和 npm(Node 包管理工具)來寫後端。你還將使用 Express 框架構建 web 應用程序,並使用 MongoDB 和 Mongoose 庫構建一個 People Finder 微服務。"
+ "In the Back End Development and APIs Certification, you'll learn how to write back end apps with Node.js and npm. You'll also build web applications with the Express framework, and build a People Finder microservice with MongoDB and the Mongoose library."
],
"note": "",
"blocks": {
@@ -787,6 +791,24 @@
}
}
},
+ "the-odin-project": {
+ "title": "The Odin Project",
+ "intro": [
+ "The Odin Project is one of those \"What I wish I had when I was learning\" resources. ",
+ "Not everyone has access to a computer science education or the funds to attend an intensive coding school and neither of those is right for everyone anyway.",
+ "This project is designed to fill in the gap for people who are trying to hack it on their own but still want a high quality education."
+ ],
+ "blocks": {
+ "top-learn-html-foundations": {
+ "title": "Learn HTML Foundations",
+ "intro": ["A description is to be determined"]
+ },
+ "top-build-a-recipe-project": {
+ "title": "Learn HTML Foundations by Building a Recipe Page",
+ "intro": ["A description is to be determined"]
+ }
+ }
+ },
"misc-text": {
"certification": "{{cert}} 認證",
"browse-other": "瀏覽我們的其他免費認證\n(我們建議你按順序學習)",
diff --git a/client/i18n/locales/chinese-traditional/motivation.json b/client/i18n/locales/chinese-traditional/motivation.json
index d65a69bb268698..12eb62efeed4a5 100644
--- a/client/i18n/locales/chinese-traditional/motivation.json
+++ b/client/i18n/locales/chinese-traditional/motivation.json
@@ -1,819 +1,856 @@
{
"compliments": [
- "Over the top!",
- "Down the rabbit hole we go!",
- "Bring that rain!",
- "Target acquired.",
- "Feel that need for speed!",
- "You've got guts!",
- "We have liftoff!",
- "To infinity and beyond!",
- "Encore!",
- "Onward!",
- "Challenge destroyed!",
- "It's on like Donkey Kong!",
- "Power level? It's over 9000!",
- "Coding spree!",
- "Code long and prosper.",
- "The crowd goes wild!",
- "One for the Guinness book!",
- "Flawless victory!",
- "Most efficient!",
- "You've got the touch!",
- "You're on fire!",
- "The town is now red!",
- "To the nines!",
- "To the Batmobile!",
- "Pull out all the stops!",
- "You're a wizard, Harry!",
- "You're an all-star!",
- "Way to go!",
- "Outta sight!",
- "You're crushing it!",
- "What sorcery is this?",
- "The world rejoices!",
- "That's the way it's done!",
- "You rock!",
- "Woo-hoo!",
- "We knew you could do it!",
- "Hyper Combo Finish!",
- "Nothing but net!",
- "Boom-shakalaka!",
- "You're a shooting star!",
- "You're unstoppable!",
- "Way cool!",
- "Walk on that sunshine!",
- "Keep on trucking!",
- "Off the charts!",
- "There is no spoon!",
- "Cranked it up to 11!",
- "Escape velocity reached!",
- "You make this look easy!",
- "Passed with flying colors!",
- "You've got this!",
- "Happy, happy, joy, joy!",
- "Tomorrow, the world!",
- "Your powers combined!",
- "It's alive. It's alive!",
- "Sonic Boom!",
- "Here's looking at you, Code!",
- "Ride like the wind!",
- "Legen - wait for it - dary!",
- "Ludicrous Speed! Go!",
- "Most triumphant!",
- "One loop to rule them all!",
- "By the power of Grayskull!",
- "You did it!",
- "Storm that castle!",
- "Face-melting guitar solo!",
- "Checkmate!",
- "Bodacious!",
- "Tubular!",
- "You're outta sight!",
- "Keep calm and code on!",
- "Even sad panda smiles!",
- "Even grumpy cat approves!",
- "Kool Aid Man says oh yeah!",
- "Bullseye!",
- "Far out!",
- "You're heating up!",
- "Standing ovation!",
- "Nice one!",
- "All right!",
- "Hasta la vista, challenge!",
- "Terminated.",
- "Off the hook!",
- "Thundercats, Hooo!",
- "Shiver me timbers!",
- "Raise the roof!",
- "Bingo!",
- "Even Honey Badger cares!",
- "Helm, Warp Nine. Engage!",
- "Gotta code 'em all!",
- "Spool up the FTL drive!",
- "Cool beans!",
- "They're in another castle.",
- "Power UP!",
- "Pikachu chooses you!",
- "I gotta have more cowbell.",
- "Gotta go fast!",
- "Yippee!",
- "Cowabunga!",
- "Moon Prism Power!",
- "Plus Ultra!"
+ "太棒了!",
+ "我們跳進兔子洞!",
+ "雨下吧!",
+ "獲取目標。",
+ "體驗極速快感!",
+ "你有膽量!",
+ "我們升空了!",
+ "飛向無限!",
+ "再來一次!",
+ "向前進!",
+ "挑戰被摧毀!",
+ "重磅如同大金剛!",
+ "戰鬥力?超過 9000!",
+ "編碼狂潮!",
+ "編碼不息,繁榮昌盛。",
+ "人羣變得瘋狂!",
+ "一個吉尼斯世界紀錄!",
+ "完勝!",
+ "最高效率!",
+ "你有手感了!",
+ "你正在燃燒!",
+ "滿城春色!",
+ "完美!",
+ "上蝙蝠車!",
+ "全力以赴!",
+ "你是個巫師,哈利!",
+ "你是全明星隊員!",
+ "幹得好!",
+ "棒極了!",
+ "你太出色了!",
+ "這是什麼魔法?",
+ "世界歡欣鼓舞!",
+ "難題就是這樣搞定的!",
+ "你真棒!",
+ "嗚呼!",
+ "我們就知道你能行!",
+ "超級組合終結!",
+ "空心球!",
+ "炸彈-沙卡拉卡!",
+ "你是一顆流星!",
+ "你勢不可擋!",
+ "太酷了!",
+ "走在那陽光下!",
+ "堅持下去!",
+ "水平爆表!",
+ "勺子並不存在!",
+ "調到最大音量!",
+ "達到逃逸速度!",
+ "你讓這看起來很簡單!",
+ "以優異的成績通過!",
+ "你能行!",
+ "開心,開心,快樂,快樂!",
+ "明天,征服世界!",
+ "你的全部力量!",
+ "它活了。它活了!",
+ "索尼克音爆!",
+ "看着你呢,代碼!",
+ "疾馳如風!",
+ "傳——奇!",
+ "離譜的速度!出發!",
+ "高奏凱歌!",
+ "用一個循環來統治它們!",
+ "憑藉灰殼堡的神力!",
+ "你做到了!",
+ "衝進城堡!",
+ "蕩人心魄的吉他獨奏!",
+ "完全擊敗!",
+ "大有膽識!",
+ "厲害!",
+ "你真強啊!",
+ "保持冷靜,繼續編碼!",
+ "即使是悲傷的熊貓也會微笑!",
+ "即使脾氣暴躁的貓也同意!",
+ "如此感覺無以倫比。",
+ "正中靶心!",
+ "前衛!",
+ "燃燒吧,小宇宙!",
+ "起立鼓掌!",
+ "不錯!",
+ "好啊!",
+ "回見,挑戰!",
+ "終結了。",
+ "脫身!",
+ "霹靂貓顯神威!",
+ "讓我五體投地!",
+ "大顯身手!",
+ "答對了!",
+ "連蜜獾都在乎!",
+ "掌舵,第九曲速。啓動!",
+ "必須全部編碼!",
+ "發動超光速引擎!",
+ "酷豆子!",
+ "她們在另一個城堡裏。",
+ "加電!",
+ "皮卡丘選擇了你!",
+ "我要再多點牛鈴。",
+ "得快點!",
+ "了不起!",
+ "卡瓦邦嘎!",
+ "月亮棱鏡能量!",
+ "超越極致!",
+ "米爾豪斯一切都會好起來的!"
],
"motivationalQuotes": [
{
- "quote": "Whatever you are, be a good one.",
- "author": "Abraham Lincoln"
+ "quote": "不管你是誰,做個好人。",
+ "author": "亞伯拉罕·林肯"
},
{
- "quote": "A change in perspective is worth 80 IQ points.",
- "author": "Alan Kay"
+ "quote": "換一個角度看問題值80點智商。",
+ "author": "艾倫·凱"
},
{
- "quote": "The best way to predict the future is to invent it.",
- "author": "Alan Kay"
+ "quote": "預測未來的最好方法是創造未來。",
+ "author": "艾倫·凱"
},
{
- "quote": "The future is not laid out on a track. It is something that we can decide, and to the extent that we do not violate any known laws of the universe, we can probably make it work the way that we want to.",
- "author": "Alan Kay"
+ "quote": "未來不是在軌道上規劃的。這是我們可以決定的事情,只要我們不違反任何已知的宇宙法則,我們就可以讓它按我們想要的方式運行。",
+ "author": "艾倫·凱"
},
{
- "quote": "We can only see a short distance ahead, but we can see plenty there that needs to be done.",
- "author": "Alan Turing"
+ "quote": "我們只能看到前面很短的距離,但我們可以看到有很多事情需要做。",
+ "author": "艾倫·圖靈"
},
{
- "quote": "In the depth of winter, I finally learned that within me there lay an invincible summer.",
- "author": "Albert Camus"
+ "quote": "隆冬時節,我終於明白,我的內心深處有一個不可戰勝的夏天。",
+ "author": "阿爾伯特·加繆"
},
{
- "quote": "A person who never made a mistake never tried anything new.",
- "author": "Albert Einstein"
+ "quote": "從不犯錯的人從不嘗試新事物。",
+ "author": "阿爾伯特·愛因斯坦"
},
{
- "quote": "Creativity is intelligence having fun.",
- "author": "Albert Einstein"
+ "quote": "創造力是智力的樂趣。",
+ "author": "阿爾伯特·愛因斯坦"
},
{
- "quote": "I have no special talents. I am only passionately curious.",
- "author": "Albert Einstein"
+ "quote": "我沒有什麼特別的才能。我只是非常好奇。",
+ "author": "阿爾伯特·愛因斯坦"
},
{
- "quote": "Life is like riding a bicycle. To keep your balance, you must keep moving.",
- "author": "Albert Einstein"
+ "quote": "生活就像騎自行車。爲了保持平衡,你必須繼續前進。",
+ "author": "阿爾伯特·愛因斯坦"
},
{
- "quote": "Make everything as simple as possible, but not simpler.",
- "author": "Albert Einstein"
+ "quote": "事情應該力求簡單,但不能過於簡單。",
+ "author": "阿爾伯特·愛因斯坦"
},
{
- "quote": "Never memorize something that you can look up.",
- "author": "Albert Einstein"
+ "quote": "絕不要去記那些你能夠查得到的東西。",
+ "author": "阿爾伯特·愛因斯坦"
},
{
- "quote": "Once we accept our limits, we go beyond them.",
- "author": "Albert Einstein"
+ "quote": "一旦我們接受了自己的極限,我們就超越了它們。",
+ "author": "阿爾伯特·愛因斯坦"
},
{
- "quote": "Play is the highest form of research.",
- "author": "Albert Einstein"
+ "quote": "玩耍是研究的最高形式。",
+ "author": "阿爾伯特·愛因斯坦"
},
{
- "quote": "We cannot solve our problems with the same thinking we used when we created them.",
- "author": "Albert Einstein"
+ "quote": "我們不能用我們創造問題時的思維來解決問題。",
+ "author": "阿爾伯特·愛因斯坦"
},
{
- "quote": "Wisdom is not a product of schooling but of the lifelong attempt to acquire it.",
- "author": "Albert Einstein"
+ "quote": "智慧不是學校教育的產物,而是終身學習的產物。",
+ "author": "阿爾伯特·愛因斯坦"
},
{
- "quote": "Your imagination is your preview of life's coming attractions.",
- "author": "Albert Einstein"
+ "quote": "你的想像是你人生的預覽。",
+ "author": "阿爾伯特·愛因斯坦"
},
{
- "quote": "There is only one corner of the universe you can be certain of improving, and that's your own self.",
- "author": "Aldous Huxley"
+ "quote": "宇宙中只有一個角落是你可以切實改進的,那就是你自己。",
+ "author": "奧爾德斯·赫胥黎"
},
{
- "quote": "The most common way people give up their power is by thinking they don't have any.",
- "author": "Alice Walker"
+ "quote": "我感謝我的奮鬥,因爲沒有它,我就不會偶然發現自己的力量。",
+ "author": "亞歷克斯·艾爾"
},
{
- "quote": "Follow your inner moonlight. Don't hide the madness.",
- "author": "Allen Ginsberg"
+ "quote": "人們放棄權力最常見的方式是認爲自己沒有權力。",
+ "author": "艾麗絲·沃克"
},
{
- "quote": "The most difficult thing is the decision to act. The rest is merely tenacity.",
- "author": "Amelia Earhart"
+ "quote": "跟隨你內心的月光。別掩飾自己的瘋狂。",
+ "author": "艾倫·金斯伯格"
},
{
- "quote": "Life shrinks or expands in proportion with one's courage.",
- "author": "Anaïs Nin"
+ "quote": "最困難的是決定採取行動。剩下的只是堅韌。",
+ "author": "阿梅莉亞·埃爾哈特"
},
{
- "quote": "Weeks of programming can save you hours of planning.",
- "author": "Unknown"
+ "quote": "生命的縮小或擴大與一個人的勇氣成正比。",
+ "author": "阿奈斯·寧"
},
{
- "quote": "Quality is not an act, it is a habit.",
- "author": "Aristotle"
+ "quote": "數週的編程可以節省你數小時的計劃。",
+ "author": "佚名"
},
{
- "quote": "Start where you are. Use what you have. Do what you can.",
- "author": "Arthur Ashe"
+ "quote": "質量不是一種行爲,而是一種習慣。",
+ "author": "亞里士多德"
},
{
- "quote": "Nothing is impossible, the word itself says \"I'm possible\"!",
- "author": "Audrey Hepburn"
+ "quote": "從現在開始。利用你所擁有的。盡你所能。",
+ "author": "亞瑟·阿什"
},
{
- "quote": "Every strike brings me closer to the next home run.",
- "author": "Babe Ruth"
+ "quote": "沒有什麼是不可能的,連這個詞本身都說“不,可能”!",
+ "author": "奧黛麗·赫本"
},
{
- "quote": "By failing to prepare, you are preparing to fail.",
- "author": "Benjamin Franklin"
+ "quote": "每一擊都讓我離下一個本壘打越來越近。",
+ "author": "貝比·魯斯"
},
{
- "quote": "Tell me and I forget. Teach me and I remember. Involve me and I learn.",
- "author": "Benjamin Franklin"
+ "quote": "如果你沒有做好準備,你就是在準備失敗。",
+ "author": "本傑明·富蘭克林"
},
{
- "quote": "Well done is better than well said.",
- "author": "Benjamin Franklin"
+ "quote": "告訴我,我會忘記。教我,我會記住。讓我參與,我會學習。",
+ "author": "本傑明·富蘭克林"
},
{
- "quote": "There are no short cuts to any place worth going.",
- "author": "Beverly Sills"
+ "quote": "說得好不如做得好。",
+ "author": "本傑明·富蘭克林"
},
{
- "quote": "Controlling complexity is the essence of computer programming.",
- "author": "Brian Kernighan"
+ "quote": "任何值得去的地方都沒有捷徑。",
+ "author": "貝弗利·希爾斯"
},
{
- "quote": "I fear not the man who has practiced 10,000 kicks once, but I fear the man who has practiced one kick 10,000 times.",
- "author": "Bruce Lee"
+ "quote": "控制複雜性是計算機編程的本質。",
+ "author": "布萊恩·科尼漢"
},
{
- "quote": "There are far, far better things ahead than any we leave behind.",
- "author": "C.S. Lewis"
+ "quote": "我不怕遇到練習過一萬種腿法的對手,但害怕遇到只將一種腿法練習一萬次的強敵。",
+ "author": "李小龍"
},
{
- "quote": "We are what we believe we are.",
- "author": "C.S. Lewis"
+ "quote": "比起遺落在過去的,未來還有更加美好的在等待着我們。",
+ "author": "C.S. 路易斯"
},
{
- "quote": "With the possible exception of the equator, everything begins somewhere.",
- "author": "C.S. Lewis"
+ "quote": "我們就是我們所相信的自己。",
+ "author": "C.S. 路易斯"
},
{
- "quote": "You are never too old to set another goal, or to dream a new dream.",
- "author": "C.S. Lewis"
+ "quote": "可能除了赤道以外,一切都從某處開始。",
+ "author": "C.S. 路易斯"
},
{
- "quote": "Somewhere, something incredible is waiting to be known.",
- "author": "Carl Sagan"
+ "quote": "無論年紀多大,你都可以設立新目標或擁有新夢想。",
+ "author": "C.S. 路易斯"
},
{
- "quote": "If you're not making mistakes, then you're not making decisions.",
- "author": "Catherine Cook"
+ "quote": "在某個地方,一些不可思議的事物正在等你去發現。",
+ "author": "卡爾·薩根"
},
{
- "quote": "Find what you love and let it kill you.",
- "author": "Charles Bukowski"
+ "quote": "當你有夢想時,你必須抓住它,永不放棄。",
+ "author": "卡羅爾·伯內特"
},
{
- "quote": "What matters most is how well you walk through the fire.",
- "author": "Charles Bukowski"
+ "quote": "如果你沒有犯錯誤,那麼你就沒有做決定。",
+ "author": "凱瑟琳·庫克"
},
{
- "quote": "It is not the strongest of the species that survive, nor the most intelligent, but the one most responsive to change.",
- "author": "Charles Darwin"
+ "quote": "愛我所愛,至死方休。",
+ "author": "查爾斯·布考斯基"
},
{
- "quote": "Life is 10% what happens to you and 90% how you react to it.",
- "author": "Charles R. Swindoll"
+ "quote": "最重要的是你能否赴湯蹈火。",
+ "author": "查爾斯·布考斯基"
},
{
- "quote": "You will do foolish things, but do them with enthusiasm.",
- "author": "Colette"
+ "quote": "生存下來的不是最強壯的物種,也不是最聰明的物種,而是最能適應變化的物種。",
+ "author": "查爾斯·達爾文"
},
{
- "quote": "It does not matter how slowly you go as long as you do not stop.",
- "author": "Confucius"
+ "quote": "細節不僅是細節,而且決定了設計。",
+ "author": "查爾斯·伊姆斯"
},
{
- "quote": "Real knowledge is to know the extent of one's ignorance.",
- "author": "Confucius"
+ "quote": "創造力不僅僅是與衆不同。任何人都可以做到怪誕不經,這很簡單。難的是像巴赫那樣簡單。使簡單的,非常簡單,這就是創造力。",
+ "author": "查爾斯·明格斯"
},
{
- "quote": "The past cannot be changed. The future is yet in your power.",
- "author": "Confucius"
+ "quote": "生活的 10% 是發生在你身上的事,90% 是你對它的反應。",
+ "author": "查爾斯·R·斯溫多爾"
},
{
- "quote": "Looking at code you wrote more than two weeks ago is like looking at code you are seeing for the first time.",
- "author": "Dan Hurvitz"
+ "quote": "你不免會做傻事,但熱烈地、衷心地投入做吧。",
+ "author": "科萊特"
},
{
- "quote": "Someday is not a day of the week.",
- "author": "Denise Brennan-Nelson"
+ "quote": "譬如爲山,未成一簣,止,吾止也。譬如平地,雖覆一簣,進,吾往也。",
+ "author": "孔子"
},
{
- "quote": "UNIX is simple. It just takes a genius to understand its simplicity.",
- "author": "Dennis Ritchie"
+ "quote": "知之爲知之,不知爲不知,是知也。",
+ "author": "孔子"
},
{
- "quote": "Computers are good at following instructions, but not at reading your mind.",
- "author": "Donald Knuth"
+ "quote": "往昔不可諫,來者猶可追。",
+ "author": "孔子"
},
{
- "quote": "A good programmer is someone who always looks both ways before crossing a one-way street.",
- "author": "Doug Linder"
+ "quote": "看着自己兩個多星期前編寫的代碼就像第一次看到這代碼一樣。",
+ "author": "丹·赫維茨"
},
{
- "quote": "Tough times never last, but tough people do.",
- "author": "Dr. Robert Schuller"
+ "quote": "“總有一天”不是一週中的一天。",
+ "author": "丹尼斯·布倫南-納爾遜"
},
{
- "quote": "If things start happening, don't worry, don't stew, just go right along and you'll start happening too.",
- "author": "Dr. Seuss"
+ "quote": "UNIX很簡單。不過只有天才才能理解它的簡單性。",
+ "author": "丹尼斯·裏奇"
},
{
- "quote": "Do not go gentle into that good night. Rage, rage against the dying of the light.",
- "author": "Dylan Thomas"
+ "quote": "在我看來,要想見彩虹,就得忍受風雨!",
+ "author": "多莉·帕頓"
},
{
- "quote": "The question of whether computers can think is like the question of whether submarines can swim.",
- "author": "E.W. Dijkstra"
+ "quote": "計算機善於遵循指令,但不善於理解你的思維。",
+ "author": "唐納德·克努特"
},
{
- "quote": "Any code of your own that you haven't looked at for six or more months might as well have been written by someone else.",
- "author": "Eagleson's Law"
+ "quote": "優秀的程序員總是在過單行道之前兩邊都看一下。",
+ "author": "道格·林德"
},
{
- "quote": "Do one thing every day that scares you.",
- "author": "Eleanor Roosevelt"
+ "quote": "創造力是狂野的頭腦和訓練有素的眼睛。",
+ "author": "多蘿西·帕克"
},
{
- "quote": "With the new day comes new strength and new thoughts.",
- "author": "Eleanor Roosevelt"
+ "quote": "艱苦的時光終將過去,堅強的人們必將苦盡甘來。",
+ "author": "羅伯特·舒勒博士"
},
{
- "quote": "You must do the things you think you cannot do.",
- "author": "Eleanor Roosevelt"
+ "quote": "如果事情開始發生,不要發愁,不要擔憂,只要一直走下去,你也會開始發生的。",
+ "author": "蘇斯博士"
},
{
- "quote": "Light tomorrow with today.",
- "author": "Elizabeth Barrett Browning"
+ "quote": "不要溫和地走進那良夜。怒斥,怒斥光明的消逝。",
+ "author": "狄蘭·托馬斯"
},
{
- "quote": "Forever is composed of nows.",
- "author": "Emily Dickinson"
+ "quote": "計算機能否思考的問題就像潛艇能否游泳的問題一樣。",
+ "author": "E·W·迪科斯徹"
},
{
- "quote": "Computer science education cannot make anybody an expert programmer any more than studying brushes and pigment can make somebody an expert painter.",
- "author": "Eric Raymond"
+ "quote": "自己寫的代碼,只要有六個月沒有看過,就像是別人寫的一樣。",
+ "author": "伊格爾森定律"
},
{
- "quote": "If you don't risk anything, you risk even more.",
- "author": "Erica Jong"
+ "quote": "每天做一件讓你害怕的事。",
+ "author": "埃莉諾·羅斯福"
},
{
- "quote": "The world breaks everyone, and afterward, many are strong at the broken places.",
- "author": "Ernest Hemingway"
+ "quote": "新的一天帶來了新的力量和新的思想。",
+ "author": "埃莉諾·羅斯福"
},
{
- "quote": "There is nothing noble in being superior to your fellow man; true nobility is being superior to your former self.",
- "author": "Ernest Hemingway"
+ "quote": "你必須做你自己認爲做不到的事。",
+ "author": "埃莉諾·羅斯福"
},
{
- "quote": "Never confuse a single defeat with a final defeat.",
- "author": "F. Scott Fitzgerald"
+ "quote": "用今天照亮明天。",
+ "author": "伊麗莎白·巴雷特·布朗寧"
},
{
- "quote": "I attribute my success to this - I never gave or took any excuse.",
- "author": "Florence Nightingale"
+ "quote": "如果你的夢想沒有嚇到你,那是因爲你夢想得還不夠大。",
+ "author": "愛倫·約翰森·希爾麗夫"
},
{
- "quote": "The best revenge is massive success.",
- "author": "Frank Sinatra"
+ "quote": "永遠是由現在組成的。",
+ "author": "艾米莉·狄金森"
},
{
- "quote": "The only limit to our realization of tomorrow, will be our doubts of today.",
- "author": "Franklin D. Roosevelt"
+ "quote": "計算機科學教育不能使任何人成爲專家程序員,正如學習畫筆和顏料無法讓人成爲繪畫專家一樣。",
+ "author": "埃裏克·雷蒙德"
},
{
- "quote": "Right or wrong, it's very pleasant to break something from time to time.",
- "author": "Fyodor Dostoevsky"
+ "quote": "如果你不冒任何風險,你的風險就更大。",
+ "author": "艾瑞卡·瓊"
},
{
- "quote": "The harder I work, the luckier I get.",
- "author": "Gary Player"
+ "quote": "生活總是讓我們遍體鱗傷,但到後來,那些受傷的地方會變得更堅強。",
+ "author": "厄內斯特·海明威"
},
{
- "quote": "Giving up is the only sure way to fail.",
- "author": "Gena Showalter"
+ "quote": "優於別人,並不高貴,真正的高貴應該是優於過去的自己。",
+ "author": "厄內斯特·海明威"
},
{
- "quote": "The only truly secure system is one that is powered off, cast in a block of concrete and sealed in a lead-lined room with armed guards.",
- "author": "Gene Spafford"
+ "quote": "永遠不要將一次失敗與最終失敗混淆。",
+ "author": "F. 斯科特·菲茨傑拉德"
},
{
- "quote": "A life spent making mistakes is not only more honorable, but more useful than a life spent doing nothing.",
- "author": "George Bernard Shaw"
+ "quote": "我將我的成功歸功於此——我從不找,也不接受任何藉口。",
+ "author": "弗洛倫斯·南丁格爾"
},
{
- "quote": "First learn computer science and all the theory. Next develop a programming style. Then forget all that and just hack.",
- "author": "George Carrette"
+ "quote": "最好的報復是巨大的成功。",
+ "author": "弗蘭克·西納特拉"
},
{
- "quote": "Discovering the unexpected is more important than confirming the known.",
- "author": "George Box"
+ "quote": "我們實現明天的唯一限制是我們對今天的懷疑。",
+ "author": "富蘭克林·羅斯福"
},
{
- "quote": "We only see what we know.",
- "author": "Goethe"
+ "quote": "不管是對是錯,時不時弄壞點東西是一件非常愉快的事情。",
+ "author": "陀思妥耶夫斯基"
},
{
- "quote": "Without hard work, nothing grows but weeds.",
- "author": "Gordon B. Hinckley"
+ "quote": "我越努力,就越幸運。",
+ "author": "蓋瑞·普萊爾"
},
{
- "quote": "The function of good software is to make the complex appear to be simple.",
- "author": "Grady Booch"
+ "quote": "放棄是失敗的唯一可靠途徑。",
+ "author": "吉娜·肖沃爾特"
},
{
- "quote": "When you know that you're capable of dealing with whatever comes, you have the only security the world has to offer.",
- "author": "Harry Browne"
+ "quote": "唯一真正安全的系統是斷了電、澆鑄在混凝土塊中、並密封在有武裝警衛的鉛襯房間內的系統。",
+ "author": "金·斯帕福德"
},
{
- "quote": "Pain is inevitable. Suffering is optional.",
- "author": "Haruki Murakami"
+ "quote": "一生犯錯誤不僅比一生無所事事更光榮,而且更有用。",
+ "author": "蕭伯納"
},
{
- "quote": "Optimism is the faith that leads to achievement. Nothing can be done without hope and confidence.",
- "author": "Helen Keller"
+ "quote": "首先學會計算機科學和所有的理論。 然後發展出一個編程風格。之後便要忘掉所有這些,自由地編碼。",
+ "author": "喬治·卡雷特"
},
{
- "quote": "The price of anything is the amount of life you exchange for it.",
- "author": "Henry David Thoreau"
+ "quote": "發現意想不到的比確認已知的更重要。",
+ "author": "喬治·博克斯"
},
{
- "quote": "Whether you think you can or think you can't, you're right.",
- "author": "Henry Ford"
+ "quote": "我們只能看到自己所知的。",
+ "author": "歌德"
},
{
- "quote": "The most exciting phrase to hear in science, the one that heralds discoveries, is not 'Eureka!' but 'Now that's funny…'",
- "author": "Isaac Asimov"
+ "quote": "不努力耕耘,只會長出雜草。",
+ "author": "戈登·B·欣克利"
},
{
- "quote": "We are all failures. At least the best of us are.",
- "author": "J.M. Barrie"
+ "quote": "好的軟件的功能就是化繁爲簡。",
+ "author": "格雷迪·布奇"
},
{
- "quote": "You can't wait for inspiration. You have to go after it with a club.",
- "author": "Jack London"
+ "quote": "當你知道自己有能力應對任何事情時,你就擁有了世界所能提供的唯一安全感。",
+ "author": "哈利·布朗"
},
{
- "quote": "Don't wish it were easier, wish you were better.",
- "author": "Jim Rohn"
+ "quote": "痛苦不可避免,但可以選擇是否受苦。",
+ "author": "村上春樹"
},
{
- "quote": "By seeking and blundering we learn.",
- "author": "Johann Wolfgang von Goethe"
+ "quote": "樂觀是導致成就的信念。沒有希望和信心,就什麼都做不了。",
+ "author": "海倫·凱勒"
},
{
- "quote": "Knowing is not enough; we must apply. Wishing is not enough; we must do.",
- "author": "Johann Wolfgang von Goethe"
+ "quote": "任何東西的價格都等於你用多少生命去換取它。",
+ "author": "亨利·大衛·梭羅"
},
{
- "quote": "We first make our habits, then our habits make us.",
- "author": "John Dryden"
+ "quote": "不管你認爲你能還是不能,你都是對的。",
+ "author": "亨利·福特"
},
{
- "quote": "The power of imagination makes us infinite.",
- "author": "John Muir"
+ "quote": "在科學中聽到的最令人興奮的短語,即預示着發現的短語,不是“找到了!” 而是“這很有趣……”",
+ "author": "艾薩克·阿西莫夫"
},
{
- "quote": "May you live every day of your life.",
- "author": "Jonathan Swift"
+ "quote": "你所做的會有影響。你必須決定你想要做出什麼樣的改變。",
+ "author": "簡·古道爾"
},
{
- "quote": "Perseverance is failing 19 times and succeeding the 20th.",
- "author": "Julie Andrews"
+ "quote": "我們都是失敗者。至少我們中最好的人是。",
+ "author": "J.M.巴里"
},
{
- "quote": "The work of today is the history of tomorrow, and we are its makers.",
- "author": "Juliette Gordon Low"
+ "quote": "你不能等待靈感。你必須提着木棒去追求它。",
+ "author": "傑克·倫敦"
},
{
- "quote": "If you reveal your secrets to the wind, you should not blame the wind for revealing them to the trees.",
- "author": "Kahlil Gibran"
+ "quote": "不要希望事情更容易,希望你更有能力。",
+ "author": "吉姆·羅恩"
},
{
- "quote": "Optimism is an occupational hazard of programming; feedback is the treatment.",
- "author": "Kent Beck"
+ "quote": "我們通過尋找和犯錯誤來學習。",
+ "author": "約翰·沃爾夫岡·馮·歌德"
},
{
- "quote": "Opportunity does not knock, it presents itself when you beat down the door.",
- "author": "Kyle Chandler"
+ "quote": "知道是不夠的;我們必須應用。希望是不夠的;我們必須行動。",
+ "author": "約翰·沃爾夫岡·馮·歌德"
},
{
- "quote": "To iterate is human, to recurse divine.",
- "author": "Peter Deutsch"
+ "quote": "我們先養成習慣,然後習慣造就我們。",
+ "author": "約翰·德萊登"
},
{
- "quote": "A good traveler has no fixed plans and is not intent on arriving.",
- "author": "Lao Tzu"
+ "quote": "想象力使我們無限。",
+ "author": "約翰·繆爾"
},
{
- "quote": "An ant on the move does more than a dozing ox.",
- "author": "Lao Tzu"
+ "quote": "願你過好每一天。",
+ "author": "喬納森·斯威夫特"
},
{
- "quote": "Do the difficult things while they are easy and do the great things while they are small. A journey of a thousand miles must begin with a single step.",
- "author": "Lao Tzu"
+ "quote": "堅持就是前 19 次失敗,第 20 次成功。",
+ "author": "朱莉·安德魯斯"
},
{
- "quote": "That's the thing about people who think they hate computers. What they really hate is lousy programmers.",
- "author": "Larry Niven"
+ "quote": "今天的工作就是明天的歷史,我們是它的創造者。",
+ "author": "朱麗葉·戈登·洛"
},
{
- "quote": "It had long since come to my attention that people of accomplishment rarely sat back and let things happen to them. They went out and happened to things.",
- "author": "Leonardo da Vinci"
+ "quote": "如果你向風泄露了你的祕密,你不應該責怪風將它們泄露給樹木。",
+ "author": "紀伯倫"
},
{
- "quote": "If you're any good at all, you know you can be better.",
- "author": "Lindsay Buckingham"
+ "quote": "樂觀是編程的職業病;反饋就是治療。",
+ "author": "肯特·貝克"
},
{
- "quote": "If people never did silly things, nothing intelligent would ever get done.",
- "author": "Ludwig Wittgenstein"
+ "quote": "機會不會敲門,它會在你敲門的時候出現。",
+ "author": "凱爾·錢德勒"
},
{
- "quote": "You only live once, but if you do it right, once is enough.",
- "author": "Mae West"
+ "quote": "迭代的是人,遞歸的是神。",
+ "author": "彼得·多伊奇"
},
{
- "quote": "Live as if you were to die tomorrow. Learn as if you were to live forever.",
- "author": "Mahatma Gandhi"
+ "quote": "善行無轍跡,善言無瑕謫。",
+ "author": "老子"
},
{
- "quote": "Strength does not come from physical capacity. It comes from an indomitable will.",
- "author": "Mahatma Gandhi"
+ "quote": "合抱之木,生於毫末;九層之臺,起於累土;千里之行,始於足下。",
+ "author": "老子"
},
{
- "quote": "One person's 'paranoia' is another person's 'engineering redundancy'.",
- "author": "Marcus J. Ranum"
+ "quote": "那些認爲自己討厭電腦的人就是這樣。他們真正討厭的是糟糕的程序員。",
+ "author": "拉里·尼文"
},
{
- "quote": "Nothing in life is to be feared, it is only to be understood. Now is the time to understand more, so that we may fear less.",
- "author": "Marie Curie"
+ "quote": "我早就發現,成功的人很少坐以待斃,讓事情發生在他們身上。他們出去主動去做事。",
+ "author": "達芬奇"
},
{
- "quote": "If you have everything under control, you're not moving fast enough.",
- "author": "Mario Andretti"
+ "quote": "如果你有一點才能,你就會知道你還可以做得更好。",
+ "author": "林賽·白金漢"
},
{
- "quote": "Education: the path from cocky ignorance to miserable uncertainty.",
- "author": "Mark Twain"
+ "quote": "如果人們從不做傻事,就什麼都不會做得聰明。",
+ "author": "路德維希·維特根斯坦"
},
{
- "quote": "It ain't what you don't know that gets you into trouble. It's what you know for sure that just ain't so.",
- "author": "Mark Twain"
+ "quote": "人只活一次,但若活得其所一次已足夠。",
+ "author": "梅·韋斯特"
},
{
- "quote": "The secret of getting ahead is getting started.",
- "author": "Mark Twain"
+ "quote": "像明天就要死一樣生活,像永遠活着一樣學習。",
+ "author": "聖雄甘地"
},
{
- "quote": "The two most important days in your life are the day you are born and the day you find out why.",
- "author": "Mark Twain"
+ "quote": "力量不是來自身體能力。它來自不屈不撓的意志。",
+ "author": "聖雄甘地"
},
{
- "quote": "Twenty years from now you will be more disappointed by the things that you didn't do than by the ones you did do. So throw off the bowlines. Sail away from the safe harbor. Catch the trade winds in your sails.",
- "author": "Mark Twain"
+ "quote": "一個人的“偏執狂”是另一個人的“工程冗餘”。",
+ "author": "馬庫斯·拉納姆"
},
{
- "quote": "Any fool can write code that a computer can understand. Good programmers write code that humans can understand.",
- "author": "Martin Fowler"
+ "quote": "生活中沒有什麼可怕的,只有需要理解的。現在是時候多去理解,這樣我們就會少一些恐懼。",
+ "author": "瑪麗·居里"
},
{
- "quote": "I know, somehow, that only when it is dark enough can you see the stars.",
- "author": "Martin Luther King Jr."
+ "quote": "如果一切都在你的掌控之中,那麼你的行動還不夠快。",
+ "author": "馬里奧·安德雷蒂"
},
{
- "quote": "It is never too late to be what you might have been.",
- "author": "Mary Anne Evans"
+ "quote": "教育:從自大的無知到悲慘的不確定性的道路。",
+ "author": "馬克·吐溫"
},
{
- "quote": "Nothing will work unless you do.",
- "author": "Maya Angelou"
+ "quote": "讓你陷入麻煩的不是你不知道的東西,而是你確信的、其實並不是真的東西。",
+ "author": "馬克·吐溫"
},
{
- "quote": "We delight in the beauty of the butterfly, but rarely admit the changes it has gone through to achieve that beauty.",
- "author": "Maya Angelou"
+ "quote": "取得成功的祕訣就是開始。",
+ "author": "馬克·吐溫"
},
{
- "quote": "We may encounter many defeats, but we must not be defeated.",
- "author": "Maya Angelou"
+ "quote": "你生命中最重要的兩天是你出生的那一天和你找到意義的那一天。",
+ "author": "馬克·吐溫"
},
{
- "quote": "Everybody has talent, but ability takes hard work.",
- "author": "Michael Jordan"
+ "quote": "二十年後,你會因自己沒做的事情而更加失望,而不是做過的事情。所以,請解開繩索,駛離安全的港灣,揚帆起航吧。",
+ "author": "馬克·吐溫"
},
{
- "quote": "I've missed more than 9,000 shots during my career. I've lost almost 300 games. 26 times, I've been trusted to take the game winning shot and missed. I've failed over and over and over again in my life. And that is why I succeed.",
- "author": "Michael Jordan"
+ "quote": "任何傻瓜都可以編寫計算機可以理解的代碼。優秀的程序員編寫人類可以理解的代碼。",
+ "author": "馬丁·福勒"
},
{
- "quote": "Impossible is just a big word thrown around by small men who find it easier to live in the world they've been given than to explore the power they have to change it. Impossible is not a fact. It's an opinion. Impossible is not a declaration. It's a dare. Impossible is potential. Impossible is temporary. Impossible is nothing.",
- "author": "Muhammad Ali"
+ "quote": "我知道,不知何故,只有當天足夠黑時,你才能看到星星。",
+ "author": "馬丁·路德·金"
},
{
- "quote": "A winner is a dreamer who never gives up.",
- "author": "Nelson Mandela"
+ "quote": "永遠不會太晚去成爲你可能成爲的人。",
+ "author": "瑪麗·安妮·埃文斯"
},
{
- "quote": "It always seems impossible until it's done.",
- "author": "Nelson Mandela"
+ "quote": "除非你行動起來,否則什麼都不會改變。",
+ "author": "瑪雅·安傑洛"
},
{
- "quote": "Failure will never overtake me if my determination to succeed is strong enough.",
- "author": "Og Mandino"
+ "quote": "你無法用盡創造力。使用得越多,就會有越多。",
+ "author": "瑪雅·安傑洛"
},
{
- "quote": "I am not young enough to know everything.",
- "author": "Oscar Wilde"
+ "quote": "我們喜歡蝴蝶的美麗,但很少承認它爲實現這種美麗所經歷的變化。",
+ "author": "瑪雅·安傑洛"
},
{
- "quote": "There is only one thing that makes a dream impossible to achieve: the fear of failure.",
- "author": "Paulo Coelho"
+ "quote": "我們可能會遇到很多失敗,但我們絕不能被擊敗。",
+ "author": "瑪雅·安傑洛"
},
{
- "quote": "Never go to bed mad. Stay up and fight.",
- "author": "Phyllis Diller"
+ "quote": "每個人都有天賦,但能力需要努力。",
+ "author": "邁克爾·喬丹"
},
{
- "quote": "You can't cross the sea merely by standing and staring at the water.",
- "author": "Rabindranath Tagore"
+ "quote": "在我的職業生涯中,我錯過了 9000 多次投籃。我輸掉了近 300 場比賽。26 次,我被信任去投決勝一投,但都沒有命中。我一次又一次地失敗。但正因如此,我才獲得了成功。",
+ "author": "邁克爾·喬丹"
},
{
- "quote": "The only person you are destined to become is the person you decide to be.",
- "author": "Ralph Waldo Emerson"
+ "quote": "“不可能”只是小人物們輕易拋出的大詞,他們寧願留在自己被賦予的世界裏,也不願探索自己改變它的力量。“不可能”不是事實,而是意見。“不可能”不是宣言,而是挑戰。“不可能”是潛力。“不可能”是暫時的。“不可能”什麼也不是。",
+ "author": "穆罕默德·阿里"
},
{
- "quote": "What you do speaks so loudly that I cannot hear what you say.",
- "author": "Ralph Waldo Emerson"
+ "quote": "勝利者是永不放棄的夢想家。",
+ "author": "納爾遜·曼德拉"
},
{
- "quote": "People who are crazy enough to think they can change the world, are the ones who do.",
- "author": "Rob Siltanen"
+ "quote": "看起來總是不可能,直到它被做到。",
+ "author": "納爾遜·曼德拉"
},
{
- "quote": "The best way out is always through.",
- "author": "Robert Frost"
+ "quote": "如果我成功的決心足夠堅定,失敗永遠不會壓倒我。",
+ "author": "奧格·曼狄諾"
},
{
- "quote": "Today's accomplishments were yesterday's impossibilities.",
- "author": "Robert H. Schuller"
+ "quote": "我還不夠年輕,不可能瞭解所有的事情。",
+ "author": "奧斯卡·王爾德"
},
{
- "quote": "Don't be satisfied with stories, how things have gone with others. Unfold your own myth.",
- "author": "Rumi"
+ "quote": "只有一件事使夢想無法實現:對失敗的恐懼。",
+ "author": "保羅·柯艾略"
},
{
- "quote": "Forget safety. Live where you fear to live. Destroy your reputation. Be notorious.",
- "author": "Rumi"
+ "quote": "光是站着看水是無法渡海的。",
+ "author": "羅賓德拉納特·泰戈爾"
},
{
- "quote": "Sell your cleverness and buy bewilderment.",
- "author": "Rumi"
+ "quote": "你註定要成爲的唯一的人,就是你決定成爲的人。",
+ "author": "拉爾夫·沃爾多·愛默生"
},
{
- "quote": "The cure for pain is in the pain.",
- "author": "Rumi"
+ "quote": "你的所作所爲聲音很大,我聽不見你在說什麼。",
+ "author": "拉爾夫·沃爾多·愛默生"
},
{
- "quote": "Have no fear of perfection - you'll never reach it.",
- "author": "Salvador Dalí"
+ "quote": "那些足夠瘋狂以爲自己可以改變世界的人,纔是真正改變世界的人。",
+ "author": "羅伯·西塔寧"
},
{
- "quote": "Don't watch the clock. Do what it does. Keep going.",
- "author": "Sam Levenson"
+ "quote": "最好的出路是有始有終。",
+ "author": "羅伯特·弗羅斯特"
},
{
- "quote": "Ever Tried. Ever failed. No matter. Try again. Fail again. Fail better.",
- "author": "Samuel Beckett"
+ "quote": "今天的成就是昨天的不可能。",
+ "author": "羅伯特·舒樂"
},
{
- "quote": "The more you know, the more you realize you know nothing.",
- "author": "Socrates"
+ "quote": "不要滿足於故事,不要滿足於別人的經歷。揭開你自己的神話。",
+ "author": "魯米"
},
{
- "quote": "The greatest enemy of knowledge is not ignorance, it is the illusion of knowledge.",
- "author": "Stephen Hawking"
+ "quote": "忘掉安全感,到你所害怕的地方去生活。摧毀你的名聲,做一個聲名狼藉的人。",
+ "author": "魯米"
},
{
- "quote": "The universe doesn't allow perfection.",
- "author": "Stephen Hawking"
+ "quote": "賣掉你的聰明,買下困惑。",
+ "author": "魯米"
},
{
- "quote": "Whether you want to uncover the secrets of the universe, or you want to pursue a career in the 21st century, basic computer programming is an essential skill to learn.",
- "author": "Stephen Hawking"
+ "quote": "治療疼痛的方法是在疼痛中。",
+ "author": "魯米"
},
{
- "quote": "The scariest moment is always just before you start.",
- "author": "Stephen King"
+ "quote": "不要害怕完美——你永遠達不到完美。",
+ "author": "薩爾瓦多·達利"
},
{
- "quote": "You can, you should, and if you're brave enough to start, you will.",
- "author": "Stephen King"
+ "quote": "不要看時鐘。做它做的事情。繼續前進。",
+ "author": "山姆·李文生"
},
{
- "quote": "Arise, Awake and Stop not until the goal is reached.",
- "author": "Swami Vivekananda"
+ "quote": "曾經嘗試過。曾經失敗過。沒關係。再嘗試一次。再失敗一次。做得更好。",
+ "author": "塞繆爾·貝克特"
},
{
- "quote": "It is said that your life flashes before your eyes just before you die. That is true, it's called Life.",
- "author": "Terry Pratchett"
+ "quote": "你知道的越多,你就越發現你什麼都不知道。",
+ "author": "蘇格拉底"
},
{
- "quote": "Believe you can and you're halfway there.",
- "author": "Theodore Roosevelt"
+ "quote": "知識最大的敵人不是無知,而是知識的幻覺。",
+ "author": "史蒂芬·霍金"
},
{
- "quote": "I have not failed. I've just found 10,000 ways that won't work.",
- "author": "Thomas A. Edison"
+ "quote": "宇宙不允許完美。",
+ "author": "史蒂芬·霍金"
},
{
- "quote": "Our greatest weakness lies in giving up. The most certain way to succeed is always to try just one more time.",
- "author": "Thomas A. Edison"
+ "quote": "無論你是想揭開宇宙的祕密,還是想在 21 世紀謀求職業,基礎計算機編程是必學的技能。",
+ "author": "史蒂芬·霍金"
},
{
- "quote": "The harder the conflict, the more glorious the triumph.",
- "author": "Thomas Paine"
+ "quote": "最可怕的時刻總是在你開始之前。",
+ "author": "史蒂芬.金"
},
{
- "quote": "The Web as I envisaged it, we have not seen it yet. The future is still so much bigger than the past.",
- "author": "Tim Berners-Lee"
+ "quote": "你可以,你應該,如果你有足夠的勇氣開始,你會的。",
+ "author": "史蒂芬.金"
},
{
- "quote": "Failure is the condiment that gives success its flavor.",
- "author": "Truman Capote"
+ "quote": "起牀,醒來,直到達到目標才停下來。",
+ "author": "斯瓦米·維韋卡南達"
},
{
- "quote": "Those who says it cannot be done should not interrupt the person doing it.",
- "author": "Unknown"
+ "quote": "據說,就在你死之前,你的生命在你眼前閃過。沒錯,這就是所謂的生活。",
+ "author": "泰瑞·普萊契"
},
{
- "quote": "Even if you fall on your face, you're still moving forward.",
- "author": "Victor Kiam"
+ "quote": "相信你可以,你就成功了一半。",
+ "author": "西奧多·羅斯福"
},
{
- "quote": "It's not whether you get knocked down, it's whether you get up.",
- "author": "Vince Lombardi"
+ "quote": "我沒有失敗。我只是找到了一萬種行不通的方法。",
+ "author": "愛迪生"
},
{
- "quote": "I dream my painting and I paint my dream.",
- "author": "Vincent van Gogh"
+ "quote": "我們最大的弱點在於放棄。最確定的成功方法永遠是再試一次。",
+ "author": "愛迪生"
},
{
- "quote": "Let us cultivate our garden.",
- "author": "Voltaire"
+ "quote": "衝突越激烈,勝利就越光榮。",
+ "author": "托馬斯·潘恩"
},
{
- "quote": "Aim for the moon. If you miss, you may hit a star.",
- "author": "W. Clement Stone"
+ "quote": "我所設想的網絡,我們還沒有看到。未來仍然比過去要大得多。",
+ "author": "蒂姆·伯納斯-李"
},
{
- "quote": "The way to get started is to quit talking and begin doing.",
- "author": "Walt Disney"
+ "quote": "失敗是給成功增添風味的調味品。",
+ "author": "杜魯門·卡波特"
},
{
- "quote": "You miss 100% of the shots you don't take.",
- "author": "Wayne Gretzky"
+ "quote": "那些說這是不可能的人,不應該打斷正在做這件事的人。",
+ "author": "佚名"
},
{
- "quote": "Don't let yesterday take up too much of today.",
- "author": "Will Rogers"
+ "quote": "用不同的眼光看待平常的事物。",
+ "author": "維科·馬吉斯泰蒂"
},
{
- "quote": "Even if you're on the right track, you'll get run over if you just sit there.",
- "author": "Will Rogers"
+ "quote": "即使你摔倒在地,你仍然在前進。",
+ "author": "維克托·基亞姆"
},
{
- "quote": "Do not wait to strike till the iron is hot; but make it hot by striking.",
- "author": "William Butler Yeats"
+ "quote": "重要的不是你是否被擊倒,而是你是否爬起來。",
+ "author": "文斯·隆巴迪"
},
{
- "quote": "You cannot swim for new horizons until you have courage to lose sight of the shore.",
- "author": "William Faulkner"
+ "quote": "我夢想我的畫,我畫我的夢。",
+ "author": "文森特·梵高"
},
{
- "quote": "Be not afraid of greatness. Some are born great, some achieve greatness, and others have greatness thrust upon them.",
- "author": "William Shakespeare"
+ "quote": "偉大的事情是由一系列小事情匯聚而成的。",
+ "author": "文森特·梵高"
},
{
- "quote": "We know what we are, but not what we may be.",
- "author": "William Shakespeare"
+ "quote": "讓我們耕種我們的花園。",
+ "author": "伏爾泰"
},
{
- "quote": "In theory there is no difference between theory and practice. In practice there is.",
- "author": "Yogi Berra"
+ "quote": "瞄準月亮。如果你錯失目標,你可能會擊中一顆恆星。",
+ "author": "克萊門特·斯通"
},
{
- "quote": "You can see a lot by just looking.",
- "author": "Yogi Berra"
+ "quote": "開始的方法是停止說話,開始行動。",
+ "author": "沃爾特·迪斯尼"
},
{
- "quote": "There is no elevator to success, you have to take the stairs.",
- "author": "Zig Ziglar"
+ "quote": "你不嘗試的話,就有 100% 的機會失敗。",
+ "author": "韋恩·格雷茨基"
},
{
- "quote": "You don't have to be great to start, but you have to start to be great.",
- "author": "Zig Ziglar"
+ "quote": "不要讓昨天佔據太多的今天。",
+ "author": "威爾·羅傑斯"
+ },
+ {
+ "quote": "即使你是在正確的路上,如果你只是坐在那裏,你也會被撞倒。",
+ "author": "威爾·羅傑斯"
+ },
+ {
+ "quote": "不要等鐵熱了再打;要用敲打使它變熱。",
+ "author": "威廉·巴特勒·葉芝"
+ },
+ {
+ "quote": "除非你有勇氣離開海岸,否則你無法遊向新的地平線。",
+ "author": "威廉·福克納"
+ },
+ {
+ "quote": "不要害怕偉大。 有些人天生偉大,有些人成就偉大,而另一些人則被推向偉大。",
+ "author": "威廉·莎士比亞"
+ },
+ {
+ "quote": "我們知道我們是什麼,但不知道我們可能成爲什麼。",
+ "author": "威廉·莎士比亞"
+ },
+ {
+ "quote": "從理論上講,理論和實踐之間沒有區別。在實踐中是有的。",
+ "author": "約吉·貝拉"
+ },
+ {
+ "quote": "通過看,你就可以覺察到很多東西。",
+ "author": "約吉·貝拉"
+ },
+ {
+ "quote": "成功沒有電梯,你必須走樓梯。",
+ "author": "齊格·齊格勒"
+ },
+ {
+ "quote": "你不一定要很偉大才能開始,但你必須開始才能變得偉大。",
+ "author": "齊格·齊格勒"
}
]
}
diff --git a/client/i18n/locales/chinese-traditional/translations.json b/client/i18n/locales/chinese-traditional/translations.json
index ae3ed605d182b7..ea2808a2c9bbda 100644
--- a/client/i18n/locales/chinese-traditional/translations.json
+++ b/client/i18n/locales/chinese-traditional/translations.json
@@ -11,11 +11,12 @@
"view": "查看",
"view-code": "查看代碼",
"view-project": "查看項目",
+ "view-cert-title": "View {{certTitle}}",
"show-cert": "顯示認證",
"claim-cert": "申請認證",
"save-progress": "保存進度",
- "accepted-honesty": "你已接受我們的《學術誠信條例》",
- "agree": "同意",
+ "accepted-honesty": "You have agreed to our Academic Honesty Policy.",
+ "agree-honesty": "I agree to freeCodeCamp's Academic Honesty Policy.",
"save-portfolio": "保存這個作品集項目",
"remove-portfolio": "移除這個作品集項目",
"add-portfolio": "增加一個新的作品集項目",
@@ -52,7 +53,7 @@
"check-code": "檢查您的代碼 (Ctrl + Enter)",
"check-code-2": "檢查你的代碼",
"reset": "重置",
- "reset-code": "重置所有代碼",
+ "reset-step": "Reset This Step",
"help": "幫助",
"get-help": "獲得幫助",
"watch-video": "觀看視頻",
@@ -157,7 +158,8 @@
"honesty": "學術誠信條例",
"internet": "你在各平臺的賬號",
"portfolio": "作品集設置",
- "privacy": "隱私設置"
+ "privacy": "隱私設置",
+ "personal-info": "Personal Information"
},
"danger": {
"heading": "危險區域",
@@ -222,16 +224,15 @@
"total-points_plural": "{{count}} 總分",
"points": "{{date}} 獲得 {{count}} 分",
"points_plural": "{{date}} 獲得 {{count}} 分",
- "screen-shot": "{{title}} 截圖",
"page-number": "第 {{pageNumber}} 頁,共 {{totalPages}} 頁"
},
"footer": {
- "tax-exempt-status": "freeCodeCamp 是捐助者支持的 501(c)(3) 條款下具有免稅資格的非營利性組織(稅號:82-0779546)。",
+ "tax-exempt-status": "freeCodeCamp 是捐助者支持的 501(c)(3) 條款下具有免稅資格的慈善組織(稅號:82-0779546)。",
"mission-statement": "我們的使命:幫助人們免費學習編程。我們通過創建成千上萬的視頻、文章和交互式編程課程——所有內容向公衆免費開放——來實現這一目標。學員在世界各地自發成立數千個 freeCodeCamp 學習小組。",
"donation-initiatives": "所有給 freeCodeCamp 的捐款都將用於我們的教育項目,購買服務器和其他服務,以及聘用員工。",
"donate-text": "你可以<1>在此處進行免稅捐贈1>。",
"trending-guides": "精選文章",
- "our-nonprofit": "關於我們",
+ "our-nonprofit": "我們的慈善組織",
"links": {
"about": "簡介",
"alumni": "校友網絡",
@@ -249,6 +250,7 @@
},
"learn": {
"heading": "歡迎學習 freeCodeCamp 的課程。",
+ "skip-to-content": "Skip to content",
"welcome-1": "歡迎回來,{{name}}。",
"welcome-2": "歡迎來到 freeCodeCamp.org",
"start-at-beginning": "如果你剛開始學習編程,我們建議你<0>從頭開始0>。",
@@ -264,7 +266,7 @@
"p8": "這套課程需要你進行數千個小時的編程練習。",
"p9": "如果你想學習更多數學和計算機科學理論,<0>freeCodeCamp 的 \n YouTube channel0> 還有數千個小時的視頻課程。",
"p10": "如果你想獲得開發者工作或者成爲自由職業開發者找到客戶,那麼除了編程技能,你還需要搭建自己的社交網絡,打造自己作爲開發者的影響力。",
- "p11": "You can do this on LinkedIn and GitHub, and also on <0>the freeCodeCamp forum0>.",
+ "p11": "你還可以在 LinkedIn、Twitter、GitHub 和 <0>freeCodeCamp 論壇0> 上做到這一點。",
"p12": "編程愉快!"
},
"upcoming-lessons": "即將上線的課程",
@@ -272,6 +274,9 @@
"add-subtitles": "幫助我們完善或添加字幕",
"wrong-answer": "抱歉,這個答案不正確。再試一次?",
"check-answer": "點擊下方按鈕,查看你的答案。",
+ "assignment-not-complete": "Please finish the assignments",
+ "assignments": "Assignments",
+ "question": "Question",
"solution-link": "解決方案鏈接",
"github-link": "GitHub 鏈接",
"submit-and-go": "提交併訪問下一個挑戰",
@@ -284,7 +289,7 @@
"sign-in-save": "登錄以保存你的學習進度",
"download-solution": "下載我的解決方案",
"percent-complete": "完成 {{percent}}%",
- "project-complete": "Completed {{completedChallengesInBlock}} of {{totalChallengesInBlock}} certification projects",
+ "project-complete": "已完成 {{totalChallengesInBlock}} 認證項目中的 {{completedChallengesInBlock}}",
"tried-rsa": "如果你已經嘗試了 <0>Read-Search-Ask(閱讀-搜索-提問)0>方法,那麼你可以在 freeCodeCamp 論壇請求幫助。",
"rsa": "閱讀,搜索,提問",
"rsa-forum": "在發佈新帖子之前 ,請確認你的問題是否<0>已經在論壇上被回答過0>。",
@@ -297,7 +302,6 @@
"certs": "{{title}} 認證"
},
"editor-tabs": {
- "info": "信息",
"code": "編程",
"tests": "測試",
"restart": "重啓",
@@ -307,6 +311,10 @@
"notes": "注意",
"preview": "預覽"
},
+ "editor-alerts": {
+ "tab-trapped": "按下選項卡將插入選項卡字符",
+ "tab-free": "按下選項卡將焦點移動到下一個焦點元素"
+ },
"help-translate": "我們仍然在翻譯以下證書。",
"help-translate-link": "幫助我們翻譯。",
"project-preview-title": "下面是你將構建的項目的預覽",
@@ -326,16 +334,16 @@
"sorry-hang-in-there": "抱歉,你的代碼未通過,堅持一下。",
"sorry-dont-giveup": "抱歉,你的代碼未通過,不要放棄。",
"challenges-completed": "已完成 {{completedCount}}/{{totalChallenges}}",
- "season-greetings-fcc": "Season's Greetings from the freeCodeCamp community 🎉",
- "if-getting-value": "If you're getting a lot out of freeCodeCamp, now is a great time to donate to support our nonprofit's mission.",
- "building-a-university": "We're Building a Free Computer Science University Degree Program",
- "if-help-university": "We've already made a ton of progress. Support our charity with the long road ahead."
+ "season-greetings-fcc": "來自 freeCodeCamp 社區的季節問候 🎉",
+ "if-getting-value": "如果你從 freeCodeCamp 中獲益良多,可以捐款支持我們的慈善組織的使命。",
+ "building-a-university": "我們正在創建一個免費計算機科學大學學位課程",
+ "if-help-university": "我們已取得了重大進展。請支持我們的慈善組織完成這項長期事業。"
},
"donate": {
- "title": "支持我們的非營利組織",
+ "title": "支持我們的慈善組織",
"processing": "我們正在處理你的捐款。",
"redirecting": "重新引導中...",
- "thanks": "謝謝捐款",
+ "thanks": "Thanks for donating",
"thank-you": "謝謝你成爲我們的支持者。",
"additional": "你可以使用這個鏈接 <0>{{url}}0> 額外進行一次性捐款:",
"help-more": "幫助我們做更多",
@@ -354,11 +362,10 @@
"your-donation": "你的 ${{usd}} 捐款將幫助世界各地的人們學習 {{hours}} 小時。",
"your-donation-2": "你的 ${{usd}} 捐款每月將幫助世界各地的人們學習 {{hours}} 小時。",
"your-donation-3": "你的 ${{usd}} 捐款每年將幫助世界各地的人們學習 {{hours}} 小時。",
- "become-supporter": "Become a Supporter",
- "duration": "成爲我們非營利組織的一次性支持者",
- "duration-2": "成爲我們非營利組織的每月定期支持者",
- "duration-3": "成爲我們非營利組織的每年定期支持者",
- "duration-4": "成爲我們非營利組織的支持者",
+ "become-supporter": "成爲支持者",
+ "duration": "成爲我們的慈善組織的一次性支持者",
+ "duration-2": "成爲我們的慈善組織的每月定期支持者",
+ "duration-4": "成爲我們的慈善組織的支持者",
"nicely-done": "很棒,你已完成 {{block}}。",
"credit-card": "信用卡",
"credit-card-2": "或者使用信用卡捐款:",
@@ -372,25 +379,25 @@
"email-receipt": "郵箱(我們將把捐款稅務收據發送給你):",
"need-help": "需要我們幫助處理你的當前或之前的捐款?",
"forward-receipt": "將你的捐款收據副本發送至 donors@freecodecamp.org,告訴我們你需要什麼幫助。",
- "efficiency": "freeCodeCamp 是一個高效率的專注教育的非營利組織。",
+ "efficiency": "freeCodeCamp 是一個高效率的教育慈善組織。",
"why-donate-1": "通過給 freeCodeCamp 捐款,你幫助人們學習新技能以供養家庭。",
"why-donate-2": "你也幫助我們創建新的學習資源,你可以利用這些資源拓展自己的技術能力。",
"bigger-donation": "給我們額度更大的一次性捐款,或寄一張支票,或通過其他方式給我們捐款?",
- "other-ways": "有許多<0>其他方式可以支持我們的非營利組織踐行使命0>.",
+ "other-ways": "有許多<0>其他方式可以支持我們的慈善組織踐行使命0>.",
"failed-pay": "呃,你的轉賬似乎沒有成功,再試一次好嗎?",
"try-again": "請重試。",
"card-number": "你的卡號:",
"expiration": "到期日:",
"secure-donation": "安全捐款",
"faq": "常見問題",
- "only-you": "只有你可以看到此消息。祝賀你獲得這項認證。獲得認證不是一件容易的事情,運營 freeCodeCamp 也不容易,而且需要花費很多。請幫助我們更好地幫助你和世界各地的許多其他人。今天就爲我們的非營利組織提供免稅捐款,支持我們。",
+ "only-you": "只有你可以看到此消息。祝賀你獲得這項認證。獲得認證不是一件容易的事情,運營 freeCodeCamp 也不容易,而且需要花費很多。請幫助我們更好地幫助你和世界各地的許多其他人。今天就爲我們的慈善組織提供免稅捐款,支持我們。",
"get-help": "我如何利用我的捐款得到幫助?",
"how-transparent": "freeCodeCamp.org 的透明度如何?",
"very-transparent": "我們甚至有一個來自 GuideStar.org 的白金透明度評級。",
"download-irs": "你可以<0>在此處下載我們的國稅局認定函0>。",
"download-990": "你可以<0>在此處下載我們最新的 990 (年度稅務報告)0>。",
"how-efficient": "freeCodeCamp 的效率如何?",
- "fcc-budget": "freeCodeCamp 的預算比大多數非營利組織少得多。我們還沒有引入專業募捐者,而是 Quincy 自己處理一切相關事務。",
+ "fcc-budget": "freeCodeCamp 的預算比大多數慈善組織少得多。我們還沒有引入專業募捐者,而是 Quincy 自己處理一切相關事務。",
"help-millions": "然而,在每年僅有 10 萬美元的預算中,我們能夠幫助數百萬人。",
"how-one-time": "我如何進行一次性捐款?",
"one-time": "如果你喜歡一次性捐款,你可以在有閒錢時支持 freeCodeCamp 的事業。你可以使用<0>此鏈接,通過 PayPal 捐你認爲合適的金額0>。",
@@ -400,7 +407,7 @@
"can-check": "我可以郵寄實物支票嗎?",
"yes-check": "是的,我們歡迎支票。你可以將其郵寄給我們:",
"how-matching-gift": "我如何從我的僱主那裏設置匹配的禮物,或者工資扣除?",
- "employers-vary": "這因僱主而異,而我們的非營利組織已經被列入許多大型捐贈匹配數據庫。",
+ "employers-vary": "這因僱主而異,而我們的慈善組織已經被列入許多大型捐贈匹配數據庫。",
"some-volunteer": "有些人能夠爲 freeCodeCamp 提供志願服務,他們的僱主通過每小時志願服務捐贈一個固定的金額進行匹配。其他僱主會對捐贈者的任何捐贈進行匹配,最高可達某一數額。",
"help-matching-gift": "如你需要幫助,請直接給 Quincy 發送電子郵件:quincy@freecodecamp.org",
"how-endowment": "如何爲 freeCodeCamp.org 設置捐贈禮物?",
@@ -411,13 +418,13 @@
"thank-wikimedia": "我們要感謝維基百科基金會爲我們提供這種正式文書。",
"legacy-gift-questions": "如果你對此過程有任何疑問,請給 Quincy 發送電子郵件到 Quincy@freecodecamp.org。",
"how-stock": "如何將股票捐贈給 freeCodeCamp.org?",
- "welcome-stock": "我們歡迎你的股票捐贈。請直接爲 Quincy 發送電子郵件到 quincy@freecodecamp.org,他可以幫助你做到這一點,並分享我們的非營利經紀業務賬戶的詳細信息。",
+ "welcome-stock": "我們歡迎你的股票捐贈。請直接給 Quincy 發送電子郵件到 quincy@freecodecamp.org,他可以幫助你,並分享我們的慈善組織的經紀賬戶的詳細信息。",
"how-receipt": "我能夠收到捐贈收據以從我的稅款中扣除我的捐贈嗎?",
"just-forward": "可以,只需將你交易的收據轉發到 donors@freecodecamp.org,告訴我們你想要一個收據以及你的使用場景,我們將發給你一個收據。",
"how-update": "我設置了每月捐款,但我需要更新或暫停每月的重複。我如何做?",
"take-care-of-this": "只需轉發你的每月捐款記錄中的一個記錄給 donors@freecodecamp.org, 並告訴我們你要做什麼。我們會爲你處理這個問題,並向你發送確認。",
"anything-else": "還有什麼關於爲 freeCodeCamp.org 捐贈可以瞭解的嗎?",
- "other-support": "如果你想要以其他方式支持我們的非營利工作並且它的渠道沒有在此列出, 或者如果你有任何問題,請給 Quincy 發送電子郵件到 quincy@freecodecamp.org。"
+ "other-support": "如果你想要通過此處未列出的其他方式支持我們的慈善組織和它的使命,或者如果你有任何問題,請給 Quincy 發送電子郵件到 quincy@freecodecamp.org。"
},
"report": {
"sign-in": "你需要先登錄才能舉報用戶",
@@ -460,7 +467,8 @@
"iframe-preview": "{{title}} 預覽",
"iframe-alert": "通常,此鏈接會將你帶到另一個網站!一切正常,這個鏈接指向:{{externalLink}}。",
"iframe-form-submit-alert": "通常這個表單將被提交!工作正常,這將被提交到:{{externalLink}}",
- "document-notfound": "找不到文件"
+ "document-notfound": "找不到文件",
+ "slow-load-msg": "Looks like this is taking longer than usual, please try refreshing the page."
},
"icons": {
"gold-cup": "金獎盃",
@@ -475,10 +483,11 @@
"hint": "提示",
"heart": "愛心",
"initial": "初始",
+ "input-reset": "Clear search terms",
"info": "介紹信息",
"spacer": "間隔",
"toggle": "切換選中標記",
- "magnifier": "放大鏡"
+ "magnifier": "Submit search terms"
},
"aria": {
"fcc-curriculum": "freeCodeCamp 課程",
@@ -504,10 +513,11 @@
"step": "步驟",
"steps": "步驟",
"steps-for": "{{blockTitle}} 的步驟",
- "code-example": "{{codeName}} code example"
+ "code-example": "{{codeName}} 代碼示例",
+ "opens-new-window": "Opens in new window"
},
"flash": {
- "honest-first": "申請認證之前,你必須先接受我們的《學術誠信條例》",
+ "honest-first": "To claim a certification, you must first agree to our academic honesty policy",
"really-weird": "出現了一些奇怪的情況。如果再出現這種情況,請考慮在 https://github.com/freeCodeCamp/freeCodeCamp/issues/new 提交 issue。",
"not-right": "有些不對勁。已生成報告,通知 freeCodeCamp.org 團隊。",
"went-wrong": "出了點問題,請檢查並重試。",
@@ -586,7 +596,8 @@
"editor-url": "記得要提交Live App的URL",
"http-url": "不能使用不安全的(http)URL。",
"own-work-url": "記住要提交你自己的作業",
- "publicly-visible-url": "記得要提交一個公開可見的app URL"
+ "publicly-visible-url": "記得要提交一個公開可見的app URL",
+ "path-url": "You probably want to submit the root path i.e. https://example.com, not https://example.com/path"
},
"certification": {
"executive": "執行董事,freeCodeCamp.org",
@@ -668,8 +679,49 @@
"Cat and Dog Image Classifier": "貓和狗圖像分類器",
"Book Recommendation Engine using KNN": "基於 KNN 的圖書推薦引擎",
"Linear Regression Health Costs Calculator": "線性迴歸健康成本計算器",
- "Neural Network SMS Text Classifier": "神經網絡短信分類器"
+ "Neural Network SMS Text Classifier": "神經網絡短信分類器",
+ "Celestial Bodies Database": "Celestial Bodies Database",
+ "World Cup Database": "World Cup Database",
+ "Salon Appointment Scheduler": "Salon Appointment Scheduler",
+ "Periodic Table Database": "Periodic Table Database",
+ "Number Guessing Game": "Number Guessing Game",
+ "Build a freeCodeCamp Forum Homepage": "Build a freeCodeCamp Forum Homepage"
}
+ },
+ "title": {
+ "Responsive Web Design": "Responsive Web Design",
+ "responsive-web-design": "Responsive Web Design Certification",
+ "JavaScript Algorithms and Data Structures": "JavaScript Algorithms and Data Structures",
+ "javascript-algorithms-and-data-structures": "JavaScript Algorithms and Data Structures Certification",
+ "Front End Development Libraries": "Front End Development Libraries",
+ "front-end-development-libraries": "Front End Development Libraries Certification",
+ "Data Visualization": "Data Visualization",
+ "data-visualization": "Data Visualization Certification",
+ "Relational Database": "Relational Database",
+ "relational-database-v8": "Relational Database Certification",
+ "Back End Development and APIs": "Back End Development and APIs",
+ "back-end-development-and-apis": "Back End Development and APIs Certification",
+ "Quality Assurance": "Quality Assurance",
+ "quality-assurance-v7": "Quality Assurance Certification",
+ "Scientific Computing with Python": "Scientific Computing with Python",
+ "scientific-computing-with-python-v7": "Scientific Computing with Python Certification",
+ "Data Analysis with Python": "Data Analysis with Python",
+ "data-analysis-with-python-v7": "Data Analysis with Python Certification",
+ "Information Security": "Information Security",
+ "information-security-v7": "Information Security Certification",
+ "Machine Learning with Python": "Machine Learning with Python",
+ "machine-learning-with-python-v7": "Machine Learning with Python Certification",
+ "Legacy Front End": "Legacy Front End",
+ "legacy-front-end": "Front End Certification",
+ "Legacy Back End": "Legacy Back End",
+ "legacy-back-end": "Back End Certification",
+ "Legacy Data Visualization": "Legacy Data Visualization",
+ "legacy-data-visualization": "Data Visualization Certification",
+ "Legacy Information Security and Quality Assurance": "Legacy Information Security and Quality Assurance",
+ "information-security-and-quality-assurance": "Information Security and Quality Assurance Certification",
+ "Legacy Full Stack Certification": "Legacy Full Stack Certification",
+ "Legacy Full Stack": "Legacy Full Stack",
+ "full-stack": "Full Stack Certification"
}
},
"certification-card": {
@@ -724,10 +776,10 @@
"navigate-next": "跳轉至下一個練習"
},
"signout": {
- "heading": "Sign out of your account",
- "p1": "Warning: If you continue, your progress will no longer be saved.",
- "p2": "This action will sign you out of your account on this device and browser session only. Please confirm if you would like to proceed.",
- "certain": "Yes, sign out of my account",
- "nevermind": "Nevermind, I don't want to sign out"
+ "heading": "註銷你的賬戶",
+ "p1": "警告:如果你繼續,你的當前進度將不再被保存。",
+ "p2": "此操作只會將你在此設備和瀏覽器會話上的賬號註銷。請確認你是否要繼續。",
+ "certain": "是的,請註銷我的賬戶",
+ "nevermind": "算了,我不想註銷賬戶"
}
}
diff --git a/client/i18n/locales/chinese/intro.json b/client/i18n/locales/chinese/intro.json
index bf8b57ea863a39..5d0179ab507947 100644
--- a/client/i18n/locales/chinese/intro.json
+++ b/client/i18n/locales/chinese/intro.json
@@ -335,6 +335,10 @@
"learn-functional-programming-by-building-a-spreadsheet": {
"title": "通过构建电子表格学习函数式编程",
"intro": ["", ""]
+ },
+ "learn-advanced-array-methods-by-building-a-statistics-calculator": {
+ "title": "Learn Advanced Array Methods by Building a Statistics Calculator",
+ "intro": ["", ""]
}
}
},
@@ -553,7 +557,7 @@
"intro": [
"在这之前,你只是在前端使用 JavaScript 来给页面添加交互、解决算法挑战,或构建一个 SPA(单页应用程序)。但 JavaScript 也可以用于后端或者服务器来构建整个 web 应用程序。",
"今天,构建应用软件的广受欢迎的方法之一是微服务,这些微服务是一种小型模块化的应用,能够共同形成一个更大的整体。",
- "在后端开发和 APIs 认证中,你将学习如何使用 Node.js 和 npm(Node 包管理工具)来写后端。你还将使用 Express 框架构建 web 应用程序,并使用 MongoDB 和 Mongoose 库构建一个 People Finder 微服务。"
+ "In the Back End Development and APIs Certification, you'll learn how to write back end apps with Node.js and npm. You'll also build web applications with the Express framework, and build a People Finder microservice with MongoDB and the Mongoose library."
],
"note": "",
"blocks": {
@@ -787,6 +791,24 @@
}
}
},
+ "the-odin-project": {
+ "title": "The Odin Project",
+ "intro": [
+ "The Odin Project is one of those \"What I wish I had when I was learning\" resources. ",
+ "Not everyone has access to a computer science education or the funds to attend an intensive coding school and neither of those is right for everyone anyway.",
+ "This project is designed to fill in the gap for people who are trying to hack it on their own but still want a high quality education."
+ ],
+ "blocks": {
+ "top-learn-html-foundations": {
+ "title": "Learn HTML Foundations",
+ "intro": ["A description is to be determined"]
+ },
+ "top-build-a-recipe-project": {
+ "title": "Learn HTML Foundations by Building a Recipe Page",
+ "intro": ["A description is to be determined"]
+ }
+ }
+ },
"misc-text": {
"certification": "{{cert}} 认证",
"browse-other": "浏览我们的其他免费认证\n(我们建议你按顺序学习)",
diff --git a/client/i18n/locales/chinese/motivation.json b/client/i18n/locales/chinese/motivation.json
index d65a69bb268698..43aba58e9b9d34 100644
--- a/client/i18n/locales/chinese/motivation.json
+++ b/client/i18n/locales/chinese/motivation.json
@@ -1,819 +1,856 @@
{
"compliments": [
- "Over the top!",
- "Down the rabbit hole we go!",
- "Bring that rain!",
- "Target acquired.",
- "Feel that need for speed!",
- "You've got guts!",
- "We have liftoff!",
- "To infinity and beyond!",
- "Encore!",
- "Onward!",
- "Challenge destroyed!",
- "It's on like Donkey Kong!",
- "Power level? It's over 9000!",
- "Coding spree!",
- "Code long and prosper.",
- "The crowd goes wild!",
- "One for the Guinness book!",
- "Flawless victory!",
- "Most efficient!",
- "You've got the touch!",
- "You're on fire!",
- "The town is now red!",
- "To the nines!",
- "To the Batmobile!",
- "Pull out all the stops!",
- "You're a wizard, Harry!",
- "You're an all-star!",
- "Way to go!",
- "Outta sight!",
- "You're crushing it!",
- "What sorcery is this?",
- "The world rejoices!",
- "That's the way it's done!",
- "You rock!",
- "Woo-hoo!",
- "We knew you could do it!",
- "Hyper Combo Finish!",
- "Nothing but net!",
- "Boom-shakalaka!",
- "You're a shooting star!",
- "You're unstoppable!",
- "Way cool!",
- "Walk on that sunshine!",
- "Keep on trucking!",
- "Off the charts!",
- "There is no spoon!",
- "Cranked it up to 11!",
- "Escape velocity reached!",
- "You make this look easy!",
- "Passed with flying colors!",
- "You've got this!",
- "Happy, happy, joy, joy!",
- "Tomorrow, the world!",
- "Your powers combined!",
- "It's alive. It's alive!",
- "Sonic Boom!",
- "Here's looking at you, Code!",
- "Ride like the wind!",
- "Legen - wait for it - dary!",
- "Ludicrous Speed! Go!",
- "Most triumphant!",
- "One loop to rule them all!",
- "By the power of Grayskull!",
- "You did it!",
- "Storm that castle!",
- "Face-melting guitar solo!",
- "Checkmate!",
- "Bodacious!",
- "Tubular!",
- "You're outta sight!",
- "Keep calm and code on!",
- "Even sad panda smiles!",
- "Even grumpy cat approves!",
- "Kool Aid Man says oh yeah!",
- "Bullseye!",
- "Far out!",
- "You're heating up!",
- "Standing ovation!",
- "Nice one!",
- "All right!",
- "Hasta la vista, challenge!",
- "Terminated.",
- "Off the hook!",
- "Thundercats, Hooo!",
- "Shiver me timbers!",
- "Raise the roof!",
- "Bingo!",
- "Even Honey Badger cares!",
- "Helm, Warp Nine. Engage!",
- "Gotta code 'em all!",
- "Spool up the FTL drive!",
- "Cool beans!",
- "They're in another castle.",
- "Power UP!",
- "Pikachu chooses you!",
- "I gotta have more cowbell.",
- "Gotta go fast!",
- "Yippee!",
- "Cowabunga!",
- "Moon Prism Power!",
- "Plus Ultra!"
+ "太棒了!",
+ "我们跳进兔子洞!",
+ "雨下吧!",
+ "获取目标。",
+ "体验极速快感!",
+ "你有胆量!",
+ "我们升空了!",
+ "飞向无限!",
+ "再来一次!",
+ "向前进!",
+ "挑战被摧毁!",
+ "重磅如同大金刚!",
+ "战斗力?超过 9000!",
+ "编码狂潮!",
+ "编码不息,繁荣昌盛。",
+ "人群变得疯狂!",
+ "一个吉尼斯世界纪录!",
+ "完胜!",
+ "最高效率!",
+ "你有手感了!",
+ "你正在燃烧!",
+ "满城春色!",
+ "完美!",
+ "上蝙蝠车!",
+ "全力以赴!",
+ "你是个巫师,哈利!",
+ "你是全明星队员!",
+ "干得好!",
+ "棒极了!",
+ "你太出色了!",
+ "这是什么魔法?",
+ "世界欢欣鼓舞!",
+ "难题就是这样搞定的!",
+ "你真棒!",
+ "呜呼!",
+ "我们就知道你能行!",
+ "超级组合终结!",
+ "空心球!",
+ "炸弹-沙卡拉卡!",
+ "你是一颗流星!",
+ "你势不可挡!",
+ "太酷了!",
+ "走在那阳光下!",
+ "坚持下去!",
+ "水平爆表!",
+ "勺子并不存在!",
+ "调到最大音量!",
+ "达到逃逸速度!",
+ "你让这看起来很简单!",
+ "以优异的成绩通过!",
+ "你能行!",
+ "开心,开心,快乐,快乐!",
+ "明天,征服世界!",
+ "你的全部力量!",
+ "它活了。它活了!",
+ "索尼克音爆!",
+ "看着你呢,代码!",
+ "疾驰如风!",
+ "传——奇!",
+ "离谱的速度!出发!",
+ "高奏凯歌!",
+ "用一个循环来统治它们!",
+ "凭借灰壳堡的神力!",
+ "你做到了!",
+ "冲进城堡!",
+ "荡人心魄的吉他独奏!",
+ "完全击败!",
+ "大有胆识!",
+ "厉害!",
+ "你真强啊!",
+ "保持冷静,继续编码!",
+ "即使是悲伤的熊猫也会微笑!",
+ "即使脾气暴躁的猫也同意!",
+ "如此感觉无以伦比。",
+ "正中靶心!",
+ "前卫!",
+ "燃烧吧,小宇宙!",
+ "起立鼓掌!",
+ "不错!",
+ "好啊!",
+ "回见,挑战!",
+ "终结了。",
+ "脱身!",
+ "霹雳猫显神威!",
+ "让我五体投地!",
+ "大显身手!",
+ "答对了!",
+ "连蜜獾都在乎!",
+ "掌舵,第九曲速。启动!",
+ "必须全部编码!",
+ "发动超光速引擎!",
+ "酷豆子!",
+ "她们在另一个城堡里。",
+ "加电!",
+ "皮卡丘选择了你!",
+ "我要再多点牛铃。",
+ "得快点!",
+ "了不起!",
+ "卡瓦邦嘎!",
+ "月亮棱镜能量!",
+ "超越极致!",
+ "米尔豪斯一切都会好起来的!"
],
"motivationalQuotes": [
{
- "quote": "Whatever you are, be a good one.",
- "author": "Abraham Lincoln"
+ "quote": "不管你是谁,做个好人。",
+ "author": "亚伯拉罕·林肯"
},
{
- "quote": "A change in perspective is worth 80 IQ points.",
- "author": "Alan Kay"
+ "quote": "换一个角度看问题值80点智商。",
+ "author": "艾伦·凯"
},
{
- "quote": "The best way to predict the future is to invent it.",
- "author": "Alan Kay"
+ "quote": "预测未来的最好方法是创造未来。",
+ "author": "艾伦·凯"
},
{
- "quote": "The future is not laid out on a track. It is something that we can decide, and to the extent that we do not violate any known laws of the universe, we can probably make it work the way that we want to.",
- "author": "Alan Kay"
+ "quote": "未来不是在轨道上规划的。这是我们可以决定的事情,只要我们不违反任何已知的宇宙法则,我们就可以让它按我们想要的方式运行。",
+ "author": "艾伦·凯"
},
{
- "quote": "We can only see a short distance ahead, but we can see plenty there that needs to be done.",
- "author": "Alan Turing"
+ "quote": "我们只能看到前面很短的距离,但我们可以看到有很多事情需要做。",
+ "author": "艾伦·图灵"
},
{
- "quote": "In the depth of winter, I finally learned that within me there lay an invincible summer.",
- "author": "Albert Camus"
+ "quote": "隆冬时节,我终于明白,我的内心深处有一个不可战胜的夏天。",
+ "author": "阿尔伯特·加缪"
},
{
- "quote": "A person who never made a mistake never tried anything new.",
- "author": "Albert Einstein"
+ "quote": "从不犯错的人从不尝试新事物。",
+ "author": "阿尔伯特·爱因斯坦"
},
{
- "quote": "Creativity is intelligence having fun.",
- "author": "Albert Einstein"
+ "quote": "创造力是智力的乐趣。",
+ "author": "阿尔伯特·爱因斯坦"
},
{
- "quote": "I have no special talents. I am only passionately curious.",
- "author": "Albert Einstein"
+ "quote": "我没有什么特别的才能。我只是非常好奇。",
+ "author": "阿尔伯特·爱因斯坦"
},
{
- "quote": "Life is like riding a bicycle. To keep your balance, you must keep moving.",
- "author": "Albert Einstein"
+ "quote": "生活就像骑自行车。为了保持平衡,你必须继续前进。",
+ "author": "阿尔伯特·爱因斯坦"
},
{
- "quote": "Make everything as simple as possible, but not simpler.",
- "author": "Albert Einstein"
+ "quote": "事情应该力求简单,但不能过于简单。",
+ "author": "阿尔伯特·爱因斯坦"
},
{
- "quote": "Never memorize something that you can look up.",
- "author": "Albert Einstein"
+ "quote": "绝不要去记那些你能够查得到的东西。",
+ "author": "阿尔伯特·爱因斯坦"
},
{
- "quote": "Once we accept our limits, we go beyond them.",
- "author": "Albert Einstein"
+ "quote": "一旦我们接受了自己的极限,我们就超越了它们。",
+ "author": "阿尔伯特·爱因斯坦"
},
{
- "quote": "Play is the highest form of research.",
- "author": "Albert Einstein"
+ "quote": "玩耍是研究的最高形式。",
+ "author": "阿尔伯特·爱因斯坦"
},
{
- "quote": "We cannot solve our problems with the same thinking we used when we created them.",
- "author": "Albert Einstein"
+ "quote": "我们不能用我们创造问题时的思维来解决问题。",
+ "author": "阿尔伯特·爱因斯坦"
},
{
- "quote": "Wisdom is not a product of schooling but of the lifelong attempt to acquire it.",
- "author": "Albert Einstein"
+ "quote": "智慧不是学校教育的产物,而是终身学习的产物。",
+ "author": "阿尔伯特·爱因斯坦"
},
{
- "quote": "Your imagination is your preview of life's coming attractions.",
- "author": "Albert Einstein"
+ "quote": "你的想像是你人生的预览。",
+ "author": "阿尔伯特·爱因斯坦"
},
{
- "quote": "There is only one corner of the universe you can be certain of improving, and that's your own self.",
- "author": "Aldous Huxley"
+ "quote": "宇宙中只有一个角落是你可以切实改进的,那就是你自己。",
+ "author": "奥尔德斯·赫胥黎"
},
{
- "quote": "The most common way people give up their power is by thinking they don't have any.",
- "author": "Alice Walker"
+ "quote": "我感谢我的奋斗,因为没有它,我就不会偶然发现自己的力量。",
+ "author": "亚历克斯·艾尔"
},
{
- "quote": "Follow your inner moonlight. Don't hide the madness.",
- "author": "Allen Ginsberg"
+ "quote": "人们放弃权力最常见的方式是认为自己没有权力。",
+ "author": "艾丽丝·沃克"
},
{
- "quote": "The most difficult thing is the decision to act. The rest is merely tenacity.",
- "author": "Amelia Earhart"
+ "quote": "跟随你内心的月光。别掩饰自己的疯狂。",
+ "author": "艾伦·金斯伯格"
},
{
- "quote": "Life shrinks or expands in proportion with one's courage.",
- "author": "Anaïs Nin"
+ "quote": "最困难的是决定采取行动。剩下的只是坚韧。",
+ "author": "阿梅莉亚·埃尔哈特"
},
{
- "quote": "Weeks of programming can save you hours of planning.",
- "author": "Unknown"
+ "quote": "生命的缩小或扩大与一个人的勇气成正比。",
+ "author": "阿奈斯·宁"
},
{
- "quote": "Quality is not an act, it is a habit.",
- "author": "Aristotle"
+ "quote": "数周的编程可以节省你数小时的计划。",
+ "author": "佚名"
},
{
- "quote": "Start where you are. Use what you have. Do what you can.",
- "author": "Arthur Ashe"
+ "quote": "质量不是一种行为,而是一种习惯。",
+ "author": "亚里士多德"
},
{
- "quote": "Nothing is impossible, the word itself says \"I'm possible\"!",
- "author": "Audrey Hepburn"
+ "quote": "从现在开始。利用你所拥有的。尽你所能。",
+ "author": "亚瑟·阿什"
},
{
- "quote": "Every strike brings me closer to the next home run.",
- "author": "Babe Ruth"
+ "quote": "没有什么是不可能的,连这个词本身都说“不,可能”!",
+ "author": "奥黛丽·赫本"
},
{
- "quote": "By failing to prepare, you are preparing to fail.",
- "author": "Benjamin Franklin"
+ "quote": "每一击都让我离下一个本垒打越来越近。",
+ "author": "贝比·鲁斯"
},
{
- "quote": "Tell me and I forget. Teach me and I remember. Involve me and I learn.",
- "author": "Benjamin Franklin"
+ "quote": "如果你没有做好准备,你就是在准备失败。",
+ "author": "本杰明·富兰克林"
},
{
- "quote": "Well done is better than well said.",
- "author": "Benjamin Franklin"
+ "quote": "告诉我,我会忘记。教我,我会记住。让我参与,我会学习。",
+ "author": "本杰明·富兰克林"
},
{
- "quote": "There are no short cuts to any place worth going.",
- "author": "Beverly Sills"
+ "quote": "说得好不如做得好。",
+ "author": "本杰明·富兰克林"
},
{
- "quote": "Controlling complexity is the essence of computer programming.",
- "author": "Brian Kernighan"
+ "quote": "任何值得去的地方都没有捷径。",
+ "author": "贝弗利·希尔斯"
},
{
- "quote": "I fear not the man who has practiced 10,000 kicks once, but I fear the man who has practiced one kick 10,000 times.",
- "author": "Bruce Lee"
+ "quote": "控制复杂性是计算机编程的本质。",
+ "author": "布莱恩·科尼汉"
},
{
- "quote": "There are far, far better things ahead than any we leave behind.",
- "author": "C.S. Lewis"
+ "quote": "我不怕遇到练习过一万种腿法的对手,但害怕遇到只将一种腿法练习一万次的强敌。",
+ "author": "李小龙"
},
{
- "quote": "We are what we believe we are.",
- "author": "C.S. Lewis"
+ "quote": "比起遗落在过去的,未来还有更加美好的在等待着我们。",
+ "author": "C.S. 路易斯"
},
{
- "quote": "With the possible exception of the equator, everything begins somewhere.",
- "author": "C.S. Lewis"
+ "quote": "我们就是我们所相信的自己。",
+ "author": "C.S. 路易斯"
},
{
- "quote": "You are never too old to set another goal, or to dream a new dream.",
- "author": "C.S. Lewis"
+ "quote": "可能除了赤道以外,一切都从某处开始。",
+ "author": "C.S. 路易斯"
},
{
- "quote": "Somewhere, something incredible is waiting to be known.",
- "author": "Carl Sagan"
+ "quote": "无论年纪多大,你都可以设立新目标或拥有新梦想。",
+ "author": "C.S. 路易斯"
},
{
- "quote": "If you're not making mistakes, then you're not making decisions.",
- "author": "Catherine Cook"
+ "quote": "在某个地方,一些不可思议的事物正在等你去发现。",
+ "author": "卡尔·萨根"
},
{
- "quote": "Find what you love and let it kill you.",
- "author": "Charles Bukowski"
+ "quote": "当你有梦想时,你必须抓住它,永不放弃。",
+ "author": "卡罗尔·伯内特"
},
{
- "quote": "What matters most is how well you walk through the fire.",
- "author": "Charles Bukowski"
+ "quote": "如果你没有犯错误,那么你就没有做决定。",
+ "author": "凯瑟琳·库克"
},
{
- "quote": "It is not the strongest of the species that survive, nor the most intelligent, but the one most responsive to change.",
- "author": "Charles Darwin"
+ "quote": "爱我所爱,至死方休。",
+ "author": "查尔斯·布考斯基"
},
{
- "quote": "Life is 10% what happens to you and 90% how you react to it.",
- "author": "Charles R. Swindoll"
+ "quote": "最重要的是你能否赴汤蹈火。",
+ "author": "查尔斯·布考斯基"
},
{
- "quote": "You will do foolish things, but do them with enthusiasm.",
- "author": "Colette"
+ "quote": "生存下来的不是最强壮的物种,也不是最聪明的物种,而是最能适应变化的物种。",
+ "author": "查尔斯·达尔文"
},
{
- "quote": "It does not matter how slowly you go as long as you do not stop.",
- "author": "Confucius"
+ "quote": "细节不仅是细节,而且决定了设计。",
+ "author": "查尔斯·伊姆斯"
},
{
- "quote": "Real knowledge is to know the extent of one's ignorance.",
- "author": "Confucius"
+ "quote": "创造力不仅仅是与众不同。任何人都可以做到怪诞不经,这很简单。难的是像巴赫那样简单。使简单的,非常简单,这就是创造力。",
+ "author": "查尔斯·明格斯"
},
{
- "quote": "The past cannot be changed. The future is yet in your power.",
- "author": "Confucius"
+ "quote": "生活的 10% 是发生在你身上的事,90% 是你对它的反应。",
+ "author": "查尔斯·R·斯温多尔"
},
{
- "quote": "Looking at code you wrote more than two weeks ago is like looking at code you are seeing for the first time.",
- "author": "Dan Hurvitz"
+ "quote": "你不免会做傻事,但热烈地、衷心地投入做吧。",
+ "author": "科莱特"
},
{
- "quote": "Someday is not a day of the week.",
- "author": "Denise Brennan-Nelson"
+ "quote": "譬如为山,未成一篑,止,吾止也。譬如平地,虽覆一篑,进,吾往也。",
+ "author": "孔子"
},
{
- "quote": "UNIX is simple. It just takes a genius to understand its simplicity.",
- "author": "Dennis Ritchie"
+ "quote": "知之为知之,不知为不知,是知也。",
+ "author": "孔子"
},
{
- "quote": "Computers are good at following instructions, but not at reading your mind.",
- "author": "Donald Knuth"
+ "quote": "往昔不可谏,来者犹可追。",
+ "author": "孔子"
},
{
- "quote": "A good programmer is someone who always looks both ways before crossing a one-way street.",
- "author": "Doug Linder"
+ "quote": "看着自己两个多星期前编写的代码就像第一次看到这代码一样。",
+ "author": "丹·赫维茨"
},
{
- "quote": "Tough times never last, but tough people do.",
- "author": "Dr. Robert Schuller"
+ "quote": "“总有一天”不是一周中的一天。",
+ "author": "丹尼斯·布伦南-纳尔逊"
},
{
- "quote": "If things start happening, don't worry, don't stew, just go right along and you'll start happening too.",
- "author": "Dr. Seuss"
+ "quote": "UNIX很简单。不过只有天才才能理解它的简单性。",
+ "author": "丹尼斯·里奇"
},
{
- "quote": "Do not go gentle into that good night. Rage, rage against the dying of the light.",
- "author": "Dylan Thomas"
+ "quote": "在我看来,要想见彩虹,就得忍受风雨!",
+ "author": "多莉·帕顿"
},
{
- "quote": "The question of whether computers can think is like the question of whether submarines can swim.",
- "author": "E.W. Dijkstra"
+ "quote": "计算机善于遵循指令,但不善于理解你的思维。",
+ "author": "唐纳德·克努特"
},
{
- "quote": "Any code of your own that you haven't looked at for six or more months might as well have been written by someone else.",
- "author": "Eagleson's Law"
+ "quote": "优秀的程序员总是在过单行道之前两边都看一下。",
+ "author": "道格·林德"
},
{
- "quote": "Do one thing every day that scares you.",
- "author": "Eleanor Roosevelt"
+ "quote": "创造力是狂野的头脑和训练有素的眼睛。",
+ "author": "多萝西·帕克"
},
{
- "quote": "With the new day comes new strength and new thoughts.",
- "author": "Eleanor Roosevelt"
+ "quote": "艰苦的时光终将过去,坚强的人们必将苦尽甘来。",
+ "author": "罗伯特·舒勒博士"
},
{
- "quote": "You must do the things you think you cannot do.",
- "author": "Eleanor Roosevelt"
+ "quote": "如果事情开始发生,不要发愁,不要担忧,只要一直走下去,你也会开始发生的。",
+ "author": "苏斯博士"
},
{
- "quote": "Light tomorrow with today.",
- "author": "Elizabeth Barrett Browning"
+ "quote": "不要温和地走进那良夜。怒斥,怒斥光明的消逝。",
+ "author": "狄兰·托马斯"
},
{
- "quote": "Forever is composed of nows.",
- "author": "Emily Dickinson"
+ "quote": "计算机能否思考的问题就像潜艇能否游泳的问题一样。",
+ "author": "E·W·迪科斯彻"
},
{
- "quote": "Computer science education cannot make anybody an expert programmer any more than studying brushes and pigment can make somebody an expert painter.",
- "author": "Eric Raymond"
+ "quote": "自己写的代码,只要有六个月没有看过,就像是别人写的一样。",
+ "author": "伊格尔森定律"
},
{
- "quote": "If you don't risk anything, you risk even more.",
- "author": "Erica Jong"
+ "quote": "每天做一件让你害怕的事。",
+ "author": "埃莉诺·罗斯福"
},
{
- "quote": "The world breaks everyone, and afterward, many are strong at the broken places.",
- "author": "Ernest Hemingway"
+ "quote": "新的一天带来了新的力量和新的思想。",
+ "author": "埃莉诺·罗斯福"
},
{
- "quote": "There is nothing noble in being superior to your fellow man; true nobility is being superior to your former self.",
- "author": "Ernest Hemingway"
+ "quote": "你必须做你自己认为做不到的事。",
+ "author": "埃莉诺·罗斯福"
},
{
- "quote": "Never confuse a single defeat with a final defeat.",
- "author": "F. Scott Fitzgerald"
+ "quote": "用今天照亮明天。",
+ "author": "伊丽莎白·巴雷特·布朗宁"
},
{
- "quote": "I attribute my success to this - I never gave or took any excuse.",
- "author": "Florence Nightingale"
+ "quote": "如果你的梦想没有吓到你,那是因为你梦想得还不够大。",
+ "author": "爱伦·约翰森·希尔丽夫"
},
{
- "quote": "The best revenge is massive success.",
- "author": "Frank Sinatra"
+ "quote": "永远是由现在组成的。",
+ "author": "艾米莉·狄金森"
},
{
- "quote": "The only limit to our realization of tomorrow, will be our doubts of today.",
- "author": "Franklin D. Roosevelt"
+ "quote": "计算机科学教育不能使任何人成为专家程序员,正如学习画笔和颜料无法让人成为绘画专家一样。",
+ "author": "埃里克·雷蒙德"
},
{
- "quote": "Right or wrong, it's very pleasant to break something from time to time.",
- "author": "Fyodor Dostoevsky"
+ "quote": "如果你不冒任何风险,你的风险就更大。",
+ "author": "艾瑞卡·琼"
},
{
- "quote": "The harder I work, the luckier I get.",
- "author": "Gary Player"
+ "quote": "生活总是让我们遍体鳞伤,但到后来,那些受伤的地方会变得更坚强。",
+ "author": "厄内斯特·海明威"
},
{
- "quote": "Giving up is the only sure way to fail.",
- "author": "Gena Showalter"
+ "quote": "优于别人,并不高贵,真正的高贵应该是优于过去的自己。",
+ "author": "厄内斯特·海明威"
},
{
- "quote": "The only truly secure system is one that is powered off, cast in a block of concrete and sealed in a lead-lined room with armed guards.",
- "author": "Gene Spafford"
+ "quote": "永远不要将一次失败与最终失败混淆。",
+ "author": "F. 斯科特·菲茨杰拉德"
},
{
- "quote": "A life spent making mistakes is not only more honorable, but more useful than a life spent doing nothing.",
- "author": "George Bernard Shaw"
+ "quote": "我将我的成功归功于此——我从不找,也不接受任何借口。",
+ "author": "弗洛伦斯·南丁格尔"
},
{
- "quote": "First learn computer science and all the theory. Next develop a programming style. Then forget all that and just hack.",
- "author": "George Carrette"
+ "quote": "最好的报复是巨大的成功。",
+ "author": "弗兰克·西纳特拉"
},
{
- "quote": "Discovering the unexpected is more important than confirming the known.",
- "author": "George Box"
+ "quote": "我们实现明天的唯一限制是我们对今天的怀疑。",
+ "author": "富兰克林·罗斯福"
},
{
- "quote": "We only see what we know.",
- "author": "Goethe"
+ "quote": "不管是对是错,时不时弄坏点东西是一件非常愉快的事情。",
+ "author": "陀思妥耶夫斯基"
},
{
- "quote": "Without hard work, nothing grows but weeds.",
- "author": "Gordon B. Hinckley"
+ "quote": "我越努力,就越幸运。",
+ "author": "盖瑞·普莱尔"
},
{
- "quote": "The function of good software is to make the complex appear to be simple.",
- "author": "Grady Booch"
+ "quote": "放弃是失败的唯一可靠途径。",
+ "author": "吉娜·肖沃尔特"
},
{
- "quote": "When you know that you're capable of dealing with whatever comes, you have the only security the world has to offer.",
- "author": "Harry Browne"
+ "quote": "唯一真正安全的系统是断了电、浇铸在混凝土块中、并密封在有武装警卫的铅衬房间内的系统。",
+ "author": "金·斯帕福德"
},
{
- "quote": "Pain is inevitable. Suffering is optional.",
- "author": "Haruki Murakami"
+ "quote": "一生犯错误不仅比一生无所事事更光荣,而且更有用。",
+ "author": "萧伯纳"
},
{
- "quote": "Optimism is the faith that leads to achievement. Nothing can be done without hope and confidence.",
- "author": "Helen Keller"
+ "quote": "首先学会计算机科学和所有的理论。 然后发展出一个编程风格。之后便要忘掉所有这些,自由地编码。",
+ "author": "乔治·卡雷特"
},
{
- "quote": "The price of anything is the amount of life you exchange for it.",
- "author": "Henry David Thoreau"
+ "quote": "发现意想不到的比确认已知的更重要。",
+ "author": "乔治·博克斯"
},
{
- "quote": "Whether you think you can or think you can't, you're right.",
- "author": "Henry Ford"
+ "quote": "我们只能看到自己所知的。",
+ "author": "歌德"
},
{
- "quote": "The most exciting phrase to hear in science, the one that heralds discoveries, is not 'Eureka!' but 'Now that's funny…'",
- "author": "Isaac Asimov"
+ "quote": "不努力耕耘,只会长出杂草。",
+ "author": "戈登·B·欣克利"
},
{
- "quote": "We are all failures. At least the best of us are.",
- "author": "J.M. Barrie"
+ "quote": "好的软件的功能就是化繁为简。",
+ "author": "格雷迪·布奇"
},
{
- "quote": "You can't wait for inspiration. You have to go after it with a club.",
- "author": "Jack London"
+ "quote": "当你知道自己有能力应对任何事情时,你就拥有了世界所能提供的唯一安全感。",
+ "author": "哈利·布朗"
},
{
- "quote": "Don't wish it were easier, wish you were better.",
- "author": "Jim Rohn"
+ "quote": "痛苦不可避免,但可以选择是否受苦。",
+ "author": "村上春树"
},
{
- "quote": "By seeking and blundering we learn.",
- "author": "Johann Wolfgang von Goethe"
+ "quote": "乐观是导致成就的信念。没有希望和信心,就什么都做不了。",
+ "author": "海伦·凯勒"
},
{
- "quote": "Knowing is not enough; we must apply. Wishing is not enough; we must do.",
- "author": "Johann Wolfgang von Goethe"
+ "quote": "任何东西的价格都等于你用多少生命去换取它。",
+ "author": "亨利·大卫·梭罗"
},
{
- "quote": "We first make our habits, then our habits make us.",
- "author": "John Dryden"
+ "quote": "不管你认为你能还是不能,你都是对的。",
+ "author": "亨利·福特"
},
{
- "quote": "The power of imagination makes us infinite.",
- "author": "John Muir"
+ "quote": "在科学中听到的最令人兴奋的短语,即预示着发现的短语,不是“找到了!” 而是“这很有趣……”",
+ "author": "艾萨克·阿西莫夫"
},
{
- "quote": "May you live every day of your life.",
- "author": "Jonathan Swift"
+ "quote": "你所做的会有影响。你必须决定你想要做出什么样的改变。",
+ "author": "简·古道尔"
},
{
- "quote": "Perseverance is failing 19 times and succeeding the 20th.",
- "author": "Julie Andrews"
+ "quote": "我们都是失败者。至少我们中最好的人是。",
+ "author": "J.M.巴里"
},
{
- "quote": "The work of today is the history of tomorrow, and we are its makers.",
- "author": "Juliette Gordon Low"
+ "quote": "你不能等待灵感。你必须提着木棒去追求它。",
+ "author": "杰克·伦敦"
},
{
- "quote": "If you reveal your secrets to the wind, you should not blame the wind for revealing them to the trees.",
- "author": "Kahlil Gibran"
+ "quote": "不要希望事情更容易,希望你更有能力。",
+ "author": "吉姆·罗恩"
},
{
- "quote": "Optimism is an occupational hazard of programming; feedback is the treatment.",
- "author": "Kent Beck"
+ "quote": "我们通过寻找和犯错误来学习。",
+ "author": "约翰·沃尔夫冈·冯·歌德"
},
{
- "quote": "Opportunity does not knock, it presents itself when you beat down the door.",
- "author": "Kyle Chandler"
+ "quote": "知道是不够的;我们必须应用。希望是不够的;我们必须行动。",
+ "author": "约翰·沃尔夫冈·冯·歌德"
},
{
- "quote": "To iterate is human, to recurse divine.",
- "author": "Peter Deutsch"
+ "quote": "我们先养成习惯,然后习惯造就我们。",
+ "author": "约翰·德莱登"
},
{
- "quote": "A good traveler has no fixed plans and is not intent on arriving.",
- "author": "Lao Tzu"
+ "quote": "想象力使我们无限。",
+ "author": "约翰·缪尔"
},
{
- "quote": "An ant on the move does more than a dozing ox.",
- "author": "Lao Tzu"
+ "quote": "愿你过好每一天。",
+ "author": "乔纳森·斯威夫特"
},
{
- "quote": "Do the difficult things while they are easy and do the great things while they are small. A journey of a thousand miles must begin with a single step.",
- "author": "Lao Tzu"
+ "quote": "坚持就是前 19 次失败,第 20 次成功。",
+ "author": "朱莉·安德鲁斯"
},
{
- "quote": "That's the thing about people who think they hate computers. What they really hate is lousy programmers.",
- "author": "Larry Niven"
+ "quote": "今天的工作就是明天的历史,我们是它的创造者。",
+ "author": "朱丽叶·戈登·洛"
},
{
- "quote": "It had long since come to my attention that people of accomplishment rarely sat back and let things happen to them. They went out and happened to things.",
- "author": "Leonardo da Vinci"
+ "quote": "如果你向风泄露了你的秘密,你不应该责怪风将它们泄露给树木。",
+ "author": "纪伯伦"
},
{
- "quote": "If you're any good at all, you know you can be better.",
- "author": "Lindsay Buckingham"
+ "quote": "乐观是编程的职业病;反馈就是治疗。",
+ "author": "肯特·贝克"
},
{
- "quote": "If people never did silly things, nothing intelligent would ever get done.",
- "author": "Ludwig Wittgenstein"
+ "quote": "机会不会敲门,它会在你敲门的时候出现。",
+ "author": "凯尔·钱德勒"
},
{
- "quote": "You only live once, but if you do it right, once is enough.",
- "author": "Mae West"
+ "quote": "迭代的是人,递归的是神。",
+ "author": "彼得·多伊奇"
},
{
- "quote": "Live as if you were to die tomorrow. Learn as if you were to live forever.",
- "author": "Mahatma Gandhi"
+ "quote": "善行无辙迹,善言无瑕谪。",
+ "author": "老子"
},
{
- "quote": "Strength does not come from physical capacity. It comes from an indomitable will.",
- "author": "Mahatma Gandhi"
+ "quote": "合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下。",
+ "author": "老子"
},
{
- "quote": "One person's 'paranoia' is another person's 'engineering redundancy'.",
- "author": "Marcus J. Ranum"
+ "quote": "那些认为自己讨厌电脑的人就是这样。他们真正讨厌的是糟糕的程序员。",
+ "author": "拉里·尼文"
},
{
- "quote": "Nothing in life is to be feared, it is only to be understood. Now is the time to understand more, so that we may fear less.",
- "author": "Marie Curie"
+ "quote": "我早就发现,成功的人很少坐以待毙,让事情发生在他们身上。他们出去主动去做事。",
+ "author": "达芬奇"
},
{
- "quote": "If you have everything under control, you're not moving fast enough.",
- "author": "Mario Andretti"
+ "quote": "如果你有一点才能,你就会知道你还可以做得更好。",
+ "author": "林赛·白金汉"
},
{
- "quote": "Education: the path from cocky ignorance to miserable uncertainty.",
- "author": "Mark Twain"
+ "quote": "如果人们从不做傻事,就什么都不会做得聪明。",
+ "author": "路德维希·维特根斯坦"
},
{
- "quote": "It ain't what you don't know that gets you into trouble. It's what you know for sure that just ain't so.",
- "author": "Mark Twain"
+ "quote": "人只活一次,但若活得其所一次已足够。",
+ "author": "梅·韦斯特"
},
{
- "quote": "The secret of getting ahead is getting started.",
- "author": "Mark Twain"
+ "quote": "像明天就要死一样生活,像永远活着一样学习。",
+ "author": "圣雄甘地"
},
{
- "quote": "The two most important days in your life are the day you are born and the day you find out why.",
- "author": "Mark Twain"
+ "quote": "力量不是来自身体能力。它来自不屈不挠的意志。",
+ "author": "圣雄甘地"
},
{
- "quote": "Twenty years from now you will be more disappointed by the things that you didn't do than by the ones you did do. So throw off the bowlines. Sail away from the safe harbor. Catch the trade winds in your sails.",
- "author": "Mark Twain"
+ "quote": "一个人的“偏执狂”是另一个人的“工程冗余”。",
+ "author": "马库斯·拉纳姆"
},
{
- "quote": "Any fool can write code that a computer can understand. Good programmers write code that humans can understand.",
- "author": "Martin Fowler"
+ "quote": "生活中没有什么可怕的,只有需要理解的。现在是时候多去理解,这样我们就会少一些恐惧。",
+ "author": "玛丽·居里"
},
{
- "quote": "I know, somehow, that only when it is dark enough can you see the stars.",
- "author": "Martin Luther King Jr."
+ "quote": "如果一切都在你的掌控之中,那么你的行动还不够快。",
+ "author": "马里奥·安德雷蒂"
},
{
- "quote": "It is never too late to be what you might have been.",
- "author": "Mary Anne Evans"
+ "quote": "教育:从自大的无知到悲惨的不确定性的道路。",
+ "author": "马克·吐温"
},
{
- "quote": "Nothing will work unless you do.",
- "author": "Maya Angelou"
+ "quote": "让你陷入麻烦的不是你不知道的东西,而是你确信的、其实并不是真的东西。",
+ "author": "马克·吐温"
},
{
- "quote": "We delight in the beauty of the butterfly, but rarely admit the changes it has gone through to achieve that beauty.",
- "author": "Maya Angelou"
+ "quote": "取得成功的秘诀就是开始。",
+ "author": "马克·吐温"
},
{
- "quote": "We may encounter many defeats, but we must not be defeated.",
- "author": "Maya Angelou"
+ "quote": "你生命中最重要的两天是你出生的那一天和你找到意义的那一天。",
+ "author": "马克·吐温"
},
{
- "quote": "Everybody has talent, but ability takes hard work.",
- "author": "Michael Jordan"
+ "quote": "二十年后,你会因自己没做的事情而更加失望,而不是做过的事情。所以,请解开绳索,驶离安全的港湾,扬帆起航吧。",
+ "author": "马克·吐温"
},
{
- "quote": "I've missed more than 9,000 shots during my career. I've lost almost 300 games. 26 times, I've been trusted to take the game winning shot and missed. I've failed over and over and over again in my life. And that is why I succeed.",
- "author": "Michael Jordan"
+ "quote": "任何傻瓜都可以编写计算机可以理解的代码。优秀的程序员编写人类可以理解的代码。",
+ "author": "马丁·福勒"
},
{
- "quote": "Impossible is just a big word thrown around by small men who find it easier to live in the world they've been given than to explore the power they have to change it. Impossible is not a fact. It's an opinion. Impossible is not a declaration. It's a dare. Impossible is potential. Impossible is temporary. Impossible is nothing.",
- "author": "Muhammad Ali"
+ "quote": "我知道,不知何故,只有当天足够黑时,你才能看到星星。",
+ "author": "马丁·路德·金"
},
{
- "quote": "A winner is a dreamer who never gives up.",
- "author": "Nelson Mandela"
+ "quote": "永远不会太晚去成为你可能成为的人。",
+ "author": "玛丽·安妮·埃文斯"
},
{
- "quote": "It always seems impossible until it's done.",
- "author": "Nelson Mandela"
+ "quote": "除非你行动起来,否则什么都不会改变。",
+ "author": "玛雅·安杰洛"
},
{
- "quote": "Failure will never overtake me if my determination to succeed is strong enough.",
- "author": "Og Mandino"
+ "quote": "你无法用尽创造力。使用得越多,就会有越多。",
+ "author": "玛雅·安杰洛"
},
{
- "quote": "I am not young enough to know everything.",
- "author": "Oscar Wilde"
+ "quote": "我们喜欢蝴蝶的美丽,但很少承认它为实现这种美丽所经历的变化。",
+ "author": "玛雅·安杰洛"
},
{
- "quote": "There is only one thing that makes a dream impossible to achieve: the fear of failure.",
- "author": "Paulo Coelho"
+ "quote": "我们可能会遇到很多失败,但我们绝不能被击败。",
+ "author": "玛雅·安杰洛"
},
{
- "quote": "Never go to bed mad. Stay up and fight.",
- "author": "Phyllis Diller"
+ "quote": "每个人都有天赋,但能力需要努力。",
+ "author": "迈克尔·乔丹"
},
{
- "quote": "You can't cross the sea merely by standing and staring at the water.",
- "author": "Rabindranath Tagore"
+ "quote": "在我的职业生涯中,我错过了 9000 多次投篮。我输掉了近 300 场比赛。26 次,我被信任去投决胜一投,但都没有命中。我一次又一次地失败。但正因如此,我才获得了成功。",
+ "author": "迈克尔·乔丹"
},
{
- "quote": "The only person you are destined to become is the person you decide to be.",
- "author": "Ralph Waldo Emerson"
+ "quote": "“不可能”只是小人物们轻易抛出的大词,他们宁愿留在自己被赋予的世界里,也不愿探索自己改变它的力量。“不可能”不是事实,而是意见。“不可能”不是宣言,而是挑战。“不可能”是潜力。“不可能”是暂时的。“不可能”什么也不是。",
+ "author": "穆罕默德·阿里"
},
{
- "quote": "What you do speaks so loudly that I cannot hear what you say.",
- "author": "Ralph Waldo Emerson"
+ "quote": "胜利者是永不放弃的梦想家。",
+ "author": "纳尔逊·曼德拉"
},
{
- "quote": "People who are crazy enough to think they can change the world, are the ones who do.",
- "author": "Rob Siltanen"
+ "quote": "看起来总是不可能,直到它被做到。",
+ "author": "纳尔逊·曼德拉"
},
{
- "quote": "The best way out is always through.",
- "author": "Robert Frost"
+ "quote": "如果我成功的决心足够坚定,失败永远不会压倒我。",
+ "author": "奥格·曼狄诺"
},
{
- "quote": "Today's accomplishments were yesterday's impossibilities.",
- "author": "Robert H. Schuller"
+ "quote": "我还不够年轻,不可能了解所有的事情。",
+ "author": "奥斯卡·王尔德"
},
{
- "quote": "Don't be satisfied with stories, how things have gone with others. Unfold your own myth.",
- "author": "Rumi"
+ "quote": "只有一件事使梦想无法实现:对失败的恐惧。",
+ "author": "保罗·柯艾略"
},
{
- "quote": "Forget safety. Live where you fear to live. Destroy your reputation. Be notorious.",
- "author": "Rumi"
+ "quote": "光是站着看水是无法渡海的。",
+ "author": "罗宾德拉纳特·泰戈尔"
},
{
- "quote": "Sell your cleverness and buy bewilderment.",
- "author": "Rumi"
+ "quote": "你注定要成为的唯一的人,就是你决定成为的人。",
+ "author": "拉尔夫·沃尔多·爱默生"
},
{
- "quote": "The cure for pain is in the pain.",
- "author": "Rumi"
+ "quote": "你的所作所为声音很大,我听不见你在说什么。",
+ "author": "拉尔夫·沃尔多·爱默生"
},
{
- "quote": "Have no fear of perfection - you'll never reach it.",
- "author": "Salvador Dalí"
+ "quote": "那些足够疯狂以为自己可以改变世界的人,才是真正改变世界的人。",
+ "author": "罗伯·西塔宁"
},
{
- "quote": "Don't watch the clock. Do what it does. Keep going.",
- "author": "Sam Levenson"
+ "quote": "最好的出路是有始有终。",
+ "author": "罗伯特·弗罗斯特"
},
{
- "quote": "Ever Tried. Ever failed. No matter. Try again. Fail again. Fail better.",
- "author": "Samuel Beckett"
+ "quote": "今天的成就是昨天的不可能。",
+ "author": "罗伯特·舒乐"
},
{
- "quote": "The more you know, the more you realize you know nothing.",
- "author": "Socrates"
+ "quote": "不要满足于故事,不要满足于别人的经历。揭开你自己的神话。",
+ "author": "鲁米"
},
{
- "quote": "The greatest enemy of knowledge is not ignorance, it is the illusion of knowledge.",
- "author": "Stephen Hawking"
+ "quote": "忘掉安全感,到你所害怕的地方去生活。摧毁你的名声,做一个声名狼藉的人。",
+ "author": "鲁米"
},
{
- "quote": "The universe doesn't allow perfection.",
- "author": "Stephen Hawking"
+ "quote": "卖掉你的聪明,买下困惑。",
+ "author": "鲁米"
},
{
- "quote": "Whether you want to uncover the secrets of the universe, or you want to pursue a career in the 21st century, basic computer programming is an essential skill to learn.",
- "author": "Stephen Hawking"
+ "quote": "治疗疼痛的方法是在疼痛中。",
+ "author": "鲁米"
},
{
- "quote": "The scariest moment is always just before you start.",
- "author": "Stephen King"
+ "quote": "不要害怕完美——你永远达不到完美。",
+ "author": "萨尔瓦多·达利"
},
{
- "quote": "You can, you should, and if you're brave enough to start, you will.",
- "author": "Stephen King"
+ "quote": "不要看时钟。做它做的事情。继续前进。",
+ "author": "山姆·李文生"
},
{
- "quote": "Arise, Awake and Stop not until the goal is reached.",
- "author": "Swami Vivekananda"
+ "quote": "曾经尝试过。曾经失败过。没关系。再尝试一次。再失败一次。做得更好。",
+ "author": "塞缪尔·贝克特"
},
{
- "quote": "It is said that your life flashes before your eyes just before you die. That is true, it's called Life.",
- "author": "Terry Pratchett"
+ "quote": "你知道的越多,你就越发现你什么都不知道。",
+ "author": "苏格拉底"
},
{
- "quote": "Believe you can and you're halfway there.",
- "author": "Theodore Roosevelt"
+ "quote": "知识最大的敌人不是无知,而是知识的幻觉。",
+ "author": "史蒂芬·霍金"
},
{
- "quote": "I have not failed. I've just found 10,000 ways that won't work.",
- "author": "Thomas A. Edison"
+ "quote": "宇宙不允许完美。",
+ "author": "史蒂芬·霍金"
},
{
- "quote": "Our greatest weakness lies in giving up. The most certain way to succeed is always to try just one more time.",
- "author": "Thomas A. Edison"
+ "quote": "无论你是想揭开宇宙的秘密,还是想在 21 世纪谋求职业,基础计算机编程是必学的技能。",
+ "author": "史蒂芬·霍金"
},
{
- "quote": "The harder the conflict, the more glorious the triumph.",
- "author": "Thomas Paine"
+ "quote": "最可怕的时刻总是在你开始之前。",
+ "author": "史蒂芬.金"
},
{
- "quote": "The Web as I envisaged it, we have not seen it yet. The future is still so much bigger than the past.",
- "author": "Tim Berners-Lee"
+ "quote": "你可以,你应该,如果你有足够的勇气开始,你会的。",
+ "author": "史蒂芬.金"
},
{
- "quote": "Failure is the condiment that gives success its flavor.",
- "author": "Truman Capote"
+ "quote": "起床,醒来,直到达到目标才停下来。",
+ "author": "斯瓦米·维韦卡南达"
},
{
- "quote": "Those who says it cannot be done should not interrupt the person doing it.",
- "author": "Unknown"
+ "quote": "据说,就在你死之前,你的生命在你眼前闪过。没错,这就是所谓的生活。",
+ "author": "泰瑞·普莱契"
},
{
- "quote": "Even if you fall on your face, you're still moving forward.",
- "author": "Victor Kiam"
+ "quote": "相信你可以,你就成功了一半。",
+ "author": "西奥多·罗斯福"
},
{
- "quote": "It's not whether you get knocked down, it's whether you get up.",
- "author": "Vince Lombardi"
+ "quote": "我没有失败。我只是找到了一万种行不通的方法。",
+ "author": "爱迪生"
},
{
- "quote": "I dream my painting and I paint my dream.",
- "author": "Vincent van Gogh"
+ "quote": "我们最大的弱点在于放弃。最确定的成功方法永远是再试一次。",
+ "author": "爱迪生"
},
{
- "quote": "Let us cultivate our garden.",
- "author": "Voltaire"
+ "quote": "冲突越激烈,胜利就越光荣。",
+ "author": "托马斯·潘恩"
},
{
- "quote": "Aim for the moon. If you miss, you may hit a star.",
- "author": "W. Clement Stone"
+ "quote": "我所设想的网络,我们还没有看到。未来仍然比过去要大得多。",
+ "author": "蒂姆·伯纳斯-李"
},
{
- "quote": "The way to get started is to quit talking and begin doing.",
- "author": "Walt Disney"
+ "quote": "失败是给成功增添风味的调味品。",
+ "author": "杜鲁门·卡波特"
},
{
- "quote": "You miss 100% of the shots you don't take.",
- "author": "Wayne Gretzky"
+ "quote": "那些说这是不可能的人,不应该打断正在做这件事的人。",
+ "author": "佚名"
},
{
- "quote": "Don't let yesterday take up too much of today.",
- "author": "Will Rogers"
+ "quote": "用不同的眼光看待平常的事物。",
+ "author": "维科·马吉斯泰蒂"
},
{
- "quote": "Even if you're on the right track, you'll get run over if you just sit there.",
- "author": "Will Rogers"
+ "quote": "即使你摔倒在地,你仍然在前进。",
+ "author": "维克托·基亚姆"
},
{
- "quote": "Do not wait to strike till the iron is hot; but make it hot by striking.",
- "author": "William Butler Yeats"
+ "quote": "重要的不是你是否被击倒,而是你是否爬起来。",
+ "author": "文斯·隆巴迪"
},
{
- "quote": "You cannot swim for new horizons until you have courage to lose sight of the shore.",
- "author": "William Faulkner"
+ "quote": "我梦想我的画,我画我的梦。",
+ "author": "文森特·梵高"
},
{
- "quote": "Be not afraid of greatness. Some are born great, some achieve greatness, and others have greatness thrust upon them.",
- "author": "William Shakespeare"
+ "quote": "伟大的事情是由一系列小事情汇聚而成的。",
+ "author": "文森特·梵高"
},
{
- "quote": "We know what we are, but not what we may be.",
- "author": "William Shakespeare"
+ "quote": "让我们耕种我们的花园。",
+ "author": "伏尔泰"
},
{
- "quote": "In theory there is no difference between theory and practice. In practice there is.",
- "author": "Yogi Berra"
+ "quote": "瞄准月亮。如果你错失目标,你可能会击中一颗恒星。",
+ "author": "克莱门特·斯通"
},
{
- "quote": "You can see a lot by just looking.",
- "author": "Yogi Berra"
+ "quote": "开始的方法是停止说话,开始行动。",
+ "author": "沃尔特·迪斯尼"
},
{
- "quote": "There is no elevator to success, you have to take the stairs.",
- "author": "Zig Ziglar"
+ "quote": "你不尝试的话,就有 100% 的机会失败。",
+ "author": "韦恩·格雷茨基"
},
{
- "quote": "You don't have to be great to start, but you have to start to be great.",
- "author": "Zig Ziglar"
+ "quote": "不要让昨天占据太多的今天。",
+ "author": "威尔·罗杰斯"
+ },
+ {
+ "quote": "即使你是在正确的路上,如果你只是坐在那里,你也会被撞倒。",
+ "author": "威尔·罗杰斯"
+ },
+ {
+ "quote": "不要等铁热了再打;要用敲打使它变热。",
+ "author": "威廉·巴特勒·叶芝"
+ },
+ {
+ "quote": "除非你有勇气离开海岸,否则你无法游向新的地平线。",
+ "author": "威廉·福克纳"
+ },
+ {
+ "quote": "不要害怕伟大。 有些人天生伟大,有些人成就伟大,而另一些人则被推向伟大。",
+ "author": "威廉·莎士比亚"
+ },
+ {
+ "quote": "我们知道我们是什么,但不知道我们可能成为什么。",
+ "author": "威廉·莎士比亚"
+ },
+ {
+ "quote": "从理论上讲,理论和实践之间没有区别。在实践中是有的。",
+ "author": "约吉·贝拉"
+ },
+ {
+ "quote": "通过看,你就可以觉察到很多东西。",
+ "author": "约吉·贝拉"
+ },
+ {
+ "quote": "成功没有电梯,你必须走楼梯。",
+ "author": "齐格·齐格勒"
+ },
+ {
+ "quote": "你不一定要很伟大才能开始,但你必须开始才能变得伟大。",
+ "author": "齐格·齐格勒"
}
]
}
diff --git a/client/i18n/locales/chinese/translations.json b/client/i18n/locales/chinese/translations.json
index bd6710bf1320bb..0db1f14dd66d0c 100644
--- a/client/i18n/locales/chinese/translations.json
+++ b/client/i18n/locales/chinese/translations.json
@@ -11,11 +11,12 @@
"view": "查看",
"view-code": "查看代码",
"view-project": "查看项目",
+ "view-cert-title": "View {{certTitle}}",
"show-cert": "显示认证",
"claim-cert": "申请认证",
"save-progress": "保存进度",
- "accepted-honesty": "你已接受我们的《学术诚信条例》",
- "agree": "同意",
+ "accepted-honesty": "You have agreed to our Academic Honesty Policy.",
+ "agree-honesty": "I agree to freeCodeCamp's Academic Honesty Policy.",
"save-portfolio": "保存这个作品集项目",
"remove-portfolio": "移除这个作品集项目",
"add-portfolio": "增加一个新的作品集项目",
@@ -52,7 +53,7 @@
"check-code": "检查您的代码 (Ctrl + Enter)",
"check-code-2": "检查你的代码",
"reset": "重置",
- "reset-code": "重置所有代码",
+ "reset-step": "Reset This Step",
"help": "帮助",
"get-help": "获得帮助",
"watch-video": "观看视频",
@@ -157,7 +158,8 @@
"honesty": "学术诚信条例",
"internet": "你在各平台的账号",
"portfolio": "作品集设置",
- "privacy": "隐私设置"
+ "privacy": "隐私设置",
+ "personal-info": "Personal Information"
},
"danger": {
"heading": "危险区域",
@@ -222,16 +224,15 @@
"total-points_plural": "{{count}} 总分",
"points": "{{date}} 获得 {{count}} 分",
"points_plural": "{{date}} 获得 {{count}} 分",
- "screen-shot": "{{title}} 截图",
"page-number": "第 {{pageNumber}} 页,共 {{totalPages}} 页"
},
"footer": {
- "tax-exempt-status": "freeCodeCamp 是捐助者支持的 501(c)(3) 条款下具有免税资格的非营利性组织(税号:82-0779546)。",
+ "tax-exempt-status": "freeCodeCamp 是捐助者支持的 501(c)(3) 条款下具有免税资格的慈善组织(税号:82-0779546)。",
"mission-statement": "我们的使命:帮助人们免费学习编程。我们通过创建成千上万的视频、文章和交互式编程课程——所有内容向公众免费开放——来实现这一目标。学员在世界各地自发成立数千个 freeCodeCamp 学习小组。",
"donation-initiatives": "所有给 freeCodeCamp 的捐款都将用于我们的教育项目,购买服务器和其他服务,以及聘用员工。",
"donate-text": "你可以<1>在此处进行免税捐赠1>。",
"trending-guides": "精选文章",
- "our-nonprofit": "关于我们",
+ "our-nonprofit": "我们的慈善组织",
"links": {
"about": "简介",
"alumni": "校友网络",
@@ -249,6 +250,7 @@
},
"learn": {
"heading": "欢迎学习 freeCodeCamp 的课程。",
+ "skip-to-content": "Skip to content",
"welcome-1": "欢迎回来,{{name}}。",
"welcome-2": "欢迎来到 freeCodeCamp.org",
"start-at-beginning": "如果你刚开始学习编程,我们建议你<0>从头开始0>。",
@@ -264,7 +266,7 @@
"p8": "这套课程需要你进行数千个小时的编程练习。",
"p9": "如果你想学习更多数学和计算机科学理论,<0>freeCodeCamp 的 \n YouTube channel0> 还有数千个小时的视频课程。",
"p10": "如果你想获得开发者工作或者成为自由职业开发者找到客户,那么除了编程技能,你还需要搭建自己的社交网络,打造自己作为开发者的影响力。",
- "p11": "You can do this on LinkedIn and GitHub, and also on <0>the freeCodeCamp forum0>.",
+ "p11": "你还可以在 LinkedIn、Twitter、GitHub 和 <0>freeCodeCamp 论坛0> 上做到这一点。",
"p12": "编程愉快!"
},
"upcoming-lessons": "即将上线的课程",
@@ -272,6 +274,9 @@
"add-subtitles": "帮助我们完善或添加字幕",
"wrong-answer": "抱歉,这个答案不正确。再试一次?",
"check-answer": "点击下方按钮,查看你的答案。",
+ "assignment-not-complete": "Please finish the assignments",
+ "assignments": "Assignments",
+ "question": "Question",
"solution-link": "解决方案链接",
"github-link": "GitHub 链接",
"submit-and-go": "提交并访问下一个挑战",
@@ -284,7 +289,7 @@
"sign-in-save": "登录以保存你的学习进度",
"download-solution": "下载我的解决方案",
"percent-complete": "完成 {{percent}}%",
- "project-complete": "Completed {{completedChallengesInBlock}} of {{totalChallengesInBlock}} certification projects",
+ "project-complete": "已完成 {{totalChallengesInBlock}} 认证项目中的 {{completedChallengesInBlock}}",
"tried-rsa": "如果你已经尝试了 <0>Read-Search-Ask(阅读-搜索-提问)0>方法,那么你可以在 freeCodeCamp 论坛请求帮助。",
"rsa": "阅读,搜索,提问",
"rsa-forum": "在发布新帖子之前 ,请确认你的问题是否<0>已经在论坛上被回答过0>。",
@@ -297,7 +302,6 @@
"certs": "{{title}} 认证"
},
"editor-tabs": {
- "info": "信息",
"code": "编程",
"tests": "测试",
"restart": "重启",
@@ -307,6 +311,10 @@
"notes": "注意",
"preview": "预览"
},
+ "editor-alerts": {
+ "tab-trapped": "按下选项卡将插入选项卡字符",
+ "tab-free": "按下选项卡将焦点移动到下一个焦点元素"
+ },
"help-translate": "我们仍然在翻译以下证书。",
"help-translate-link": "帮助我们翻译。",
"project-preview-title": "下面是你将构建的项目的预览",
@@ -326,16 +334,16 @@
"sorry-hang-in-there": "抱歉,你的代码未通过,坚持一下。",
"sorry-dont-giveup": "抱歉,你的代码未通过,不要放弃。",
"challenges-completed": "已完成 {{completedCount}}/{{totalChallenges}}",
- "season-greetings-fcc": "Season's Greetings from the freeCodeCamp community 🎉",
- "if-getting-value": "If you're getting a lot out of freeCodeCamp, now is a great time to donate to support our nonprofit's mission.",
- "building-a-university": "We're Building a Free Computer Science University Degree Program",
- "if-help-university": "We've already made a ton of progress. Support our charity with the long road ahead."
+ "season-greetings-fcc": "来自 freeCodeCamp 社区的季节问候 🎉",
+ "if-getting-value": "如果你从 freeCodeCamp 中获益良多,可以捐款支持我们的慈善组织的使命。",
+ "building-a-university": "我们正在创建一个免费计算机科学大学学位课程",
+ "if-help-university": "我们已取得了重大进展。请支持我们的慈善组织完成这项长期事业。"
},
"donate": {
- "title": "支持我们的非营利组织",
+ "title": "支持我们的慈善组织",
"processing": "我们正在处理你的捐款。",
"redirecting": "重新引导中...",
- "thanks": "谢谢捐款",
+ "thanks": "Thanks for donating",
"thank-you": "谢谢你成为我们的支持者。",
"additional": "你可以使用这个链接 <0>{{url}}0> 额外进行一次性捐款:",
"help-more": "帮助我们做更多",
@@ -354,11 +362,10 @@
"your-donation": "你的 ${{usd}} 捐款将帮助世界各地的人们学习 {{hours}} 小时。",
"your-donation-2": "你的 ${{usd}} 捐款每月将帮助世界各地的人们学习 {{hours}} 小时。",
"your-donation-3": "你的 ${{usd}} 捐款每年将帮助世界各地的人们学习 {{hours}} 小时。",
- "become-supporter": "Become a Supporter",
- "duration": "成为我们非营利组织的一次性支持者",
- "duration-2": "成为我们非营利组织的每月定期支持者",
- "duration-3": "成为我们非营利组织的每年定期支持者",
- "duration-4": "成为我们非营利组织的支持者",
+ "become-supporter": "成为支持者",
+ "duration": "成为我们的慈善组织的一次性支持者",
+ "duration-2": "成为我们的慈善组织的每月定期支持者",
+ "duration-4": "成为我们的慈善组织的支持者",
"nicely-done": "很棒,你已完成 {{block}}。",
"credit-card": "信用卡",
"credit-card-2": "或者使用信用卡捐款:",
@@ -372,25 +379,25 @@
"email-receipt": "邮箱(我们将把捐款税务收据发送给你):",
"need-help": "需要我们帮助处理你的当前或之前的捐款?",
"forward-receipt": "将你的捐款收据副本发送至 donors@freecodecamp.org,告诉我们你需要什么帮助。",
- "efficiency": "freeCodeCamp 是一个高效率的专注教育的非营利组织。",
+ "efficiency": "freeCodeCamp 是一个高效率的教育慈善组织。",
"why-donate-1": "通过给 freeCodeCamp 捐款,你帮助人们学习新技能以供养家庭。",
"why-donate-2": "你也帮助我们创建新的学习资源,你可以利用这些资源拓展自己的技术能力。",
"bigger-donation": "给我们额度更大的一次性捐款,或寄一张支票,或通过其他方式给我们捐款?",
- "other-ways": "有许多<0>其他方式可以支持我们的非营利组织践行使命0>.",
+ "other-ways": "有许多<0>其他方式可以支持我们的慈善组织践行使命0>.",
"failed-pay": "呃,你的转账似乎没有成功,再试一次好吗?",
"try-again": "请重试。",
"card-number": "你的卡号:",
"expiration": "到期日:",
"secure-donation": "安全捐款",
"faq": "常见问题",
- "only-you": "只有你可以看到此消息。祝贺你获得这项认证。获得认证不是一件容易的事情,运营 freeCodeCamp 也不容易,而且需要花费很多。请帮助我们更好地帮助你和世界各地的许多其他人。今天就为我们的非营利组织提供免税捐款,支持我们。",
+ "only-you": "只有你可以看到此消息。祝贺你获得这项认证。获得认证不是一件容易的事情,运营 freeCodeCamp 也不容易,而且需要花费很多。请帮助我们更好地帮助你和世界各地的许多其他人。今天就为我们的慈善组织提供免税捐款,支持我们。",
"get-help": "我如何利用我的捐款得到帮助?",
"how-transparent": "freeCodeCamp.org 的透明度如何?",
"very-transparent": "我们甚至有一个来自 GuideStar.org 的白金透明度评级。",
"download-irs": "你可以<0>在此处下载我们的国税局认定函0>。",
"download-990": "你可以<0>在此处下载我们最新的 990 (年度税务报告)0>。",
"how-efficient": "freeCodeCamp 的效率如何?",
- "fcc-budget": "freeCodeCamp 的预算比大多数非营利组织少得多。我们还没有引入专业募捐者,而是 Quincy 自己处理一切相关事务。",
+ "fcc-budget": "freeCodeCamp 的预算比大多数慈善组织少得多。我们还没有引入专业募捐者,而是 Quincy 自己处理一切相关事务。",
"help-millions": "然而,在每年仅有 10 万美元的预算中,我们能够帮助数百万人。",
"how-one-time": "我如何进行一次性捐款?",
"one-time": "如果你喜欢一次性捐款,你可以在有闲钱时支持 freeCodeCamp 的事业。你可以使用<0>此链接,通过 PayPal 捐你认为合适的金额0>。",
@@ -400,7 +407,7 @@
"can-check": "我可以邮寄实物支票吗?",
"yes-check": "是的,我们欢迎支票。你可以将其邮寄给我们:",
"how-matching-gift": "我如何从我的雇主那里设置匹配的礼物,或者工资扣除?",
- "employers-vary": "这因雇主而异,而我们的非营利组织已经被列入许多大型捐赠匹配数据库。",
+ "employers-vary": "这因雇主而异,而我们的慈善组织已经被列入许多大型捐赠匹配数据库。",
"some-volunteer": "有些人能够为 freeCodeCamp 提供志愿服务,他们的雇主通过每小时志愿服务捐赠一个固定的金额进行匹配。其他雇主会对捐赠者的任何捐赠进行匹配,最高可达某一数额。",
"help-matching-gift": "如你需要帮助,请直接给 Quincy 发送电子邮件:quincy@freecodecamp.org",
"how-endowment": "如何为 freeCodeCamp.org 设置捐赠礼物?",
@@ -411,13 +418,13 @@
"thank-wikimedia": "我们要感谢维基百科基金会为我们提供这种正式文书。",
"legacy-gift-questions": "如果你对此过程有任何疑问,请给 Quincy 发送电子邮件到 Quincy@freecodecamp.org。",
"how-stock": "如何将股票捐赠给 freeCodeCamp.org?",
- "welcome-stock": "我们欢迎你的股票捐赠。请直接为 Quincy 发送电子邮件到 quincy@freecodecamp.org,他可以帮助你做到这一点,并分享我们的非营利经纪业务账户的详细信息。",
+ "welcome-stock": "我们欢迎你的股票捐赠。请直接给 Quincy 发送电子邮件到 quincy@freecodecamp.org,他可以帮助你,并分享我们的慈善组织的经纪账户的详细信息。",
"how-receipt": "我能够收到捐赠收据以从我的税款中扣除我的捐赠吗?",
"just-forward": "可以,只需将你交易的收据转发到 donors@freecodecamp.org,告诉我们你想要一个收据以及你的使用场景,我们将发给你一个收据。",
"how-update": "我设置了每月捐款,但我需要更新或暂停每月的重复。我如何做?",
"take-care-of-this": "只需转发你的每月捐款记录中的一个记录给 donors@freecodecamp.org, 并告诉我们你要做什么。我们会为你处理这个问题,并向你发送确认。",
"anything-else": "还有什么关于为 freeCodeCamp.org 捐赠可以了解的吗?",
- "other-support": "如果你想要以其他方式支持我们的非营利工作并且它的渠道没有在此列出, 或者如果你有任何问题,请给 Quincy 发送电子邮件到 quincy@freecodecamp.org。"
+ "other-support": "如果你想要通过此处未列出的其他方式支持我们的慈善组织和它的使命,或者如果你有任何问题,请给 Quincy 发送电子邮件到 quincy@freecodecamp.org。"
},
"report": {
"sign-in": "你需要先登录才能举报用户",
@@ -460,7 +467,8 @@
"iframe-preview": "{{title}} 预览",
"iframe-alert": "通常,此链接会将你带到另一个网站!一切正常,这个链接指向:{{externalLink}}。",
"iframe-form-submit-alert": "通常这个表单将被提交!工作正常,这将被提交到:{{externalLink}}",
- "document-notfound": "找不到文件"
+ "document-notfound": "找不到文件",
+ "slow-load-msg": "Looks like this is taking longer than usual, please try refreshing the page."
},
"icons": {
"gold-cup": "金奖杯",
@@ -475,10 +483,11 @@
"hint": "提示",
"heart": "爱心",
"initial": "初始",
+ "input-reset": "Clear search terms",
"info": "介绍信息",
"spacer": "间隔",
"toggle": "切换选中标记",
- "magnifier": "放大镜"
+ "magnifier": "Submit search terms"
},
"aria": {
"fcc-curriculum": "freeCodeCamp 课程",
@@ -504,10 +513,11 @@
"step": "步骤",
"steps": "步骤",
"steps-for": "{{blockTitle}} 的步骤",
- "code-example": "{{codeName}} code example"
+ "code-example": "{{codeName}} 代码示例",
+ "opens-new-window": "Opens in new window"
},
"flash": {
- "honest-first": "申请认证之前,你必须先接受我们的《学术诚信条例》",
+ "honest-first": "To claim a certification, you must first agree to our academic honesty policy",
"really-weird": "出现了一些奇怪的情况。如果再出现这种情况,请考虑在 https://github.com/freeCodeCamp/freeCodeCamp/issues/new 提交 issue。",
"not-right": "有些不对劲。已生成报告,通知 freeCodeCamp.org 团队。",
"went-wrong": "出了点问题,请检查并重试。",
@@ -586,7 +596,8 @@
"editor-url": "记得要提交Live App的URL",
"http-url": "不能使用不安全的(http)URL。",
"own-work-url": "记住要提交你自己的作业",
- "publicly-visible-url": "记得要提交一个公开可见的app URL"
+ "publicly-visible-url": "记得要提交一个公开可见的app URL",
+ "path-url": "You probably want to submit the root path i.e. https://example.com, not https://example.com/path"
},
"certification": {
"executive": "执行董事,freeCodeCamp.org",
@@ -668,8 +679,49 @@
"Cat and Dog Image Classifier": "猫和狗图像分类器",
"Book Recommendation Engine using KNN": "基于 KNN 的图书推荐引擎",
"Linear Regression Health Costs Calculator": "线性回归健康成本计算器",
- "Neural Network SMS Text Classifier": "神经网络短信分类器"
+ "Neural Network SMS Text Classifier": "神经网络短信分类器",
+ "Celestial Bodies Database": "Celestial Bodies Database",
+ "World Cup Database": "World Cup Database",
+ "Salon Appointment Scheduler": "Salon Appointment Scheduler",
+ "Periodic Table Database": "Periodic Table Database",
+ "Number Guessing Game": "Number Guessing Game",
+ "Build a freeCodeCamp Forum Homepage": "Build a freeCodeCamp Forum Homepage"
}
+ },
+ "title": {
+ "Responsive Web Design": "Responsive Web Design",
+ "responsive-web-design": "Responsive Web Design Certification",
+ "JavaScript Algorithms and Data Structures": "JavaScript Algorithms and Data Structures",
+ "javascript-algorithms-and-data-structures": "JavaScript Algorithms and Data Structures Certification",
+ "Front End Development Libraries": "Front End Development Libraries",
+ "front-end-development-libraries": "Front End Development Libraries Certification",
+ "Data Visualization": "Data Visualization",
+ "data-visualization": "Data Visualization Certification",
+ "Relational Database": "Relational Database",
+ "relational-database-v8": "Relational Database Certification",
+ "Back End Development and APIs": "Back End Development and APIs",
+ "back-end-development-and-apis": "Back End Development and APIs Certification",
+ "Quality Assurance": "Quality Assurance",
+ "quality-assurance-v7": "Quality Assurance Certification",
+ "Scientific Computing with Python": "Scientific Computing with Python",
+ "scientific-computing-with-python-v7": "Scientific Computing with Python Certification",
+ "Data Analysis with Python": "Data Analysis with Python",
+ "data-analysis-with-python-v7": "Data Analysis with Python Certification",
+ "Information Security": "Information Security",
+ "information-security-v7": "Information Security Certification",
+ "Machine Learning with Python": "Machine Learning with Python",
+ "machine-learning-with-python-v7": "Machine Learning with Python Certification",
+ "Legacy Front End": "Legacy Front End",
+ "legacy-front-end": "Front End Certification",
+ "Legacy Back End": "Legacy Back End",
+ "legacy-back-end": "Back End Certification",
+ "Legacy Data Visualization": "Legacy Data Visualization",
+ "legacy-data-visualization": "Data Visualization Certification",
+ "Legacy Information Security and Quality Assurance": "Legacy Information Security and Quality Assurance",
+ "information-security-and-quality-assurance": "Information Security and Quality Assurance Certification",
+ "Legacy Full Stack Certification": "Legacy Full Stack Certification",
+ "Legacy Full Stack": "Legacy Full Stack",
+ "full-stack": "Full Stack Certification"
}
},
"certification-card": {
@@ -724,10 +776,10 @@
"navigate-next": "跳转至下一个练习"
},
"signout": {
- "heading": "Sign out of your account",
- "p1": "Warning: If you continue, your progress will no longer be saved.",
- "p2": "This action will sign you out of your account on this device and browser session only. Please confirm if you would like to proceed.",
- "certain": "Yes, sign out of my account",
- "nevermind": "Nevermind, I don't want to sign out"
+ "heading": "注销你的账户",
+ "p1": "警告:如果你继续,你的当前进度将不再被保存。",
+ "p2": "此操作只会将你在此设备和浏览器会话上的账号注销。请确认你是否要继续。",
+ "certain": "是的,请注销我的账户",
+ "nevermind": "算了,我不想注销账户"
}
}
diff --git a/client/i18n/locales/english/intro.json b/client/i18n/locales/english/intro.json
index 863446aa4c258c..5b34848fb52dee 100644
--- a/client/i18n/locales/english/intro.json
+++ b/client/i18n/locales/english/intro.json
@@ -367,6 +367,10 @@
"learn-functional-programming-by-building-a-spreadsheet": {
"title": "Learn Functional Programming by Building a Spreadsheet",
"intro": ["", ""]
+ },
+ "learn-advanced-array-methods-by-building-a-statistics-calculator": {
+ "title": "Learn Advanced Array Methods by Building a Statistics Calculator",
+ "intro": ["", ""]
}
}
},
@@ -466,10 +470,7 @@
"In these projects, you'll need to fetch data and parse a dataset, then use D3 to create different data visualizations. Finish them all to earn your Data Visualization certification."
]
},
- "d3-dashboard": {
- "title": "D3 Dashboard",
- "intro": ["", ""]
- }
+ "d3-dashboard": { "title": "D3 Dashboard", "intro": ["", ""] }
}
},
"relational-database": {
@@ -585,7 +586,7 @@
"intro": [
"Until this point, you've only used JavaScript on the front end to add interactivity to a page, solve algorithm challenges, or build an SPA. But JavaScript can also be used on the back end, or server, to build entire web applications.",
"Today, one of the popular ways to build applications is through microservices, which are small, modular applications that work together to form a larger whole.",
- "In the Back End Development and APIs Certification, you'll learn how to write back end apps with Node.js and npm (Node Package Manager). You'll also build web applications with the Express framework, and build a People Finder microservice with MongoDB and the Mongoose library."
+ "In the Back End Development and APIs Certification, you'll learn how to write back end apps with Node.js and npm. You'll also build web applications with the Express framework, and build a People Finder microservice with MongoDB and the Mongoose library."
],
"note": "",
"blocks": {
@@ -819,6 +820,24 @@
}
}
},
+ "the-odin-project": {
+ "title": "The Odin Project",
+ "intro": [
+ "The Odin Project is one of those \"What I wish I had when I was learning\" resources. ",
+ "Not everyone has access to a computer science education or the funds to attend an intensive coding school and neither of those is right for everyone anyway.",
+ "This project is designed to fill in the gap for people who are trying to hack it on their own but still want a high quality education."
+ ],
+ "blocks": {
+ "top-learn-html-foundations": {
+ "title": "Learn HTML Foundations",
+ "intro": ["A description is to be determined"]
+ },
+ "top-build-a-recipe-project": {
+ "title": "Learn HTML Foundations by Building a Recipe Page",
+ "intro": ["A description is to be determined"]
+ }
+ }
+ },
"misc-text": {
"certification": "{{cert}} Certification",
"browse-other": "Browse our other free certifications\n(we recommend doing these in order)",
diff --git a/client/i18n/locales/english/translations.json b/client/i18n/locales/english/translations.json
index 2ece8d81b3ddf1..64fa3faebab4eb 100644
--- a/client/i18n/locales/english/translations.json
+++ b/client/i18n/locales/english/translations.json
@@ -11,11 +11,12 @@
"view": "View",
"view-code": "View Code",
"view-project": "View Project",
+ "view-cert-title": "View {{certTitle}}",
"show-cert": "Show Certification",
"claim-cert": "Claim Certification",
"save-progress": "Save Progress",
- "accepted-honesty": "You have accepted our Academic Honesty Policy.",
- "agree": "Agree",
+ "accepted-honesty": "You have agreed to our Academic Honesty Policy.",
+ "agree-honesty": "I agree to freeCodeCamp's Academic Honesty Policy.",
"save-portfolio": "Save this portfolio item",
"remove-portfolio": "Remove this portfolio item",
"add-portfolio": "Add a new portfolio Item",
@@ -53,7 +54,7 @@
"check-code": "Check Your Code (Ctrl + Enter)",
"check-code-2": "Check Your Code",
"reset": "Reset",
- "reset-code": "Reset Code",
+ "reset-step": "Reset This Step",
"help": "Help",
"get-help": "Get Help",
"watch-video": "Watch a Video",
@@ -158,7 +159,8 @@
"honesty": "Academic Honesty Policy",
"internet": "Your Internet Presence",
"portfolio": "Portfolio Settings",
- "privacy": "Privacy Settings"
+ "privacy": "Privacy Settings",
+ "personal-info": "Personal Information"
},
"danger": {
"heading": "Danger Zone",
@@ -223,16 +225,15 @@
"total-points_plural": "{{count}} total points",
"points": "{{count}} point on {{date}}",
"points_plural": "{{count}} points on {{date}}",
- "screen-shot": "A screen shot of {{title}}",
"page-number": "{{pageNumber}} of {{totalPages}}"
},
"footer": {
- "tax-exempt-status": "freeCodeCamp is a donor-supported tax-exempt 501(c)(3) nonprofit organization (United States Federal Tax Identification Number: 82-0779546)",
+ "tax-exempt-status": "freeCodeCamp is a donor-supported tax-exempt 501(c)(3) charitable organization (United States Federal Tax Identification Number: 82-0779546)",
"mission-statement": "Our mission: to help people learn to code for free. We accomplish this by creating thousands of videos, articles, and interactive coding lessons - all freely available to the public. We also have thousands of freeCodeCamp study groups around the world.",
"donation-initiatives": "Donations to freeCodeCamp go toward our education initiatives, and help pay for servers, services, and staff.",
"donate-text": "You can <1>make a tax-deductible donation here1>.",
"trending-guides": "Trending Guides",
- "our-nonprofit": "Our Nonprofit",
+ "our-nonprofit": "Our Charity",
"links": {
"about": "About",
"alumni": "Alumni Network",
@@ -250,6 +251,7 @@
},
"learn": {
"heading": "Welcome to freeCodeCamp's curriculum.",
+ "skip-to-content": "Skip to content",
"welcome-1": "Welcome back, {{name}}.",
"welcome-2": "Welcome to freeCodeCamp.org",
"start-at-beginning": "If you are new to coding, we recommend you <0>start at the beginning0>.",
@@ -273,6 +275,9 @@
"add-subtitles": "Help improve or add subtitles",
"wrong-answer": "Sorry, that's not the right answer. Give it another try?",
"check-answer": "Click the button below to check your answer.",
+ "assignment-not-complete": "Please finish the assignments",
+ "assignments": "Assignments",
+ "question": "Question",
"solution-link": "Solution Link",
"github-link": "GitHub Link",
"submit-and-go": "Submit & go to next step",
@@ -298,7 +303,6 @@
"certs": "{{title}} Certification"
},
"editor-tabs": {
- "info": "Info",
"code": "Code",
"tests": "Tests",
"restart": "Restart",
@@ -308,6 +312,10 @@
"notes": "Notes",
"preview": "Preview"
},
+ "editor-alerts": {
+ "tab-trapped": "Pressing tab will now insert the tab character",
+ "tab-free": "Pressing tab will now move focus to the next focusable element"
+ },
"help-translate": "We are still translating the following certifications.",
"help-translate-link": "Help us translate.",
"project-preview-title": "Here's a preview of what you will build",
@@ -328,12 +336,12 @@
"sorry-dont-giveup": "Sorry, your code does not pass. Don't give up.",
"challenges-completed": "{{completedCount}} of {{totalChallenges}} challenges completed",
"season-greetings-fcc": "Season's Greetings from the freeCodeCamp community 🎉",
- "if-getting-value": "If you're getting a lot out of freeCodeCamp, now is a great time to donate to support our nonprofit's mission.",
+ "if-getting-value": "If you're getting a lot out of freeCodeCamp, now is a great time to donate to support our charity's mission.",
"building-a-university": "We're Building a Free Computer Science University Degree Program",
"if-help-university": "We've already made a ton of progress. Support our charity with the long road ahead."
},
"donate": {
- "title": "Support our nonprofit",
+ "title": "Support our charity",
"processing": "We are processing your donation.",
"redirecting": "Redirecting...",
"thanks": "Thanks for donating",
@@ -356,10 +364,9 @@
"your-donation-2": "Your ${{usd}} donation will provide {{hours}} hours of learning to people around the world each month.",
"your-donation-3": "Your ${{usd}} donation will provide {{hours}} hours of learning to people around the world each year.",
"become-supporter": "Become a Supporter",
- "duration": "Become a one-time supporter of our nonprofit.",
- "duration-2": "Become a monthly supporter of our nonprofit.",
- "duration-3": "Become an annual supporter of our nonprofit",
- "duration-4": "Become a supporter of our nonprofit",
+ "duration": "Become a one-time supporter of our charity.",
+ "duration-2": "Become a monthly supporter of our charity.",
+ "duration-4": "Become a supporter of our charity",
"nicely-done": "Nicely done. You just completed {{block}}.",
"credit-card": "Credit Card",
"credit-card-2": "Or donate with a credit card:",
@@ -373,25 +380,25 @@
"email-receipt": "Email (we'll send you a tax-deductible donation receipt):",
"need-help": "Need help with your current or past donations?",
"forward-receipt": "Forward a copy of your donation receipt to donors@freecodecamp.org and tell us how we can help.",
- "efficiency": "freeCodeCamp is a highly efficient education nonprofit.",
+ "efficiency": "freeCodeCamp is a highly efficient education charity.",
"why-donate-1": "When you donate to freeCodeCamp, you help people learn new skills and provide for their families.",
"why-donate-2": "You also help us create new resources for you to use to expand your own technology skills.",
"bigger-donation": "Want to make a bigger one-time donation, mail us a check, or give in other ways?",
- "other-ways": "Here are many <0>other ways you can support our non-profit's mission0>.",
+ "other-ways": "Here are many <0>other ways you can support our charity's mission0>.",
"failed-pay": "Uh - oh. It looks like your transaction didn't go through. Could you please try again?",
"try-again": "Please try again.",
"card-number": "Your Card Number:",
"expiration": "Expiration Date:",
"secure-donation": "Secure donation",
"faq": "Frequently asked questions",
- "only-you": "Only you can see this message. Congratulations on earning this certification. It's no easy task. Running freeCodeCamp isn't easy either. Nor is it cheap. Help us help you and many other people around the world. Make a tax-deductible supporting donation to our nonprofit today.",
+ "only-you": "Only you can see this message. Congratulations on earning this certification. It's no easy task. Running freeCodeCamp isn't easy either. Nor is it cheap. Help us help you and many other people around the world. Make a tax-deductible supporting donation to our charity today.",
"get-help": "How can I get help with my donations?",
"how-transparent": "How transparent is freeCodeCamp.org?",
"very-transparent": "Very. We have a Platinum transparency rating from GuideStar.org.",
"download-irs": "You can <0>download our IRS Determination Letter here0>.",
"download-990": "You can <0>download our most recent 990 (annual tax report) here0>.",
"how-efficient": "How efficient is freeCodeCamp?",
- "fcc-budget": "freeCodeCamp's budget is much smaller than most comparable nonprofits. We haven't brought in professional fundraisers. Instead, Quincy does everything himself.",
+ "fcc-budget": "freeCodeCamp's budget is much smaller than most comparable charity. We haven't brought in professional fundraisers. Instead, Quincy does everything himself.",
"help-millions": "However, on a budget of only a few hundred thousand dollars per year, we have been able to help millions of people.",
"how-one-time": "How can I make a one-time donation?",
"one-time": "If you'd prefer to make one-time donations, you can support freeCodeCamp's mission whenever you have cash to spare. You can use <0>this link to donate whatever amount feels right through PayPal0>.",
@@ -401,7 +408,7 @@
"can-check": "Can I mail a physical check?",
"yes-check": "Yes, we would welcome a check. You can mail it to us at:",
"how-matching-gift": "How can I set up matching gifts from my employer, or payroll deductions?",
- "employers-vary": "This varies from employer to employer, and our nonprofit is already listed in many of the big donation-matching databases.",
+ "employers-vary": "This varies from employer to employer, and our charity is already listed in many of the big donation-matching databases.",
"some-volunteer": "Some people are able to volunteer for freeCodeCamp and their employer matches by donating a fixed amount per hour they volunteer. Other employers will match any donations the donors make up to a certain amount",
"help-matching-gift": "If you need help with this, please email Quincy directly: quincy@freecodecamp.org",
"how-endowment": "How can I set up an Endowment Gift to freeCodeCamp.org?",
@@ -412,13 +419,13 @@
"thank-wikimedia": "We would like to thank the Wikimedia Foundation for providing this formal language for us to use.",
"legacy-gift-questions": "If you have any questions about this process, please email Quincy at quincy@freecodecamp.org.",
"how-stock": "How can I donate stock to freeCodeCamp.org?",
- "welcome-stock": "We would welcome your stock donations. Please email Quincy directly and he can help you with this, and share our nonprofit's brokerage account details: quincy@freecodecamp.org.",
+ "welcome-stock": "We would welcome your stock donations. Please email Quincy directly and he can help you with this, and share our charity's brokerage account details: quincy@freecodecamp.org.",
"how-receipt": "Can I get a donation receipt so that I can deduct my donation from my taxes?",
"just-forward": "Absolutely. Just forward the receipt from your transaction to donors@freecodecamp.org, tell us you'd like a receipt and any special instructions you may have, and we'll reply with a receipt for you.",
"how-update": "I set up a monthly donation, but I need to update or pause the monthly recurrence. How can I do this?",
"take-care-of-this": "Just forward one of your monthly donation receipts to donors@freecodecamp.org and tell us what you'd like us to do. We'll take care of this for you and send you confirmation.",
"anything-else": "Is there anything else I can learn about donating to freeCodeCamp.org?",
- "other-support": "If there is some other way you'd like to support our nonprofit and its mission that isn't listed here, or if you have any questions at all, please email Quincy at quincy@freecodecamp.org."
+ "other-support": "If there is some other way you'd like to support our charity and its mission that isn't listed here, or if you have any questions at all, please email Quincy at quincy@freecodecamp.org."
},
"report": {
"sign-in": "You need to be signed in to report a user",
@@ -461,7 +468,8 @@
"iframe-preview": "{{title}} preview",
"iframe-alert": "Normally this link would bring you to another website! It works. This is a link to: {{externalLink}}",
"iframe-form-submit-alert": "Normally this form would be submitted! It works. This will be submitted to: {{externalLink}}",
- "document-notfound": "document not found"
+ "document-notfound": "document not found",
+ "slow-load-msg": "Looks like this is taking longer than usual, please try refreshing the page."
},
"icons": {
"gold-cup": "Gold Cup",
@@ -476,10 +484,11 @@
"hint": "Hint",
"heart": "Heart",
"initial": "Initial",
+ "input-reset": "Clear search terms",
"info": "Intro Information",
"spacer": "Spacer",
"toggle": "Toggle Checkmark",
- "magnifier": "magnifier"
+ "magnifier": "Submit search terms"
},
"aria": {
"fcc-curriculum": "freeCodeCamp Curriculum",
@@ -505,10 +514,11 @@
"step": "Step",
"steps": "Steps",
"steps-for": "Steps for {{blockTitle}}",
- "code-example": "{{codeName}} code example"
+ "code-example": "{{codeName}} code example",
+ "opens-new-window": "Opens in new window"
},
"flash": {
- "honest-first": "To claim a certification, you must first accept our academic honesty policy",
+ "honest-first": "To claim a certification, you must first agree to our academic honesty policy",
"really-weird": "Something really weird happened, if it happens again, please consider raising an issue on https://github.com/freeCodeCamp/freeCodeCamp/issues/new",
"not-right": "Something is not quite right. A report has been generated and the freeCodeCamp.org team have been notified",
"went-wrong": "Something went wrong, please check and try again",
@@ -587,7 +597,8 @@
"editor-url": "Remember to submit the Live App URL.",
"http-url": "An unsecure (http) URL cannot be used.",
"own-work-url": "Remember to submit your own work.",
- "publicly-visible-url": "Remember to submit a publicly visible app URL."
+ "publicly-visible-url": "Remember to submit a publicly visible app URL.",
+ "path-url": "You probably want to submit the root path i.e. https://example.com, not https://example.com/path"
},
"certification": {
"executive": "Executive Director, freeCodeCamp.org",
@@ -669,8 +680,49 @@
"Cat and Dog Image Classifier": "Cat and Dog Image Classifier",
"Book Recommendation Engine using KNN": "Book Recommendation Engine using KNN",
"Linear Regression Health Costs Calculator": "Linear Regression Health Costs Calculator",
- "Neural Network SMS Text Classifier": "Neural Network SMS Text Classifier"
+ "Neural Network SMS Text Classifier": "Neural Network SMS Text Classifier",
+ "Celestial Bodies Database": "Celestial Bodies Database",
+ "World Cup Database": "World Cup Database",
+ "Salon Appointment Scheduler": "Salon Appointment Scheduler",
+ "Periodic Table Database": "Periodic Table Database",
+ "Number Guessing Game": "Number Guessing Game",
+ "Build a freeCodeCamp Forum Homepage": "Build a freeCodeCamp Forum Homepage"
}
+ },
+ "title": {
+ "Responsive Web Design": "Responsive Web Design",
+ "responsive-web-design": "Responsive Web Design Certification",
+ "JavaScript Algorithms and Data Structures": "JavaScript Algorithms and Data Structures",
+ "javascript-algorithms-and-data-structures": "JavaScript Algorithms and Data Structures Certification",
+ "Front End Development Libraries": "Front End Development Libraries",
+ "front-end-development-libraries": "Front End Development Libraries Certification",
+ "Data Visualization": "Data Visualization",
+ "data-visualization": "Data Visualization Certification",
+ "Relational Database": "Relational Database",
+ "relational-database-v8": "Relational Database Certification",
+ "Back End Development and APIs": "Back End Development and APIs",
+ "back-end-development-and-apis": "Back End Development and APIs Certification",
+ "Quality Assurance": "Quality Assurance",
+ "quality-assurance-v7": "Quality Assurance Certification",
+ "Scientific Computing with Python": "Scientific Computing with Python",
+ "scientific-computing-with-python-v7": "Scientific Computing with Python Certification",
+ "Data Analysis with Python": "Data Analysis with Python",
+ "data-analysis-with-python-v7": "Data Analysis with Python Certification",
+ "Information Security": "Information Security",
+ "information-security-v7": "Information Security Certification",
+ "Machine Learning with Python": "Machine Learning with Python",
+ "machine-learning-with-python-v7": "Machine Learning with Python Certification",
+ "Legacy Front End": "Legacy Front End",
+ "legacy-front-end": "Front End Certification",
+ "Legacy Back End": "Legacy Back End",
+ "legacy-back-end": "Back End Certification",
+ "Legacy Data Visualization": "Legacy Data Visualization",
+ "legacy-data-visualization": "Data Visualization Certification",
+ "Legacy Information Security and Quality Assurance": "Legacy Information Security and Quality Assurance",
+ "information-security-and-quality-assurance": "Information Security and Quality Assurance Certification",
+ "Legacy Full Stack Certification": "Legacy Full Stack Certification",
+ "Legacy Full Stack": "Legacy Full Stack",
+ "full-stack": "Full Stack Certification"
}
},
"certification-card": {
diff --git a/client/i18n/locales/espanol/intro.json b/client/i18n/locales/espanol/intro.json
index 06cd2940c088a6..6b69e55e927ed8 100644
--- a/client/i18n/locales/espanol/intro.json
+++ b/client/i18n/locales/espanol/intro.json
@@ -1,8 +1,8 @@
{
"responsive-web-design": {
- "title": "Diseño Web Responsivo Legado",
+ "title": "Diseño Web Adaptativo Legado",
"intro": [
- "En esta Certificación de Diseño Web Responsivo, aprenderás los lenguajes que los desarrolladores utilizan para construir páginas web: HTML (lenguaje de marcado de hipertexto) para el contenido, y CSS (Hojas de estilo en cascada) para el diseño.",
+ "En esta Certificación de Diseño Web Adaptativo, aprenderás los lenguajes que los desarrolladores utilizan para construir páginas web: HTML (lenguaje de marcado de hipertexto) para el contenido, y CSS (Hojas de estilo en cascada) para el diseño.",
"Primero, crearás una aplicación de fotos de gatos para aprender los conceptos básicos de HTML y CSS. Más adelante, aprenderá técnicas modernas como variables CSS mediante la construcción de un pingüino, y las mejores prácticas para la accesibilidad mediante la construcción de un formulario web.",
"Finalmente, aprenderás cómo hacer páginas web que respondan a diferentes tamaños de pantalla construyendo una tarjeta de Twitter con Flexbox, y un diseño complejo de blog con CSS Grid."
],
@@ -37,9 +37,9 @@
]
},
"responsive-web-design-principles": {
- "title": "Principios de diseño web responsivo",
+ "title": "Principios de diseño web adaptativo",
"intro": [
- "Hay muchos dispositivos que pueden acceder a la web, y vienen en todas las formas y tamaños. El diseño web responsivo es la práctica de diseñar sitios web flexibles que pueden responder a diferentes tamaños de pantalla, orientaciones y resoluciones.",
+ "Hay muchos dispositivos que pueden acceder a la web, y vienen en todas las formas y tamaños. El diseño web adaptativo es la práctica de diseñar sitios web flexibles que pueden responder a diferentes tamaños de pantalla, orientaciones y resoluciones.",
"En este curso, aprenderás a usar CSS para que tus páginas web luzcan bien, sin importar en qué dispositivo se vean."
]
},
@@ -61,15 +61,15 @@
"title": "Proyectos de diseño web responsivo",
"intro": [
"Es hora de poner tus habilidades recién aprendidas a funcionar. Al trabajar en estos proyectos, tendrás la oportunidad de aplicar todas las habilidades, principios y conceptos que has aprendido hasta ahora: HTML, CSS, diseño visual, accesibilidad y más.",
- "Completa los cinco proyectos de programación web de abajo para obtener tu certificación de diseño web responsivo."
+ "Completa los cinco proyectos de programación web de abajo para obtener tu certificación de diseño web adaptativo."
]
}
}
},
"2022/responsive-web-design": {
- "title": "(Nuevo) Diseño Web Responsivo",
+ "title": "(Nuevo) Diseño Web Adaptativo",
"intro": [
- "En esta certificación de Diseño Web Responsivo, aprenderás los lenguajes que los desarrolladores usan para construir páginas web: HTML (Lenguaje de Marcado de Hipertexto) para el contenido, y CSS (hojas de estilo en cascada) para el diseño.",
+ "En esta certificación de Diseño Web Adaptativo, aprenderás los lenguajes que los desarrolladores usan para construir páginas web: HTML (Lenguaje de Marcado de Hipertexto) para el contenido, y CSS (hojas de estilo en cascada) para el diseño.",
"Primero, crearás una aplicación de fotos de gatos para aprender los conceptos básicos de HTML y CSS. Más adelante, aprenderás técnicas modernas como variables CSS, mediante la construcción de un pingüino, y las mejores prácticas para la accesibilidad mediante la construcción de un sitio de cuestionarios.",
"Por último, aprenderás cómo hacer páginas web que respondan a diferentes tamaños de pantalla, mediante la construcción de una galería de fotos con Flexbox, y un diseño de artículos de revista con CSS Grid."
],
@@ -159,17 +159,17 @@
]
},
"learn-responsive-web-design-by-building-a-piano": {
- "title": "Aprende diseño web adaptable construyendo un piano",
+ "title": "Aprende diseño web adaptativo construyendo un piano",
"intro": [
- "El diseño web adaptable dice a tu página como debe verse en pantallas de diferentes tamaños.",
- "En este curso, usarás CSS y Diseño Responsivo para programar un piano. También aprenderás más sobre las consultas de medios y pseudoselectores."
+ "El diseño adaptativo indica a tu página web cómo debe verse en pantallas de distintos tamaños.",
+ "En este curso, usarás CSS y Diseño Adaptativo para programar un piano. También aprenderás más sobre las consultas de medios y pseudoselectores."
]
},
"learn-css-flexbox-by-building-a-photo-gallery": {
"title": "Aprende CSS Flexbox construyendo una galería de fotos",
"intro": [
"Flexbox te ayuda a diseñar tu página web para que se vea bien en cualquier tamaño de pantalla.",
- "En este curso, usarás Flexbox para crear una página web de una galería de fotos receptiva."
+ "En este curso, usarás Flexbox para crear una página web de una galería de fotos adaptativa."
]
},
"learn-css-grid-by-building-a-magazine": {
@@ -180,7 +180,7 @@
]
},
"learn-typography-by-building-a-nutrition-label": {
- "title": "Aprende tipografias compilando una etiqueta nutricional",
+ "title": "Aprende tipografía construyendo una etiqueta de nutrición",
"intro": [
"La tipografía es el arte de diseñar tu texto haciéndolo de fácil lectura y adaptado a su propósito.",
"En este curso, usarás tipografía para compilar una página web de etiqueta. Aprenderás cómo estilizar el texto, ajustar altura de línea y la posición de tu texto usando CSS."
@@ -335,6 +335,10 @@
"learn-functional-programming-by-building-a-spreadsheet": {
"title": "Aprende programación funcional construyendo una hoja de cálculo",
"intro": ["", ""]
+ },
+ "learn-advanced-array-methods-by-building-a-statistics-calculator": {
+ "title": "Learn Advanced Array Methods by Building a Statistics Calculator",
+ "intro": ["", ""]
}
}
},
@@ -350,8 +354,8 @@
"bootstrap": {
"title": "Bootstrap",
"intro": [
- "Bootstrap es un framework de la interfaz utilizado para diseñar páginas y aplicaciones web. Tiene un enfoque de desarrollo web centrado en los dispositivos móviles e incluye estilos y clases CSS pre-configurados, además de algunas funciones de JavaScript.",
- "En este curso, aprenderás cómo crear sitios web responsivos con Bootstrap, y utilizarás sus clases incluidas para estilizar botones, imágenes, formularios, navegación y otros elementos."
+ "Bootstrap es un framework front end que se utiliza para diseñar páginas y aplicaciones web adaptativas. Tiene un enfoque de desarrollo web e incluye estilos y clases CSS predefinidos, además de algunas funcionalidades de JavaScript.",
+ "En este curso, aprenderás cómo crear sitios web adaptativos con Bootstrap, y utilizarás sus clases incluidas para estilizar botones, imágenes, formularios, navegación y otros elementos."
]
},
"jquery": {
@@ -553,7 +557,7 @@
"intro": [
"Hasta este punto, solo has usado JavaScript en la parte de front-end para agregar interactividad a una página, resolver los desafíos de algoritmos o construir un SPA. Pero JavaScript también se puede utilizar en el back-end, o servidor, para construir aplicaciones web completas.",
"Hoy en día, una de las formas populares para construir aplicaciones es a través de microservicios, que son pequeñas aplicaciones modulares que trabajan juntas para formar una aplicación más grande.",
- "En la Certificación Desarrollo de Back End y APIs, aprenderás cómo escribir aplicaciones de back-end con Node.js y npm (Node Package Manager). También construirás aplicaciones web con el framework Express, y un microservicio \"People Finder\" con MongoDB y la biblioteca Mongoose."
+ "In the Back End Development and APIs Certification, you'll learn how to write back end apps with Node.js and npm. You'll also build web applications with the Express framework, and build a People Finder microservice with MongoDB and the Mongoose library."
],
"note": "",
"blocks": {
@@ -787,6 +791,24 @@
}
}
},
+ "the-odin-project": {
+ "title": "The Odin Project",
+ "intro": [
+ "The Odin Project is one of those \"What I wish I had when I was learning\" resources. ",
+ "Not everyone has access to a computer science education or the funds to attend an intensive coding school and neither of those is right for everyone anyway.",
+ "This project is designed to fill in the gap for people who are trying to hack it on their own but still want a high quality education."
+ ],
+ "blocks": {
+ "top-learn-html-foundations": {
+ "title": "Learn HTML Foundations",
+ "intro": ["A description is to be determined"]
+ },
+ "top-build-a-recipe-project": {
+ "title": "Learn HTML Foundations by Building a Recipe Page",
+ "intro": ["A description is to be determined"]
+ }
+ }
+ },
"misc-text": {
"certification": "Certificación de {{cert}}",
"browse-other": "Navega por nuestras otras certificaciones gratuitas\n(recomendamos hacerlo en orden)",
@@ -797,7 +819,7 @@
"legacy-header": "Cursos Antiguos",
"legacy-desc": "Estos cursos ya no forman parte de la ruta de certificación, pero todavía están disponibles para tu aprendizaje.",
"legacy-go-back": "Ve a la versión actual del plan de estudios.",
- "new-rwd-desc": "Hemos actualizado nuestro plan de estudios de diseño web responsivo. Si anteriormente estabas trabajando en el plan de estudios de diseño web responsivo, ¡tu progreso sigue guardado! Puedes encontrarlo en la sección diseño web responsivo legado.",
+ "new-rwd-desc": "Hemos actualizado nuestro plan de estudios de diseño web adaptativo. Si anteriormente estabas trabajando en el plan de estudios de diseño web adaptativo, ¡tu progreso sigue guardado! Puedes encontrarlo en la sección diseño web adaptativo legado.",
"new-rwd-article": "Te animamos a leer sobre los cambios que hicimos y considerar explorar el plan de estudios actualizado.",
"viewing-upcoming-change": "Estás viendo una página beta. ",
"go-back-to-learn": "Volver a la versión estable del currículum.",
diff --git a/client/i18n/locales/espanol/translations.json b/client/i18n/locales/espanol/translations.json
index 90596ce7450b85..57ffea1192ed22 100644
--- a/client/i18n/locales/espanol/translations.json
+++ b/client/i18n/locales/espanol/translations.json
@@ -11,11 +11,12 @@
"view": "Ver",
"view-code": "Mostrar Código",
"view-project": "Mostrar Proyecto",
+ "view-cert-title": "Ver {{certTitle}}",
"show-cert": "Mostrar certificación",
"claim-cert": "Solicitar certificación",
"save-progress": "Guardar progreso",
"accepted-honesty": "Has aceptado nuestra Política de Honestidad Académica.",
- "agree": "Aceptar",
+ "agree-honesty": "Estoy de acuerdo con la Política de Honestidad Académica de freeCodeCamp.",
"save-portfolio": "Guardar este elemento de portafolio",
"remove-portfolio": "Eliminar este elemento de portafolio",
"add-portfolio": "Agregar un nuevo elemento de portafolio",
@@ -52,7 +53,7 @@
"check-code": "Comprueba tu código (Ctrl + Enter)",
"check-code-2": "Comprueba tu código",
"reset": "Restablecer",
- "reset-code": "Restablecer todo el código",
+ "reset-step": "Restablecer este paso",
"help": "Ayuda",
"get-help": "Obtener ayuda",
"watch-video": "Ver un Video",
@@ -157,7 +158,8 @@
"honesty": "Política de Honestidad Académica",
"internet": "Tu presencia en Internet",
"portfolio": "Ajustes de portafolio",
- "privacy": "Ajustes de privacidad"
+ "privacy": "Ajustes de privacidad",
+ "personal-info": "Información Personal"
},
"danger": {
"heading": "Zona de peligro",
@@ -222,16 +224,15 @@
"total-points_plural": "{{count}} puntos en total",
"points": "{{count}} punto en {{date}}",
"points_plural": "{{count}} puntos en {{date}}",
- "screen-shot": "Una captura de pantalla de {{title}}",
"page-number": "{{pageNumber}} de {{totalPages}}"
},
"footer": {
- "tax-exempt-status": "freeCodeCamp es una organización sin fines de lucro exenta de impuestos 501(c)(3) respaldada por donantes (Número de identificación fiscal federal de los Estados Unidos: 82-0779546)",
+ "tax-exempt-status": "freeCodeCamp es una organización benéfica 501(c)(3) exenta de impuestos apoyada por donantes (Número de Identificación Fiscal Federal De Los Estados Unidos: 82-0779546)",
"mission-statement": "Nuestra misión: ayudar a las personas a aprender a programar de forma gratuita. Logramos esto mediante la creación de miles de videos, artículos y lecciones de programación interactivas, todos disponibles gratuitamente para el público. También tenemos miles de grupos de estudio de FreeCodeCamp en todo el mundo.",
"donation-initiatives": "Las donaciones a freeCodeCamp se destinan a nuestras iniciativas educativas y ayudan a pagar los servidores, los servicios y el personal.",
"donate-text": "Puedes <1>hacer una donación deducible de impuestos aquí1>.",
"trending-guides": "Guías de tendencias",
- "our-nonprofit": "Nuestra organización sin fines de lucro",
+ "our-nonprofit": "Nuestra Caridad",
"links": {
"about": "Acerca de",
"alumni": "Red de ex-Alumnos",
@@ -249,6 +250,7 @@
},
"learn": {
"heading": "Bienvenido al currículo de freeCodeCamp.",
+ "skip-to-content": "Skip to content",
"welcome-1": "Bienvenido de nuevo, {{name}}.",
"welcome-2": "Bienvenido a freeCodeCamp.org",
"start-at-beginning": "Si eres nuevo en la programación, te recomendamos <0>comenzar desde el principio0>.",
@@ -264,7 +266,7 @@
"p8": "Y este currículo te brindará miles de horas de práctica de programación.",
"p9": "Y si deseas aprender más sobre matemáticas y teoría de la informática, también tenemos miles de horas de cursos en video en <0>el canal de YouTube de freeCodeCamp0>.",
"p10": "Si deseas obtener un trabajo de desarrollador o clientes independientes, las habilidades de programación serán solo una parte del rompecabezas. También necesitas construir tu red personal y tu reputación como desarrollador.",
- "p11": "You can do this on LinkedIn and GitHub, and also on <0>the freeCodeCamp forum0>.",
+ "p11": "Puedes hacer esto en LinkedIn y GitHub, y también en <0>el foro freeCodeCamp0>.",
"p12": "¡Feliz día programando!"
},
"upcoming-lessons": "Próximas lecciones",
@@ -272,6 +274,9 @@
"add-subtitles": "Ayudar a mejorar o agregar subtítulos",
"wrong-answer": "Lo siento, esa no es la respuesta correcta. ¡Vuelve a intentarlo!",
"check-answer": "Haz clic en el botón de abajo para verificar tu respuesta.",
+ "assignment-not-complete": "Por favor, completa las tareas",
+ "assignments": "Asignaciones",
+ "question": "Pregunta",
"solution-link": "Enlace a la solución",
"github-link": "Enlace de GitHub",
"submit-and-go": "Enviar y pasar a mi siguiente desafío",
@@ -297,7 +302,6 @@
"certs": "Certificación {{title}}"
},
"editor-tabs": {
- "info": "Info",
"code": "Código",
"tests": "Pruebas",
"restart": "Reiniciar",
@@ -307,6 +311,10 @@
"notes": "Notas",
"preview": "Vista"
},
+ "editor-alerts": {
+ "tab-trapped": "Presionando la pestaña insertará el carácter de la pestaña",
+ "tab-free": "Presionando la pestaña ahora se moverá el foco al siguiente elemento enfocable"
+ },
"help-translate": "Todavía estamos traduciendo las siguientes certificaciones.",
"help-translate-link": "Ayúdanos a traducir.",
"project-preview-title": "Aquí hay una vista previa de lo que construirás",
@@ -326,13 +334,13 @@
"sorry-hang-in-there": "Lo sentimos, su código no pasa. Aguanta ahí.",
"sorry-dont-giveup": "Lo sentimos, su código no pasa. No te rindas.",
"challenges-completed": "{{completedCount}} de {{totalChallenges}} desafíos completados",
- "season-greetings-fcc": "Season's Greetings from the freeCodeCamp community 🎉",
- "if-getting-value": "If you're getting a lot out of freeCodeCamp, now is a great time to donate to support our nonprofit's mission.",
- "building-a-university": "We're Building a Free Computer Science University Degree Program",
- "if-help-university": "We've already made a ton of progress. Support our charity with the long road ahead."
+ "season-greetings-fcc": "Saludos de Temporada de la comunidad freeCodeCamp 🎉",
+ "if-getting-value": "Si estás obteniendo mucho de freeCodeCamp, ahora es un buen momento para donar con el fin de apoyar nuestra misión sin fines de lucro.",
+ "building-a-university": "Estamos construyendo un programa gratuito de grado universitario en ciencias de la computación",
+ "if-help-university": "Ya hemos hecho un montón de progresos. Apoyamos nuestra caridad con el largo camino por delante."
},
"donate": {
- "title": "Apoya a nuestra organización sin fines de lucro",
+ "title": "Apoya nuestra caridad",
"processing": "Estamos procesando tu donación.",
"redirecting": "Redirigiendo...",
"thanks": "Gracias por donar",
@@ -354,11 +362,10 @@
"your-donation": "Tu donación de ${{usd}} proporcionará {{hours}} horas de aprendizaje a personas de todo el mundo.",
"your-donation-2": "Tu donación de ${{usd}} proporcionará {{hours}} horas de aprendizaje a personas de todo el mundo cada mes.",
"your-donation-3": "Tu donación de ${{usd}} proporcionará {{hours}} horas de aprendizaje a personas de todo el mundo cada año.",
- "become-supporter": "Become a Supporter",
- "duration": "Conviértete en un contribuyente único de nuestra organización sin fines de lucro.",
- "duration-2": "Conviértete en un contribuyente mensual de nuestra organización sin fines de lucro.",
- "duration-3": "Conviértete en un contribuyente anual de nuestra organización sin fines de lucro",
- "duration-4": "Conviértete en un contribuyente de nuestra organización sin fines de lucro",
+ "become-supporter": "Conviértete en un colaborador",
+ "duration": "Se un benefactor de nuestra organización benéfica con una donación única.",
+ "duration-2": "Se un benefactor mensual de nuestra organización benéfica.",
+ "duration-4": "Se un benefactor de nuestra organización benéfica",
"nicely-done": "Bien hecho. Acabas de completar {{block}}.",
"credit-card": "Tarjeta de crédito",
"credit-card-2": "O dona con una tarjeta de crédito:",
@@ -372,25 +379,25 @@
"email-receipt": "Correo electrónico (te enviaremos un recibo de donación deducible de impuestos):",
"need-help": "¿Necesitas ayuda con tus donaciones actuales o pasadas?",
"forward-receipt": "Envía una copia de tu recibo de donación a donors@freecodecamp.org y dinos cómo podemos ayudar.",
- "efficiency": "freeCodeCamp es una organización educativa sin fines de lucro altamente eficiente.",
+ "efficiency": "freeCodeCamp es una organización benéfica educativa de gran eficacia.",
"why-donate-1": "Cuando donas a freeCodeCamp, ayudas a las personas a aprender nuevas habilidades y proveer para sus familias",
"why-donate-2": "También nos ayudas a crear nuevos recursos para que los utilices y amplíes tus propias habilidades tecnológicas.",
"bigger-donation": "¿Quieres hacer una donación más grande de una sola vez, envíanos un cheque o da de otras maneras?",
- "other-ways": "Aquí hay muchas <0>otras formas en las que puedes apoyar la misión de nuestra organización sin fines de lucro0>.",
+ "other-ways": "Aquí hay muchas <0>otras formas de apoyar la misión de nuestra organización benéfica0>.",
"failed-pay": "Oh no. Parece que tu transacción no se realizó. ¿Podrías intentarlo de nuevo?",
"try-again": "Por favor, intenta de nuevo.",
"card-number": "Tu número de tarjeta:",
"expiration": "Fecha de vencimiento:",
"secure-donation": "Donación segura",
"faq": "Preguntas frecuentes",
- "only-you": "Solo tú puedes ver este mensaje. Felicitaciones por obtener esta certificación. No es una tarea fácil. Operar freeCodeCamp tampoco es fácil. Ni es barato. Ayúdanos a ayudarte a ti y a muchas otras personas en todo el mundo. Haz una donación de apoyo deducible de impuestos a nuestra organización sin fines de lucro hoy.",
+ "only-you": "Sólo tu puedes ver este mensaje. Enhorabuena por haber obtenido esta certificación. No es tarea fácil. Administrar freeCodeCamp tampoco es fácil. Tampoco es barato. Ayúdanos a ayudarte a ti y a muchas otras personas de todo el mundo. Haz hoy una donación deducible de impuestos a nuestra organización benéfica.",
"get-help": "¿Cómo puedo obtener ayuda con mis donaciones?",
"how-transparent": "¿Qué tan transparente es freeCodeCamp.org?",
"very-transparent": "Muy Transparente. Tenemos una valoración de transparencia de platino en GuideStar.org.",
"download-irs": "Puedes <0>descargar nuestra Carta de Determinación de IRS aquí0>.",
"download-990": "Puedes <0>descargar nuestro 990 más reciente (informe anual de impuestos) aquí0>.",
"how-efficient": "¿Qué tan eficiente es freeCodeCamp?",
- "fcc-budget": "El presupuesto de freeCodeCamp es mucho más pequeño que la mayoría de las organizaciones sin fines de lucro comparables. No hemos traído recaudadores de fondos profesionales. En lugar de eso, Quincy hace todo él mismo.",
+ "fcc-budget": "El presupuesto de freeCodeCamp es mucho menor que el de la mayoría de organizaciones benéficas comparables. No hemos contratado a profesionales para recaudar fondos. En su lugar, Quincy lo hace todo él mismo.",
"help-millions": "Sin embargo, con un presupuesto de tan sólo unos cientos de miles de dólares al año, hemos podido ayudar a millones de personas.",
"how-one-time": "¿Cómo puedo realizar una donación única?",
"one-time": "Si prefieres hacer donaciones únicas, puedes apoyar la misión de freeCodeCamp cuando tengas dinero suficiente para hacer una aportación. Puedes usar <0>este enlace para donar cualquier cantidad que te sea cómodo a través de PayPal0>.",
@@ -400,7 +407,7 @@
"can-check": "¿Puedo enviar un cheque físico?",
"yes-check": "Sí, bienvenido sea, aceptamos cheque. Puedes enviarlo a:",
"how-matching-gift": "¿Cómo puedo configurar regalos coincidentes de mi empleador o deducciones de nómina?",
- "employers-vary": "Esto varía de un empleador a otro, y nuestra organización sin fines de lucro ya se encuentra en muchas de las bases de datos que se ajustan a las grandes donaciones.",
+ "employers-vary": "This varies from employer to employer, and our charity is already listed in many of the big donation-matching databases.",
"some-volunteer": "Algunas personas tienen la posibilidad de ser voluntarias para freeCodeCamp y su empleador iguala al donar una cantidad fija por hora que ofrecen como voluntarios. Otros empleadores igualan cualquier donación que los donantes hagan hasta una cierta cantidad",
"help-matching-gift": "Si necesitas ayuda con esto, por favor envía un correo electrónico a Quincy directamente: quincy@freecodecamp.org",
"how-endowment": "¿Cómo puedo hacer un regalo de dotación a freeCodeCamp.org?",
@@ -411,13 +418,13 @@
"thank-wikimedia": "Nos gustaría dar las gracias a la Fundación Wikimedia por proporcionar este lenguaje formal para que podamos utilizarlo.",
"legacy-gift-questions": "Si tienes alguna pregunta sobre este proceso, por favor envía un correo electrónico a Quincy@freecodecamp.org.",
"how-stock": "¿Cómo puedo donar acciones a freeCodeCamp.org?",
- "welcome-stock": "Agradeceríamos tus donaciones de acciones. Por favor envía un correo electrónico a Quincy directamente y él puede ayudarte con esto, y compartir los detalles de nuestra cuenta de corretaje sin fines de lucro: quincy@freecodecamp.org.",
+ "welcome-stock": "We would welcome your stock donations. Please email Quincy directly and he can help you with this, and share our charity's brokerage account details: quincy@freecodecamp.org.",
"how-receipt": "¿Puedo obtener un recibo de donación para que pueda deducir mi donación de mis impuestos?",
"just-forward": "Claro que sí. Solo reenvía el recibo de tu transacción a donors@freecodecamp.org, menciónanos que deseas un recibo y cualquier otra instrucción especial que puedas tener, y te contestaremos con un recibo por ti.",
"how-update": "He configurado una donación mensual, pero necesito actualizar o pausar la recurrencia mensual. ¿Cómo puedo hacerlo?",
"take-care-of-this": "Manda uno de tus recibos mensuales de donación a donors@freecodecamp.org y dinos lo que te gustaría que hiciéramos. Nos ocuparemos de esto y te enviaremos confirmación.",
"anything-else": "¿Hay algo más que pueda aprender sobre cómo hacer una donación a freeCodeCamp.org?",
- "other-support": "Si hay alguna otra forma en la que te gustaría apoyar a nuestra organización sin fines de lucro y su misión que no aparece aquí, o si tienes alguna pregunta, envía un correo electrónico a Quincy a quincy@freecodecamp.org."
+ "other-support": "If there is some other way you'd like to support our charity and its mission that isn't listed here, or if you have any questions at all, please email Quincy at quincy@freecodecamp.org."
},
"report": {
"sign-in": "Necesitas iniciar sesión para reportar a un usuario",
@@ -460,7 +467,8 @@
"iframe-preview": "{{title}} Vista previa",
"iframe-alert": "¡Normalmente este link te llevaría a otro sitio web! Funciona. Este es un enlace a: {{externalLink}}",
"iframe-form-submit-alert": "¡Normalmente, se enviaría este formulario! Funciona. Esto se enviará a: {{externalLink}}",
- "document-notfound": "documento no encontrado"
+ "document-notfound": "documento no encontrado",
+ "slow-load-msg": "Looks like this is taking longer than usual, please try refreshing the page."
},
"icons": {
"gold-cup": "Copa de Oro",
@@ -475,10 +483,11 @@
"hint": "Sugerencia",
"heart": "Corazón",
"initial": "Inicial",
+ "input-reset": "Clear search terms",
"info": "Información de introducción",
"spacer": "Espaciador",
"toggle": "Alternar marca de verificación",
- "magnifier": "lupa"
+ "magnifier": "Submit search terms"
},
"aria": {
"fcc-curriculum": "currículo de freeCodeCamp",
@@ -504,10 +513,11 @@
"step": "Paso",
"steps": "Pasos",
"steps-for": "Pasos para {{blockTitle}}",
- "code-example": "{{codeName}} code example"
+ "code-example": "ejemplo de código de {{codeName}}",
+ "opens-new-window": "Opens in new window"
},
"flash": {
- "honest-first": "Para reclamar una certificación, primero debes aceptar nuestra política de honestidad académica.",
+ "honest-first": "To claim a certification, you must first agree to our academic honesty policy",
"really-weird": "Sucedió algo realmente extraño. Si vuelve a ocurrir, considera hacer un reporte del problema en https://github.com/freeCodeCamp/freeCodeCamp/issues/new",
"not-right": "Algo no está bien. Se ha generado un informe y se ha notificado al equipo de freeCodeCamp.org",
"went-wrong": "Algo salió mal, verifica e intenta nuevamente",
@@ -586,7 +596,8 @@
"editor-url": "Recuerda enviar la URL de Live App.",
"http-url": "No se puede utilizar una URL insegura (http).",
"own-work-url": "Recuerda enviar tu propio trabajo.",
- "publicly-visible-url": "Recuerda enviar una URL de aplicación visible públicamente."
+ "publicly-visible-url": "Recuerda enviar una URL de aplicación visible públicamente.",
+ "path-url": "You probably want to submit the root path i.e. https://example.com, not https://example.com/path"
},
"certification": {
"executive": "Director Ejecutivo, freeCodeCamp.org",
@@ -668,8 +679,49 @@
"Cat and Dog Image Classifier": "Clasificador de imágenes de gatos y perros",
"Book Recommendation Engine using KNN": "Motor de recomendación de libros usando KNN",
"Linear Regression Health Costs Calculator": "Calculadora de costos de salud por regresión lineal",
- "Neural Network SMS Text Classifier": "Clasificador de textos SMS basado en redes neuronales"
+ "Neural Network SMS Text Classifier": "Clasificador de textos SMS basado en redes neuronales",
+ "Celestial Bodies Database": "Celestial Bodies Database",
+ "World Cup Database": "World Cup Database",
+ "Salon Appointment Scheduler": "Salon Appointment Scheduler",
+ "Periodic Table Database": "Periodic Table Database",
+ "Number Guessing Game": "Number Guessing Game",
+ "Build a freeCodeCamp Forum Homepage": "Build a freeCodeCamp Forum Homepage"
}
+ },
+ "title": {
+ "Responsive Web Design": "Responsive Web Design",
+ "responsive-web-design": "Responsive Web Design Certification",
+ "JavaScript Algorithms and Data Structures": "JavaScript Algorithms and Data Structures",
+ "javascript-algorithms-and-data-structures": "JavaScript Algorithms and Data Structures Certification",
+ "Front End Development Libraries": "Front End Development Libraries",
+ "front-end-development-libraries": "Front End Development Libraries Certification",
+ "Data Visualization": "Data Visualization",
+ "data-visualization": "Data Visualization Certification",
+ "Relational Database": "Relational Database",
+ "relational-database-v8": "Relational Database Certification",
+ "Back End Development and APIs": "Back End Development and APIs",
+ "back-end-development-and-apis": "Back End Development and APIs Certification",
+ "Quality Assurance": "Quality Assurance",
+ "quality-assurance-v7": "Quality Assurance Certification",
+ "Scientific Computing with Python": "Scientific Computing with Python",
+ "scientific-computing-with-python-v7": "Scientific Computing with Python Certification",
+ "Data Analysis with Python": "Data Analysis with Python",
+ "data-analysis-with-python-v7": "Data Analysis with Python Certification",
+ "Information Security": "Information Security",
+ "information-security-v7": "Information Security Certification",
+ "Machine Learning with Python": "Machine Learning with Python",
+ "machine-learning-with-python-v7": "Machine Learning with Python Certification",
+ "Legacy Front End": "Legacy Front End",
+ "legacy-front-end": "Front End Certification",
+ "Legacy Back End": "Legacy Back End",
+ "legacy-back-end": "Back End Certification",
+ "Legacy Data Visualization": "Legacy Data Visualization",
+ "legacy-data-visualization": "Data Visualization Certification",
+ "Legacy Information Security and Quality Assurance": "Legacy Information Security and Quality Assurance",
+ "information-security-and-quality-assurance": "Information Security and Quality Assurance Certification",
+ "Legacy Full Stack Certification": "Legacy Full Stack Certification",
+ "Legacy Full Stack": "Legacy Full Stack",
+ "full-stack": "Full Stack Certification"
}
},
"certification-card": {
diff --git a/client/i18n/locales/german/intro.json b/client/i18n/locales/german/intro.json
index c7337e2d451230..b23ae9ad6e77b0 100644
--- a/client/i18n/locales/german/intro.json
+++ b/client/i18n/locales/german/intro.json
@@ -335,6 +335,10 @@
"learn-functional-programming-by-building-a-spreadsheet": {
"title": "Lerne die funktionale Programmierung durch das Erstellen einer Tabellenkalkulation",
"intro": ["", ""]
+ },
+ "learn-advanced-array-methods-by-building-a-statistics-calculator": {
+ "title": "Learn Advanced Array Methods by Building a Statistics Calculator",
+ "intro": ["", ""]
}
}
},
@@ -553,7 +557,7 @@
"intro": [
"Bis zu diesem Punkt hast du JavaScript nur im Front-End verwendet, um einer Seite Interaktivität hinzuzufügen, Aufgaben mit Algorithmen zu lösen oder eine SPA zu bauen. Aber JavaScript kann auch im Back-End, also auf dem Server, verwendet werden, um ganze Webanwendungen zu erstellen.",
"Heutzutage ist eine der beliebtesten Arten, Anwendungen zu erstellen, Microservices. Das sind kleine, modulare Anwendungen, die zusammenarbeiten und ein größeres Ganzes bilden.",
- "In der Zertifizierung für Back-End-Entwicklung und APIs lernst du, wie du Back-End-Apps mit Node.js und npm (Node Package Manager) schreibst. Du wirst auch Webanwendungen mit dem Express-Framework erstellen und einen Personensuche-Microservice mit MongoDB und der Mongoose-Bibliothek bauen."
+ "In the Back End Development and APIs Certification, you'll learn how to write back end apps with Node.js and npm. You'll also build web applications with the Express framework, and build a People Finder microservice with MongoDB and the Mongoose library."
],
"note": "",
"blocks": {
@@ -787,6 +791,24 @@
}
}
},
+ "the-odin-project": {
+ "title": "The Odin Project",
+ "intro": [
+ "The Odin Project is one of those \"What I wish I had when I was learning\" resources. ",
+ "Not everyone has access to a computer science education or the funds to attend an intensive coding school and neither of those is right for everyone anyway.",
+ "This project is designed to fill in the gap for people who are trying to hack it on their own but still want a high quality education."
+ ],
+ "blocks": {
+ "top-learn-html-foundations": {
+ "title": "Learn HTML Foundations",
+ "intro": ["A description is to be determined"]
+ },
+ "top-build-a-recipe-project": {
+ "title": "Learn HTML Foundations by Building a Recipe Page",
+ "intro": ["A description is to be determined"]
+ }
+ }
+ },
"misc-text": {
"certification": "{{cert}} Zertifikat",
"browse-other": "Stöbere in unseren anderen kostenlosen Zertifizierungen\n(Wir empfehlen, diese der Reihe nach zu erledigen)",
diff --git a/client/i18n/locales/german/translations.json b/client/i18n/locales/german/translations.json
index 3b59be781e9e2a..0aa7823c328f31 100644
--- a/client/i18n/locales/german/translations.json
+++ b/client/i18n/locales/german/translations.json
@@ -11,11 +11,12 @@
"view": "Anzeigen",
"view-code": "Code anschauen",
"view-project": "Projekt anschauen",
+ "view-cert-title": "View {{certTitle}}",
"show-cert": "Zertifikat anzeigen",
"claim-cert": "Zertifizierung anfordern",
"save-progress": "Fortschritt speichern",
- "accepted-honesty": "Du hast unsere Akademische Ehrlichkeitsrichtlinie akzeptiert.",
- "agree": "Zustimmen",
+ "accepted-honesty": "You have agreed to our Academic Honesty Policy.",
+ "agree-honesty": "I agree to freeCodeCamp's Academic Honesty Policy.",
"save-portfolio": "Dieses Portfolioelement speichern",
"remove-portfolio": "Dieses Portfolioelement entfernen",
"add-portfolio": "Neues Portfolioelement hinzufügen",
@@ -52,7 +53,7 @@
"check-code": "Überprüfe deinen Code (Strg + Enter)",
"check-code-2": "Prüfe deinen Code",
"reset": "Zurücksetzen",
- "reset-code": "Den Quellcode zurücksetzen",
+ "reset-step": "Reset This Step",
"help": "Hilfe",
"get-help": "Hilfe bekommen",
"watch-video": "Ein Video ansehen",
@@ -157,7 +158,8 @@
"honesty": "Akademischer Ehrlichkeitskodex",
"internet": "Dein Internetauftritt",
"portfolio": "Portfolio-Einstellungen",
- "privacy": "Privatsphäre-Einstellungen"
+ "privacy": "Privatsphäre-Einstellungen",
+ "personal-info": "Personal Information"
},
"danger": {
"heading": "Gefahrenzone",
@@ -222,16 +224,15 @@
"total-points_plural": "{{count}} Gesamtpunkte",
"points": "{{count}} Punkt am {{date}}",
"points_plural": "{{count}} Punkte am {{date}}",
- "screen-shot": "Eine Bildschirmaufnahme von {{title}}",
"page-number": "{{pageNumber}} von {{totalPages}}"
},
"footer": {
- "tax-exempt-status": "freeCodeCamp ist eine von Spendern unterstützte steuerbefreite gemeinnützige Organisation gemäß 501(c)(3) (US-Steueridentifikationsnummer: 82-0779546)",
+ "tax-exempt-status": "freeCodeCamp is a donor-supported tax-exempt 501(c)(3) charitable organization (United States Federal Tax Identification Number: 82-0779546)",
"mission-statement": "Unsere Mission: Menschen dabei zu helfen, kostenlos zu programmieren. Dies erreichen wir, indem wir Tausende von Videos, Artikeln und interaktiven Programmierstunden erstellen, die der Öffentlichkeit frei zugänglich sind. Wir haben auch Tausende von freeCodeCamp-Lerngruppen auf der ganzen Welt.",
"donation-initiatives": "Spenden an das freeCodeCamp fließen in unsere Bildungsinitiativen und helfen, Server, Dienstleistungen und Mitarbeiter zu bezahlen.",
"donate-text": "Du kannst <1>hier eine steuerlich absetzbare Spende tätigen1>.",
"trending-guides": "Beliebte Guides",
- "our-nonprofit": "Unser Non-Profit",
+ "our-nonprofit": "Our Charity",
"links": {
"about": "Über",
"alumni": "Alumni-Netzwerk",
@@ -249,6 +250,7 @@
},
"learn": {
"heading": "Willkommen zum Studienplan von freeCodeCamp.",
+ "skip-to-content": "Skip to content",
"welcome-1": "Willkommen zurück, {{name}}.",
"welcome-2": "Willkommen auf freeCodeCamp.org",
"start-at-beginning": "Wenn Programmieren ganz neu für dich ist, schlagen wir vor, <0>am Anfang zu beginnen0>.",
@@ -272,6 +274,9 @@
"add-subtitles": "Hilf mit Untertitel hinzuzufügen oder zu verbessern",
"wrong-answer": "Sorry, das ist nicht die richtige Antwort. Möchtest du noch einen Anlauf wagen?",
"check-answer": "Klick unten auf den Button, um deine Antwort zu überprüfen.",
+ "assignment-not-complete": "Please finish the assignments",
+ "assignments": "Assignments",
+ "question": "Question",
"solution-link": "Lösungs-Link",
"github-link": "GitHub Link",
"submit-and-go": "Absenden und zur nächsten Herausforderung gehen",
@@ -297,7 +302,6 @@
"certs": "{{title}} Zertifizierung"
},
"editor-tabs": {
- "info": "Informationen",
"code": "Code",
"tests": "Tests",
"restart": "Neustart",
@@ -307,6 +311,10 @@
"notes": "Hinweise",
"preview": "Vorschau"
},
+ "editor-alerts": {
+ "tab-trapped": "Pressing tab will now insert the tab character",
+ "tab-free": "Pressing tab will now move focus to the next focusable element"
+ },
"help-translate": "Wir übersetzen noch die folgenden Zertifikate.",
"help-translate-link": "Hilf uns, zu übersetzen.",
"project-preview-title": "Hier ist eine Vorschau auf das, was du erstellen wirst",
@@ -327,15 +335,15 @@
"sorry-dont-giveup": "Tut mir leid, dein Code funktioniert nicht. Gib nicht auf.",
"challenges-completed": "{{completedCount}} von {{totalChallenges}} Herausforderungen erfüllt",
"season-greetings-fcc": "Season's Greetings from the freeCodeCamp community 🎉",
- "if-getting-value": "If you're getting a lot out of freeCodeCamp, now is a great time to donate to support our nonprofit's mission.",
+ "if-getting-value": "If you're getting a lot out of freeCodeCamp, now is a great time to donate to support our charity's mission.",
"building-a-university": "We're Building a Free Computer Science University Degree Program",
"if-help-university": "We've already made a ton of progress. Support our charity with the long road ahead."
},
"donate": {
- "title": "Unterstütze unsere Non-Profit-Organisation",
+ "title": "Support our charity",
"processing": "Wir bearbeiten deine Spende.",
"redirecting": "Weiterleiten...",
- "thanks": "Vielen Dank für die Spende",
+ "thanks": "Thanks for donating",
"thank-you": "Vielen Dank für deine Unterstützung.",
"additional": "Du kannst eine zusätzliche einmalige Spende in beliebiger Höhe über diesen Link tätigen: <0>{{url}}0>",
"help-more": "Hilf uns, mehr zu tun",
@@ -355,10 +363,9 @@
"your-donation-2": "Deine ${{usd}} Spende wird jeden Monat {{hours}} Stunden des Lernens für Menschen auf der ganzen Welt ermöglichen.",
"your-donation-3": "Deine ${{usd}} Spende wird jedes Jahr {{hours}} Stunden des Lernens für Menschen auf der ganzen Welt ermöglichen.",
"become-supporter": "Become a Supporter",
- "duration": "Werde ein einmaliger Unterstützer für unsere gemeinnützigen Organisation.",
- "duration-2": "Werde ein monatlicher Unterstützer für unsere gemeinnützigen Organisation.",
- "duration-3": "Werde ein jährlicher Unterstützer für unsere gemeinnützigen Organisation",
- "duration-4": "Werde ein Unterstützer für unsere gemeinnützigen Organisation",
+ "duration": "Become a one-time supporter of our charity.",
+ "duration-2": "Become a monthly supporter of our charity.",
+ "duration-4": "Become a supporter of our charity",
"nicely-done": "Großartig. Du hast soeben {{block}} abgeschlossen.",
"credit-card": "Kreditkarte",
"credit-card-2": "Oder spende mit einer Kreditkarte:",
@@ -372,25 +379,25 @@
"email-receipt": "E-Mail (wir schicken dir eine steuerlich absetzbare Spendenquittung):",
"need-help": "Brauchst du Hilfe bei deinen aktuellen oder vergangenen Spenden?",
"forward-receipt": "Sende uns eine Kopie deiner Spendenbescheinigung an donors@freecodecamp.org und lass uns wissen, wie wir dir helfen können.",
- "efficiency": "freeCodeCamp ist eine hocheffiziente, gemeinnützige Bildungsorganisation.",
+ "efficiency": "freeCodeCamp is a highly efficient education charity.",
"why-donate-1": "Wenn du für freeCodeCamp spendest, hilfst du Menschen, neue Fähigkeiten zu erlernen und ihre Familien zu versorgen.",
"why-donate-2": "Du hilfst uns auch neue Angebote zu schaffen, die du selbst nutzen kannst, um deine technischen Fähigkeiten zu erweitern.",
"bigger-donation": "Möchtest du eine größere einmalige Spende tätigen, uns einen Scheck schicken oder auf andere Weise spenden?",
- "other-ways": "Hier sind viele <0>andere Möglichkeiten, wie du die Mission unserer gemeinnützigen Organisation unterstützen kannst0>.",
+ "other-ways": "Here are many <0>other ways you can support our charity's mission0>.",
"failed-pay": "Oh - oh. Es sieht so aus, als ob deine Transaktion nicht durchgeführt werden konnte. Kannst du es bitte noch einmal versuchen?",
"try-again": "Bitte versuche es erneut.",
"card-number": "Deine Kartennummer:",
"expiration": "Ablaufdatum:",
"secure-donation": "Sichere Spende",
"faq": "Häufig gestellte Fragen",
- "only-you": "Nur du kannst diese Nachricht sehen. Herzlichen Glückwunsch zum Erhalt dieses Zertifikats. Es ist keine leichte Aufgabe. Das freeCodeCamp zu leiten, ist auch nicht einfach. Und billig ist es auch nicht. Hilf uns, dir und vielen anderen Menschen auf der ganzen Welt zu helfen. Sende noch heute eine steuerlich absetzbare Spende an unsere gemeinnützige Organisation.",
+ "only-you": "Only you can see this message. Congratulations on earning this certification. It's no easy task. Running freeCodeCamp isn't easy either. Nor is it cheap. Help us help you and many other people around the world. Make a tax-deductible supporting donation to our charity today.",
"get-help": "Wie kann ich Hilfe für meine Spenden bekommen?",
"how-transparent": "Wie transparent ist freeCodeCamp.org?",
"very-transparent": "Sehr. Wir haben eine Platin-Transparenzbewertung von GuideStar.org.",
"download-irs": "Du kannst <0>unseren Feststellungsbescheid der IRS hier herunterladen0>.",
"download-990": "Du kannst <0>hier unseren letzten 990 (Jahressteuerbericht) herunterladen0>.",
"how-efficient": "Wie effizient ist das freeCodeCamp?",
- "fcc-budget": "Das Budget von freeCodeCamp ist viel kleiner als das der meisten vergleichbaren gemeinnützigen Organisationen. Wir haben keine professionellen Geldbeschaffer eingestellt. Stattdessen macht Quincy alles selbst.",
+ "fcc-budget": "freeCodeCamp's budget is much smaller than most comparable charity. We haven't brought in professional fundraisers. Instead, Quincy does everything himself.",
"help-millions": "Doch mit einem Budget von nur ein paar hunderttausend Dollar pro Jahr konnten wir Millionen von Menschen helfen.",
"how-one-time": "Wie kann ich eine einmalige Spende leisten?",
"one-time": "Wenn du lieber einmalig spenden möchtest, kannst du die Mission von freeCodeCamp unterstützen, wann immer du Geld übrig hast. Du kannst <0>diesen Link benutzen, um einen beliebigen Betrag über PayPal0> zu spenden.",
@@ -400,7 +407,7 @@
"can-check": "Kann ich einen Scheck per Post schicken?",
"yes-check": "Ja, wir würden uns über einen Scheck freuen. Du kannst ihn per Post an uns schicken:",
"how-matching-gift": "Wie kann ich die gleiche Spende von meinem Arbeitgeber erhalten oder von der Gehaltsabrechnung abziehen lassen?",
- "employers-vary": "Das ist von Arbeitgeber zu Arbeitgeber unterschiedlich, und unsere gemeinnützige Organisation ist bereits in vielen der großen Spenden-Datenbanken gelistet.",
+ "employers-vary": "This varies from employer to employer, and our charity is already listed in many of the big donation-matching databases.",
"some-volunteer": "Manche Menschen können sich bei freeCodeCamp freiwillig engagieren und ihr Arbeitgeber spendet einen festen Betrag pro Stunde, in der sie sich freiwillig engagieren. Andere Arbeitgeber verdoppeln die Spenden der Spender bis zu einem bestimmten Betrag",
"help-matching-gift": "Wenn du dabei Hilfe brauchst, schreibe Quincy bitte direkt eine E-Mail: quincy@freecodecamp.org",
"how-endowment": "Wie kann ich freeCodeCamp.org eine Spende zukommen lassen?",
@@ -411,13 +418,13 @@
"thank-wikimedia": "Wir möchten uns bei der Wikimedia Foundation dafür bedanken, dass sie uns diese formelle Formulierung zur Verfügung gestellt hat.",
"legacy-gift-questions": "Wenn du Fragen zu diesem Verfahren hast, schreibe bitte eine E-Mail an Quincy unter quincy@freecodecamp.org.",
"how-stock": "Wie kann ich Aktien für freeCodeCamp.org spenden?",
- "welcome-stock": "Wir nehmen deine Aktienspenden gerne entgegen. Schreib Quincy direkt eine E-Mail und er kann dir dabei helfen und dir die Details unseres gemeinnützigen Maklerkontos mitteilen: quincy@freecodecamp.org.",
+ "welcome-stock": "We would welcome your stock donations. Please email Quincy directly and he can help you with this, and share our charity's brokerage account details: quincy@freecodecamp.org.",
"how-receipt": "Kann ich eine Spendenbescheinigung bekommen, damit ich meine Spende von der Steuer absetzen kann?",
"just-forward": "Ja, natürlich. Schicke einfach die Quittung deiner Transaktion an donors@freecodecamp.org, sag uns, dass du eine Quittung möchtest und welche besonderen Anweisungen du hast, und wir schicken dir eine Quittung zu.",
"how-update": "Ich habe eine monatliche Spende eingerichtet, aber ich muss die monatliche Zahlung aktualisieren oder aussetzen. Wie kann ich das tun?",
"take-care-of-this": "Schicke einfach eine deiner monatlichen Spendenquittungen an donors@freecodecamp.org und sag uns, was wir für dich tun sollen. Wir erledigen das für dich und schicken dir eine Bestätigung.",
"anything-else": "Gibt es noch etwas, was ich über das Spenden an freeCodeCamp.org erfahren kann?",
- "other-support": "Wenn es eine andere Möglichkeit gibt, unsere gemeinnützige Organisation zu unterstützen, die hier nicht aufgeführt ist, oder wenn du Fragen hast, schreibe bitte eine E-Mail an Quincy unter quincy@freecodecamp.org."
+ "other-support": "If there is some other way you'd like to support our charity and its mission that isn't listed here, or if you have any questions at all, please email Quincy at quincy@freecodecamp.org."
},
"report": {
"sign-in": "Du musst angemeldet sein, um einen Benutzer zu melden",
@@ -460,7 +467,8 @@
"iframe-preview": "{{title}} Vorschau",
"iframe-alert": "Normalerweise würde dieser Link dich auf eine andere Website führen! Er funktioniert. Dies ist ein Link zu: {{externalLink}}",
"iframe-form-submit-alert": "Normalerweise würde dieses Formular übermittelt werden! Es funktioniert. Dies wird übermittelt an: {{externalLink}}",
- "document-notfound": "Dokument wurde nicht gefunden"
+ "document-notfound": "Dokument wurde nicht gefunden",
+ "slow-load-msg": "Looks like this is taking longer than usual, please try refreshing the page."
},
"icons": {
"gold-cup": "Goldpokal",
@@ -475,10 +483,11 @@
"hint": "Hinweis",
"heart": "Herz",
"initial": "Initial",
+ "input-reset": "Clear search terms",
"info": "Einführungsinformationen",
"spacer": "Abstandhalter",
"toggle": "Häkchen umschalten",
- "magnifier": "Lupe"
+ "magnifier": "Submit search terms"
},
"aria": {
"fcc-curriculum": "freeCodeCamp Studienplan",
@@ -504,10 +513,11 @@
"step": "Schritt",
"steps": "Schritte",
"steps-for": "Schritte für {{blockTitle}}",
- "code-example": "{{codeName}} code example"
+ "code-example": "{{codeName}} code example",
+ "opens-new-window": "Opens in new window"
},
"flash": {
- "honest-first": "Um eine Zertifizierung zu erlangen, musst du zunächst unsere Richtlinie zur akademischen Ehrlichkeit akzeptieren",
+ "honest-first": "To claim a certification, you must first agree to our academic honesty policy",
"really-weird": "Etwas wirklich Seltsames ist passiert. Wenn es wieder passiert, erwäge bitte, einen Fehler auf https://github.com/freeCodeCamp/freeCodeCamp/issues/new zu melden.",
"not-right": "Irgendetwas ist nicht in Ordnung. Es wurde ein Bericht erstellt und das freeCodeCamp.org Team wurde benachrichtigt",
"went-wrong": "Etwas ist schief gelaufen, bitte überprüfe und versuche es erneut",
@@ -586,7 +596,8 @@
"editor-url": "Denke daran, die Live App URL einzureichen.",
"http-url": "Eine unsichere (http) URL kann nicht verwendet werden.",
"own-work-url": "Denke daran, deine eigene Arbeit einzureichen.",
- "publicly-visible-url": "Denke daran, eine öffentlich sichtbare App-URL einzureichen."
+ "publicly-visible-url": "Denke daran, eine öffentlich sichtbare App-URL einzureichen.",
+ "path-url": "You probably want to submit the root path i.e. https://example.com, not https://example.com/path"
},
"certification": {
"executive": "Geschäftsführender Direktor, freeCodeCamp.org",
@@ -668,8 +679,49 @@
"Cat and Dog Image Classifier": "Katzen- und Hundebildklassifizierer",
"Book Recommendation Engine using KNN": "Buchempfehlungsmaschine mithilfe von KNN",
"Linear Regression Health Costs Calculator": "Gesundheitskostenrechner mit einer linearen Regression",
- "Neural Network SMS Text Classifier": "SMS-Textklassifizierung mittels neuronalem Netzwerk"
+ "Neural Network SMS Text Classifier": "SMS-Textklassifizierung mittels neuronalem Netzwerk",
+ "Celestial Bodies Database": "Celestial Bodies Database",
+ "World Cup Database": "World Cup Database",
+ "Salon Appointment Scheduler": "Salon Appointment Scheduler",
+ "Periodic Table Database": "Periodic Table Database",
+ "Number Guessing Game": "Number Guessing Game",
+ "Build a freeCodeCamp Forum Homepage": "Build a freeCodeCamp Forum Homepage"
}
+ },
+ "title": {
+ "Responsive Web Design": "Responsive Web Design",
+ "responsive-web-design": "Responsive Web Design Certification",
+ "JavaScript Algorithms and Data Structures": "JavaScript Algorithms and Data Structures",
+ "javascript-algorithms-and-data-structures": "JavaScript Algorithms and Data Structures Certification",
+ "Front End Development Libraries": "Front End Development Libraries",
+ "front-end-development-libraries": "Front End Development Libraries Certification",
+ "Data Visualization": "Data Visualization",
+ "data-visualization": "Data Visualization Certification",
+ "Relational Database": "Relational Database",
+ "relational-database-v8": "Relational Database Certification",
+ "Back End Development and APIs": "Back End Development and APIs",
+ "back-end-development-and-apis": "Back End Development and APIs Certification",
+ "Quality Assurance": "Quality Assurance",
+ "quality-assurance-v7": "Quality Assurance Certification",
+ "Scientific Computing with Python": "Scientific Computing with Python",
+ "scientific-computing-with-python-v7": "Scientific Computing with Python Certification",
+ "Data Analysis with Python": "Data Analysis with Python",
+ "data-analysis-with-python-v7": "Data Analysis with Python Certification",
+ "Information Security": "Information Security",
+ "information-security-v7": "Information Security Certification",
+ "Machine Learning with Python": "Machine Learning with Python",
+ "machine-learning-with-python-v7": "Machine Learning with Python Certification",
+ "Legacy Front End": "Legacy Front End",
+ "legacy-front-end": "Front End Certification",
+ "Legacy Back End": "Legacy Back End",
+ "legacy-back-end": "Back End Certification",
+ "Legacy Data Visualization": "Legacy Data Visualization",
+ "legacy-data-visualization": "Data Visualization Certification",
+ "Legacy Information Security and Quality Assurance": "Legacy Information Security and Quality Assurance",
+ "information-security-and-quality-assurance": "Information Security and Quality Assurance Certification",
+ "Legacy Full Stack Certification": "Legacy Full Stack Certification",
+ "Legacy Full Stack": "Legacy Full Stack",
+ "full-stack": "Full Stack Certification"
}
},
"certification-card": {
diff --git a/client/i18n/locales/italian/intro.json b/client/i18n/locales/italian/intro.json
index 8145eb32773fab..981a10c35ce4f6 100644
--- a/client/i18n/locales/italian/intro.json
+++ b/client/i18n/locales/italian/intro.json
@@ -166,7 +166,7 @@
]
},
"learn-css-flexbox-by-building-a-photo-gallery": {
- "title": "Impara il Flexbox CSS costruendo una fotogallery",
+ "title": "Impara Flexbox CSS costruendo una fotogallery",
"intro": [
"Flexbox ti aiuta a progettare la tua pagina web in modo che vada bene su qualsiasi dimensione dello schermo.",
"In questo corso, utilizzerai Flexbox per creare una pagina web di una galleria fotografica reattiva."
@@ -335,6 +335,10 @@
"learn-functional-programming-by-building-a-spreadsheet": {
"title": "Impara programmazione funzionale creando un foglio di calcolo",
"intro": ["", ""]
+ },
+ "learn-advanced-array-methods-by-building-a-statistics-calculator": {
+ "title": "Learn Advanced Array Methods by Building a Statistics Calculator",
+ "intro": ["", ""]
}
}
},
@@ -553,7 +557,7 @@
"intro": [
"Fino a questo punto, hai usato solo JavaScript sul front-end per aggiungere interattività a una pagina, risolvere sfide algoritmiche o costruire una Single Page Application. Ma JavaScript può essere utilizzato anche nel backend (cioè lato server), per costruire intere applicazioni web.",
"Oggi, uno dei modi più popolari per costruire applicazioni è attraverso i microservizi, che sono piccole applicazioni modulari che lavorano insieme per formare qualcosa di più grande.",
- "Nella Certificazione Sviluppo Back End e API, imparerai a scrivere app per il backend con Node.js e npm (Node Package Manager). Costruirai anche applicazioni web con il framework Express, e costruirai un microservizio Trova Persone con MongoDB e la libreria Mongoose."
+ "Nella Certificazione Sviluppo Back End e API, imparerai a scrivere app per il backend con Node.js e npm. Costruirai anche applicazioni web con il framework Express, e costruirai un microservizio Trova Persone con MongoDB e la libreria Mongoose."
],
"note": "",
"blocks": {
@@ -787,6 +791,24 @@
}
}
},
+ "the-odin-project": {
+ "title": "The Odin Project",
+ "intro": [
+ "The Odin Project è una di quelle risorse che \"avrei voluto mentre stavo imparando\". ",
+ "Non tutti hanno accesso a un'educazione all'informatica o ai fondi per frequentare una scuola intensiva di programmazione e, in ogni caso, sono soluzioni non adatte a tutti.",
+ "Questo progetto è stato ideato per colmare il vuoto per le persone che stanno cercando di farcela da sole ma desiderano un'istruzione di alta qualità."
+ ],
+ "blocks": {
+ "top-learn-html-foundations": {
+ "title": "Impara i Fondamenti di HTML",
+ "intro": ["A description is to be determined"]
+ },
+ "top-build-a-recipe-project": {
+ "title": "Impara i Fondamenti di HTML Creando una Pagina di Ricette",
+ "intro": ["A description is to be determined"]
+ }
+ }
+ },
"misc-text": {
"certification": "Certificazione {{cert}}",
"browse-other": "Sfoglia le altre nostre certificazioni gratuite\n(consigliamo di seguirle in ordine)",
diff --git a/client/i18n/locales/italian/translations.json b/client/i18n/locales/italian/translations.json
index b0a17f480911fa..b4a25a5c6470dc 100644
--- a/client/i18n/locales/italian/translations.json
+++ b/client/i18n/locales/italian/translations.json
@@ -11,11 +11,12 @@
"view": "Visualizza",
"view-code": "Visualizza il Codice",
"view-project": "Visualizza il Progetto",
+ "view-cert-title": "Visualizza {{certTitle}}",
"show-cert": "Mostra la Certificazione",
"claim-cert": "Richiedi la Certificazione",
"save-progress": "Salva l'avanzamento",
"accepted-honesty": "Hai accettato la nostra Politica di Onestà Accademica.",
- "agree": "Accetta",
+ "agree-honesty": "Accetto la Politica di Onestà Accademica di freeCodeCamp.",
"save-portfolio": "Salva questo elemento del portfolio",
"remove-portfolio": "Rimuovi questo elemento del portfolio",
"add-portfolio": "Aggiungi un nuovo elemento nel portfolio",
@@ -52,7 +53,7 @@
"check-code": "Verifica il tuo codice (Ctrl + Invio)",
"check-code-2": "Verifica il tuo codice",
"reset": "Resetta",
- "reset-code": "Resetta tutto il codice",
+ "reset-step": "Resetta questo step",
"help": "Guida",
"get-help": "Ottieni Aiuto",
"watch-video": "Guarda un video",
@@ -80,7 +81,7 @@
"big-heading-1": "Impara a programmare — gratis.",
"big-heading-2": "Costruisci progetti.",
"big-heading-3": "Ottieni certificazioni.",
- "h2-heading": "Dal 2014, più di 40.000 laureati di freeCodeCamp.org hanno ottenuto posti di lavoro presso aziende tecnologiche, tra cui:",
+ "h2-heading": "Dal 2014, più di 40.000 studenti di freeCodeCamp.org hanno ottenuto posti di lavoro presso aziende tecnologiche, tra cui:",
"hero-img-description": "Studenti di un gruppo di studio locale di freeCodeCamp in Corea del Sud.",
"as-seen-in": "Hanno parlato di noi:",
"testimonials": {
@@ -157,7 +158,8 @@
"honesty": "Politica di Onestà Accademica",
"internet": "La Tua presenza su Internet",
"portfolio": "Impostazioni Portfolio",
- "privacy": "Impostazioni Privacy"
+ "privacy": "Impostazioni Privacy",
+ "personal-info": "Informazioni personali"
},
"danger": {
"heading": "Zona di Pericolo",
@@ -222,16 +224,15 @@
"total-points_plural": "{{count}} punti totali",
"points": "{{count}} punto il {{date}}",
"points_plural": "{{count}} punti il {{date}}",
- "screen-shot": "Uno screenshot di {{title}}",
"page-number": "{{pageNumber}} di {{totalPages}}"
},
"footer": {
- "tax-exempt-status": "freeCodeCamp è un'organizzazione senza scopo di lucro (United States Federal Tax Identification Number: 82-0779546)",
+ "tax-exempt-status": "freeCodeCamp è un'organizzazione di beneficenza 501(c)(3) esentasse supportata da donazioni (Numero di identificazione per le tasse federali negli Stati Uniti d'America: 82-0779546)",
"mission-statement": "La nostra missione: aiutare le persone a imparare a programmare gratuitamente. Lo facciamo creando migliaia di video, articoli e lezioni di programmazione interattive - tutti liberamente disponibili al pubblico. Abbiamo anche migliaia di gruppi di studio freeCodeCamp in tutto il mondo.",
"donation-initiatives": "Le donazioni a freeCodeCamp vanno alle nostre iniziative educative e aiutano a pagare i server, i servizi e il personale.",
"donate-text": "Puoi fare una <1>donazione deducibile dalle tasse qui1>.",
"trending-guides": "Guide Di Tendenza",
- "our-nonprofit": "Il nostro nonprofit",
+ "our-nonprofit": "La nostra Charity",
"links": {
"about": "Informazioni",
"alumni": "Rete degli allievi",
@@ -249,6 +250,7 @@
},
"learn": {
"heading": "Benvenuti nel curriculum di freeCodeCamp.",
+ "skip-to-content": "Vai al contenuto",
"welcome-1": "Bentornato, {{name}}.",
"welcome-2": "Benvenuto su freeCodeCamp.org",
"start-at-beginning": "Se sei nuovo alla programmazione, ti consigliamo di <0>iniziare dall'inizio0>.",
@@ -272,6 +274,9 @@
"add-subtitles": "Aiuta a migliorare o aggiungi sottotitoli",
"wrong-answer": "Siamo spiacenti, non è la risposta giusta. Vuoi riprovare?",
"check-answer": "Fai clic sul pulsante qui sotto per controllare la tua risposta.",
+ "assignment-not-complete": "Per favore completa le attività",
+ "assignments": "Attività",
+ "question": "Domande",
"solution-link": "Link alla soluzione",
"github-link": "Link GitHub",
"submit-and-go": "Invia e vai alla prossima sfida",
@@ -297,7 +302,6 @@
"certs": "Certificazione {{title}}"
},
"editor-tabs": {
- "info": "Informazioni",
"code": "Codice",
"tests": "Test",
"restart": "Inizia da capo",
@@ -307,6 +311,10 @@
"notes": "Note",
"preview": "Anteprima"
},
+ "editor-alerts": {
+ "tab-trapped": "Premendo tab ora potrai inserire il carattere tab",
+ "tab-free": "Premendo tab ora potrai spostare il focus sull'elemento successivo"
+ },
"help-translate": "Stiamo ancora traducendo le seguenti certificazioni.",
"help-translate-link": "Aiutaci con le traduzioni...",
"project-preview-title": "Ecco una anticipazione di quello che creerai",
@@ -327,12 +335,12 @@
"sorry-dont-giveup": "Il tuo codice non è corretto. Non arrenderti.",
"challenges-completed": "{{completedCount}} di {{totalChallenges}} sfide completate",
"season-greetings-fcc": "Saluti dalla comunità freeCodeCamp 🎉",
- "if-getting-value": "Se stai trovando utile freeCodeCamp, è un ottimo momento per donare e sostenere la missione della nostra nonprofit.",
+ "if-getting-value": "Se stai trovando utile freeCodeCamp, è un ottimo momento per donare e sostenere la missione del nostro ente di beneficenza.",
"building-a-university": "Stiamo creando un corso di laurea gratuito in Scienze Informatiche",
"if-help-university": "Abbiamo già fatto tanti progressi. Sostieni il nostro ente benefico con la lunga strada che ci attende."
},
"donate": {
- "title": "Supporta il nostro no profit",
+ "title": "Supporta il nostro ente",
"processing": "Stiamo elaborando la tua donazione.",
"redirecting": "Reindirizzamento...",
"thanks": "Grazie per la donazione",
@@ -355,10 +363,9 @@
"your-donation-2": "La tua donazione ${{usd}} fornirà {{hours}} ore di apprendimento alle persone di tutto il mondo ogni mese.",
"your-donation-3": "La tua donazione di ${{usd}} fornirà {{hours}} ore di apprendimento a persone di tutto il mondo ogni anno.",
"become-supporter": "Diventa sostenitore",
- "duration": "Diventa un sostenitore una tantum del nostro non-profit.",
- "duration-2": "Diventa un sostenitore mensile del nostro non-profit.",
- "duration-3": "Diventa un sostenitore annuale del nostro no profit",
- "duration-4": "Diventa un sostenitore del nostro non-profit",
+ "duration": "Diventa un sostenitore una tantum del nostro ente di beneficenza.",
+ "duration-2": "Diventa un sostenitore mensile del nostro ente di beneficenza.",
+ "duration-4": "Diventa un sostenitore del nostro ente di beneficenza",
"nicely-done": "Ben fatto. Hai appena completato {{block}}.",
"credit-card": "Carta di credito",
"credit-card-2": "O dona con una carta di credito:",
@@ -372,25 +379,25 @@
"email-receipt": "Email (ti invieremo una ricevuta di donazione):",
"need-help": "Hai bisogno di aiuto con le tue donazioni attuali o passate?",
"forward-receipt": "Inoltra una copia della tua ricevuta di donazione a donors@freecodecamp.org e dicci come possiamo aiutarti.",
- "efficiency": "freeCodeCamp è una non-profit dell'educazione altamente efficiente.",
+ "efficiency": "freeCodeCamp è un'organizzazione altamente efficiente che si dedica all'educazione.",
"why-donate-1": "Quando doni a freeCodeCamp, aiuti tante persone a fare proprie nuove competenze e a prendersi cura delle loro famiglie.",
"why-donate-2": "Ci aiuterai anche a creare nuove risorse per te da utilizzare per espandere le tue abilità tecnologiche.",
"bigger-donation": "Vuoi fare una donazione una tantum più sostanziosa, inviarci un assegno o donare in altri modi?",
- "other-ways": "Qui ci sono molti <0>altri modi per supportare la nostra mission non-profit. 0>.",
+ "other-ways": "Qui ci sono molti <0>altri modi per supportare la missione del nostro ente di beneficenza0>.",
"failed-pay": "Uh - oh. Sembra che la tua transazione non sia passata. Potresti riprovare?",
"try-again": "Per favore riprova.",
"card-number": "Numero della tua Carta:",
"expiration": "Data di scadenza:",
"secure-donation": "Donazione sicura",
"faq": "Domande frequenti",
- "only-you": "Solo tu puoi vedere questo messaggio. Congratulazioni nell'aver ottenuto questa certificazione. Non è una cosa facile. Neanche mantenere attivo freeCodeCamp è facile. E non è neanche economico. Aiutaci ad aiutare te e tante altre persone attorno al mondo. Fai oggi una donazione per supportare la nostra noprofit.",
+ "only-you": "Solo tu puoi vedere questo messaggio. Congratulazioni per aver ottenuto questa certificazione. Non è una cosa facile. Neanche mantenere attivo freeCodeCamp è facile. E non è neanche economico. Aiutaci ad aiutare te e tante altre persone in tutto il mondo. Fai oggi una donazione per supportare la nostra organizzazione di beneficenza.",
"get-help": "Come posso ottenere aiuto con le mie donazioni?",
"how-transparent": "Quanto è trasparente freeCodeCamp.org?",
"very-transparent": "Un sacco. Abbiamo un giudizio Platino per la trasparenza su GuideStar.org.",
"download-irs": "Puoi <0>scaricare la nostra Lettera di Determinazione IRS qui0>.",
"download-990": "È possibile <0>scaricare il nostro più recente 990 (rapporto fiscale annuale) qui0>.",
"how-efficient": "Quanto è efficiente freeCodeCamp?",
- "fcc-budget": "Il budget di freeCodeCamp è molto più piccolo della maggior parte delle noprofit comparabili. Non abbiamo usato il servizio di raccoglitori di fondi professionali. Invece, Quincy fa tutto da se.",
+ "fcc-budget": "Il budget di freeCodeCamp è molto ristretto rispetto alla maggior parte delle organizzazioni di beneficenza comparabili. Non ci siamo rivolti a fundraiser professionisti. Invece, Quincy fa tutto da sé.",
"help-millions": "Però, con un budget di poche centinaia di migliaia di dollari per anno, siamo stati in grado di aiutare milioni di persone.",
"how-one-time": "Come posso fare una singola donazione non ricorrente?",
"one-time": "Se preferisci fare una singola donazione, puoi supportare la missione di freeCodeCamp quando hai qualche soldo in più. Puoi usare <0>questo link per donare qualsiasi ammontare ti senti di dare tramite PayPal0>.",
@@ -399,8 +406,8 @@
"yes-cryptocurrency": "Sì. Per favore manda una email a Quincy a quincy@freecodecamp.org e ti può mandare le informazioni del portafogli di freeCodeCamp. Ti può anche dare una ricevuta se ne hai bisogno per le tasse.",
"can-check": "Posso spedire un assegno fisico?",
"yes-check": "Sì, te ne saremmo grati. Puoi spedirlo a:",
- "how-matching-gift": "Come posso organizzare donazioni combacianti dal mio datore di lavoro, o riduzioni dalla mia busta paga?",
- "employers-vary": "Questo varia da datore di lavoro a datore di lavoro, e la nostra noprofit è già elencata in molti dei grandi database di donazioni combacianti.",
+ "how-matching-gift": "Come posso definire delle matching donation dal mio datore di lavoro, o detrazioni dalla mia busta paga?",
+ "employers-vary": "Questo varia da datore di lavoro a datore di lavoro, e il nostro ente benefico è già elencato in molti dei grandi database di match giving.",
"some-volunteer": "Alcune persone sono in grado di fare volontariato per freeCodeCamp e i loro datori di lavoro combaciano un dato valore per ora del loro tempo donato. Altri combaciano qualsiasi donazione che i donatori fanno con un tetto massimo",
"help-matching-gift": "Se hai bisogno di aiuto con questo, per favore manda una mail a Quincy a quincy@freecodecamp.org",
"how-endowment": "Come posso organizzare un finanziamento per freeCodeCamp.org?",
@@ -411,13 +418,13 @@
"thank-wikimedia": "Vorremmo ringraziare la Fondazione Wikimedia per aver provveduto questo linguaggio formare per il nostro uso.",
"legacy-gift-questions": "Se hai domande su questo processo, per favore scrivi a Quincy a quincy@freecodecamp.org.",
"how-stock": "Come posso donare azioni a freeCodeCamp.org?",
- "welcome-stock": "Saremmo grati per la tua donazione in azioni. Per favore scrivi a Quincy direttamente e ti può aiutare con questo, e condividere con te i dettagli del nostro account di brokerage: quindy@freecodecamp.org.",
+ "welcome-stock": "Saremmo grati per la tua donazione in azioni. Per favore scrivi direttamente a Quincy, che potrà aiutarti e condividere con te i dettagli del nostro account di brokerage: quincy@freecodecamp.org.",
"how-receipt": "Posso avere una ricevuta della mia donazione così da dedurla dalle mie tasse?",
"just-forward": "Certo. Basta che inoltri la ricevuta della transazione a donors@freecodecamp.org, dicci che vorresti una ricevuta e qualsiasi istruzione speciale tu abbia, e ti risponderemo con una ricevuta.",
"how-update": "Ho impostato una donazione mensile, ma ho bisogno di aggiornarla o metterla in pausa. Come posso fare?",
"take-care-of-this": "Inoltra una delle tue ricevute a donors@freecodecamp.org e dicci cosa vorresti fare. Ce ne occuperemo e ti risponderemo con una conferma.",
"anything-else": "C'è altro da sapere su donare a freeCodeCamp.org?",
- "other-support": "Se ci sono altri modi in cui vorresti supportare la nostra noprofit e la sua missione che non è in questa pagina, o se hai qualsiasi domanda, per favore scrivi a Quincy a quincy@freecodecamp.org."
+ "other-support": "Se ci sono altri modi in cui vorresti supportare il nostro ente benefico e la sua missione che non sono elencati in questa pagina, o se hai qualsiasi domanda, per favore scrivi a Quincy a quincy@freecodecamp.org."
},
"report": {
"sign-in": "Devi essere loggato per segnalare un utente",
@@ -460,7 +467,8 @@
"iframe-preview": "Anteprima {{title}}",
"iframe-alert": "Solitamente questo link ti porterebbe su un altro sito web! Funziona. Questo è un link per {{externalLink}}",
"iframe-form-submit-alert": "Normalmente questo modulo sarebbe stato inviato! Funziona. Sarà inviato a: {{externalLink}}",
- "document-notfound": "documento non trovato"
+ "document-notfound": "documento non trovato",
+ "slow-load-msg": "Sembra che sia necessario più tempo del solito, per favore prova ad aggiornare la pagina."
},
"icons": {
"gold-cup": "Coppa d'Oro",
@@ -475,10 +483,11 @@
"hint": "Suggerimento",
"heart": "Cuore",
"initial": "Iniziale",
+ "input-reset": "Cancella termini di ricerca",
"info": "Informazioni introduttive",
"spacer": "Distanziatore",
"toggle": "Attiva/Disattiva segno di spunta",
- "magnifier": "lente d'ingrandimento"
+ "magnifier": "Invia i termini di ricerca"
},
"aria": {
"fcc-curriculum": "Curriculum di freeCodeCamp",
@@ -504,7 +513,8 @@
"step": "Step",
"steps": "Step",
"steps-for": "Step per {{blockTitle}}",
- "code-example": "{{codeName}} code example"
+ "code-example": "{{codeName}} esempio di codice",
+ "opens-new-window": "Apri in una nuova finestra"
},
"flash": {
"honest-first": "Per richiedere una certificazione, è necessario prima accettare la nostra politica di onestà accademica",
@@ -586,7 +596,8 @@
"editor-url": "Ricordati di inviare l'URL della Live App.",
"http-url": "Non è possibile utilizzare un URL non sicuro (http).",
"own-work-url": "Ricordati di inviare il tuo lavoro.",
- "publicly-visible-url": "Ricorda di inviare un URL dell'app visibile pubblicamente."
+ "publicly-visible-url": "Ricorda di inviare un URL dell'app visibile pubblicamente.",
+ "path-url": "Probabilmente vuoi inviare il percorso root, ovvero https://example.com, non https://example.com/percorso"
},
"certification": {
"executive": "Direttore esecutivo, freeCodeCamp.org",
@@ -668,8 +679,49 @@
"Cat and Dog Image Classifier": "Classificatore di immagini di gatti e cani",
"Book Recommendation Engine using KNN": "Motore per la raccomandazione di libri che usa KNN",
"Linear Regression Health Costs Calculator": "Calcolatore di costi per la salute con la Regressione Lineare",
- "Neural Network SMS Text Classifier": "Classificatore neurale di messaggi SMS"
+ "Neural Network SMS Text Classifier": "Classificatore neurale di messaggi SMS",
+ "Celestial Bodies Database": "Database Corpi Celesti",
+ "World Cup Database": "Database Coppa Del Mondo",
+ "Salon Appointment Scheduler": "Pianificatore Appuntamento Salone",
+ "Periodic Table Database": "Database della Tavola Periodica",
+ "Number Guessing Game": "Gioco di indovinare il numero",
+ "Build a freeCodeCamp Forum Homepage": "Costruisci l'Homepage del Forum di freeCodeCamp"
}
+ },
+ "title": {
+ "Responsive Web Design": "Web Design Responsivo",
+ "responsive-web-design": "Certificazione Web Design Responsivo",
+ "JavaScript Algorithms and Data Structures": "Algoritmi e Strutture Dati in JavaScript",
+ "javascript-algorithms-and-data-structures": "Certificazione Algoritmi e Strutture Dati in JavaScript",
+ "Front End Development Libraries": "Librerie di Sviluppo Front End",
+ "front-end-development-libraries": "Certificazione Librerie di Sviluppo Front End",
+ "Data Visualization": "Visualizzazione Dati",
+ "data-visualization": "Certificazione Visualizzazione Dati",
+ "Relational Database": "Database Relazionale",
+ "relational-database-v8": "Certificazione Database Relazionale",
+ "Back End Development and APIs": "Sviluppo Back End e API",
+ "back-end-development-and-apis": "Certificazione di Sviluppo Back End e API",
+ "Quality Assurance": "Garanzia di Qualità",
+ "quality-assurance-v7": "Certificazione Garanzia di Qualità",
+ "Scientific Computing with Python": "Calcolo Scientifico con Python",
+ "scientific-computing-with-python-v7": "Certificazione Calcolo Scientifico con Python",
+ "Data Analysis with Python": "Analisi dei Dati con Python",
+ "data-analysis-with-python-v7": "Certificazione Analisi dei Dati con Python",
+ "Information Security": "Sicurezza dell'Informazione",
+ "information-security-v7": "Certificazione Sicurezza dell'Informazione",
+ "Machine Learning with Python": "Machine Learning con Python",
+ "machine-learning-with-python-v7": "Certificazione Machine Learning con Python",
+ "Legacy Front End": "Front End Legacy",
+ "legacy-front-end": "Certificazione Front End",
+ "Legacy Back End": "Back End Legacy",
+ "legacy-back-end": "Certificazione Back End",
+ "Legacy Data Visualization": "Visualizzazione Dati Legacy",
+ "legacy-data-visualization": "Certificazione Visualizzazione Dati",
+ "Legacy Information Security and Quality Assurance": "Sicurezza delle Informazioni e Garanzia di Qualità Legacy",
+ "information-security-and-quality-assurance": "Certificazione di Sicurezza delle Informazioni e Garanzia di Qualità",
+ "Legacy Full Stack Certification": "Certificazione Full Stack Legacy",
+ "Legacy Full Stack": "Full Stack Legacy",
+ "full-stack": "Certificazione Full Stack"
}
},
"certification-card": {
diff --git a/client/i18n/locales/japanese/intro.json b/client/i18n/locales/japanese/intro.json
index 053833b850d001..8c32e0e042c8c8 100644
--- a/client/i18n/locales/japanese/intro.json
+++ b/client/i18n/locales/japanese/intro.json
@@ -335,6 +335,10 @@
"learn-functional-programming-by-building-a-spreadsheet": {
"title": "関数型プログラミングの学習: スプレッドシートを作る",
"intro": ["", ""]
+ },
+ "learn-advanced-array-methods-by-building-a-statistics-calculator": {
+ "title": "Learn Advanced Array Methods by Building a Statistics Calculator",
+ "intro": ["", ""]
}
}
},
@@ -553,7 +557,7 @@
"intro": [
"ここまでは、JavaScript をフロントエンドで使用して、ページに対話性を加えたり、アルゴリズムチャレンジを解決したり、SPA を構築したりしてきました。しかし JavaScript は、バックエンド (サーバー) でも使用でき、ウェブアプリケーション全体を構築することができます。",
"現在、アプリケーションを構築する一般的な方法の一つはマイクロサービスを使用する方法です。これは、小さなモジュール式のアプリケーションを組み合わせて、より大きな全体を形成する方法です。",
- "バックエンド開発と API 認定講座では、Node.js と npm (Node Package Manager) を使用してバックエンドアプリを記述する方法を学習します。また、Express フレームワークでウェブアプリケーションを構築し、そして MongoDB と Mongoose ライブラリで People Finder マイクロサービスを構築します。"
+ "バックエンド開発と API 認定講座では、Node.js と npm を使用してバックエンドアプリを記述する方法を学習します。Express フレームワークでウェブアプリケーションを構築し、MongoDB と Mongoose ライブラリで People Finder マイクロサービスを構築します。"
],
"note": "",
"blocks": {
@@ -625,10 +629,10 @@
}
},
"scientific-computing-with-python": {
- "title": "Python を用いた科学的コンピューティング",
+ "title": "Python を用いた科学技術計算",
"intro": [
"Python は現在最も一般的で適応性のあるプログラミング言語です。基本的なスクリプトから機械学習まで幅広く使用することができます。",
- "Python を用いた科学的コンピューティング認定講座では、変数、ループ、条件式、そして関数のような、Python の基本を学習します。それから、複雑なデータ構造、ネットワーキング、リレーショナルデータベース、そしてデータ可視化まで素早く強化します。"
+ "Python を用いた科学技術計算認定講座では、変数、ループ、条件式、そして関数のような、Python の基本を学習します。それから、複雑なデータ構造、ネットワーキング、リレーショナルデータベース、そしてデータ可視化まで素早く強化します。"
],
"note": "",
"blocks": {
@@ -640,9 +644,9 @@
]
},
"scientific-computing-with-python-projects": {
- "title": "Python を用いた科学的コンピューティングプロジェクト",
+ "title": "Python を用いた科学技術計算プロジェクト",
"intro": [
- "Python の技能をテストする時です。これらのプロジェクトを完成させることによって、Python の優れた基礎知識をもっていることと、Python を用いた科学的コンピューティング認定証を得る資格があることを証明します。"
+ "Python の技能をテストする時です。これらのプロジェクトを完成させることによって、Python の優れた基礎知識をもっていることと、Python を用いた科学技術計算認定証を得る資格があることを証明します。"
]
}
}
@@ -787,6 +791,24 @@
}
}
},
+ "the-odin-project": {
+ "title": "The Odin Project",
+ "intro": [
+ "The Odin Project is one of those \"What I wish I had when I was learning\" resources. ",
+ "Not everyone has access to a computer science education or the funds to attend an intensive coding school and neither of those is right for everyone anyway.",
+ "This project is designed to fill in the gap for people who are trying to hack it on their own but still want a high quality education."
+ ],
+ "blocks": {
+ "top-learn-html-foundations": {
+ "title": "Learn HTML Foundations",
+ "intro": ["A description is to be determined"]
+ },
+ "top-build-a-recipe-project": {
+ "title": "Learn HTML Foundations by Building a Recipe Page",
+ "intro": ["A description is to be determined"]
+ }
+ }
+ },
"misc-text": {
"certification": "{{cert}} 認定",
"browse-other": "他の無料の認定講座を閲覧する\n(上から順に受講することをお勧めします)",
@@ -802,7 +824,7 @@
"viewing-upcoming-change": "ベータ版のページを閲覧中です。 ",
"go-back-to-learn": "カリキュラムの安定版へ戻る。",
"read-database-cert-article": "続行する前に、こちらのフォーラム投稿をお読みください。",
- "enable-cookies": "開始前にサードパーティーの Cookie を有効にしてください。",
+ "enable-cookies": "サードパーティーの Cookie が有効になっていることを確認してから開始してください。",
"english-only": "このセクションのコースは、英語版でのみ利用可能です。現時点ではタイトルと紹介文のみが翻訳に対応しており、レッスン自体は翻訳されておりません。"
}
}
diff --git a/client/i18n/locales/japanese/translations.json b/client/i18n/locales/japanese/translations.json
index 8308831b0769af..237a5ade9a5cfc 100644
--- a/client/i18n/locales/japanese/translations.json
+++ b/client/i18n/locales/japanese/translations.json
@@ -11,11 +11,12 @@
"view": "表示",
"view-code": "コードを表示",
"view-project": "プロジェクトを表示",
+ "view-cert-title": "{{certTitle}}を表示",
"show-cert": "認定証を表示",
"claim-cert": "認定証を取得",
"save-progress": "進行状況を保存",
- "accepted-honesty": "学問的誠実性ポリシーに同意しました。",
- "agree": "同意する",
+ "accepted-honesty": "You have agreed to our Academic Honesty Policy.",
+ "agree-honesty": "I agree to freeCodeCamp's Academic Honesty Policy.",
"save-portfolio": "このポートフォリオアイテムを保存",
"remove-portfolio": "このポートフォリオアイテムを削除",
"add-portfolio": "新規ポートフォリオアイテムを追加",
@@ -52,7 +53,7 @@
"check-code": "コードをチェック (Ctrl + Enter)",
"check-code-2": "コードをチェック",
"reset": "リセット",
- "reset-code": "全てのコードをリセット",
+ "reset-step": "Reset This Step",
"help": "ヘルプ",
"get-help": "助けを求める",
"watch-video": "動画を見る",
@@ -109,7 +110,7 @@
"data": "アカウントに保存されているデータを確認するには、下の「データをダウンロード」ボタンをクリックしてください",
"disabled": "非公開に設定されている場合、認定証は無効化されます。",
"private-name": "非公開に設定されている場合、あなたの名前は認定証に表示されません。",
- "claim-legacy": "以下の freeCodeCamp 認定証を取得すると、 {{cert}} を受け取ることができます。",
+ "claim-legacy": "以下の freeCodeCamp 認定証を取得すると、{{cert}}を受け取ることができます。",
"for": "{{username}} さんのアカウント設定",
"sound-mode": "これは快適なアコースティックギターの音をウェブサイトの至る所へ追加します。エディターにタイプしたり、チャレンジを完了したり、認定証を請求したり、その他いろいろなことをする度に音のフィードバックを受け取ります。",
"sound-volume": "キャンプファイアモードの音量:",
@@ -157,7 +158,8 @@
"honesty": "学問的誠実性ポリシー",
"internet": "他サービスのリンク",
"portfolio": "ポートフォリオ設定",
- "privacy": "プライバシー設定"
+ "privacy": "プライバシー設定",
+ "personal-info": "Personal Information"
},
"danger": {
"heading": "危険な操作",
@@ -222,11 +224,10 @@
"total-points_plural": "合計 {{count}} ポイント",
"points": "{{count}} ポイント ({{date}})",
"points_plural": "{{count}} ポイント ({{date}})",
- "screen-shot": "{{title}} のスクリーンショット",
"page-number": "{{pageNumber}} / {{totalPages}}"
},
"footer": {
- "tax-exempt-status": "freeCodeCamp は皆様のご寄付により支えられている非課税の 501(c)(3) 非営利団体です。(United States Federal Tax Identification Number: 82-0779546)",
+ "tax-exempt-status": "freeCodeCamp は皆様のご寄付により支えられている非課税の 501(c)(3) 慈善団体です。(United States Federal Tax Identification Number: 82-0779546)",
"mission-statement": "私たちのミッション: 人々が無料でコーディングを学べるよう支援することです。その実現のため、何千もの動画、記事、インタラクティブなコーディングレッスンを作成し、すべて無料で公開しています。さらに、数千の freeCodeCamp スタディグループが世界中に存在します。",
"donation-initiatives": "freeCodeCamp へのご寄付は教育活動のために用いられ、サーバー、サービス、スタッフなどの費用に充てられます。",
"donate-text": "<1>こちらからご寄付をお願いいたします1>。(場合により税控除可能)",
@@ -249,6 +250,7 @@
},
"learn": {
"heading": "freeCodeCamp のカリキュラムへようこそ。",
+ "skip-to-content": "Skip to content",
"welcome-1": "{{name}} さん、おかえりなさい。",
"welcome-2": "freeCodeCamp.org へようこそ",
"start-at-beginning": "コーディングが初めての場合は、<0>最初から開始する0> ことをお勧めします。",
@@ -272,6 +274,9 @@
"add-subtitles": "字幕の改善や追加を支援する",
"wrong-answer": "残念、正しい答えではありません。もう一度挑戦してみましょう。",
"check-answer": "以下のボタンをクリックして解答を確認してください。",
+ "assignment-not-complete": "Please finish the assignments",
+ "assignments": "Assignments",
+ "question": "Question",
"solution-link": "回答のリンク",
"github-link": "GitHub のリンク",
"submit-and-go": "提出して次のチャレンジに進む",
@@ -297,7 +302,6 @@
"certs": "{{title}} 認定講座"
},
"editor-tabs": {
- "info": "詳細",
"code": "コード",
"tests": "テスト",
"restart": "リスタート",
@@ -307,6 +311,10 @@
"notes": "ノート",
"preview": "プレビュー"
},
+ "editor-alerts": {
+ "tab-trapped": "タブキーを押すとタブ文字が入力されます",
+ "tab-free": "タブキーを押すと次のフォーカス可能要素にフォーカスします"
+ },
"help-translate": "以下の認定講座は現在翻訳中です。",
"help-translate-link": "翻訳にご協力ください。",
"project-preview-title": "これが今から作る物のプレビューです。",
@@ -327,16 +335,16 @@
"sorry-dont-giveup": "残念ながら、テストが通りませんでした。諦めないでください。",
"challenges-completed": "{{totalChallenges}} 件中 {{completedCount}} 件完了",
"season-greetings-fcc": "freeCodeCamp コミュニティから季節のご挨拶🎉",
- "if-getting-value": "freeCodeCamp が役に立ったと感じていただけたなら、寄付を通して当非営利団体の使命をご支援いただけますと幸いです。",
+ "if-getting-value": "freeCodeCamp が役に立ったと感じていただけたなら、寄付を通して当団体の使命をご支援いただけますと幸いです。",
"building-a-university": "freeCodeCamp では無料のコンピューターサイエンス学位プログラムの設立に取り組んでいます。",
"if-help-university": "すでに順調に進んでいますが、この先更に長い道のりが待っています。ぜひ私たちのチャリティー活動をご支援ください。"
},
"donate": {
- "title": "非営利団体を支援する",
+ "title": "当団体への支援",
"processing": "いただいた寄付を処理中です。",
"redirecting": "リダイレクト中...",
"thanks": "寄付ありがとうございます",
- "thank-you": "サポーターとなっていただき、ありがとうございます。",
+ "thank-you": "サポーターとなってくださり、ありがとうございます。",
"additional": "任意の金額を、追加で 1 回ずつご寄付いただけるリンクはこちら: <0>{{url}}0>",
"help-more": "私たちのさらなる活動をご支援ください",
"error": "寄付の処理に問題が発生しました。",
@@ -355,10 +363,9 @@
"your-donation-2": "あなたの {{usd}} ドルのご寄付が、世界中の人々に {{hours}} 時間の学びを毎月提供します。",
"your-donation-3": "あなたの {{usd}} ドルのご寄付が、世界中の人々に {{hours}} 時間の学びを毎年提供します。",
"become-supporter": "サポーターになる",
- "duration": "当非営利団体に一回のご支援をいただけますと幸いです。",
- "duration-2": "当非営利団体に毎月のご支援をいただけますと幸いです。",
- "duration-3": "当非営利団体に毎年のご支援をいただけますと幸いです。",
- "duration-4": "当非営利団体にご支援をいただけますと幸いです。",
+ "duration": "当団体に一回のご支援をいただけますと幸いです。",
+ "duration-2": "当団体に毎月のご支援をいただけますと幸いです。",
+ "duration-4": "当団体にご支援をいただけますと幸いです。",
"nicely-done": "おめでとうございます。「{{block}}」を完了しました。",
"credit-card": "クレジットカード",
"credit-card-2": "またはクレジットカードで寄付する:",
@@ -372,25 +379,25 @@
"email-receipt": "Eメール (寄付の領収書をお送りいたします。税控除可能な場合がございます。):",
"need-help": "現在または過去の寄付についてお困りでしょうか?",
"forward-receipt": "寄付の領収書のコピーを添えて、お問い合わせ内容を donors@freecodecamp.org までお送りください。",
- "efficiency": "freeCodeCamp は非常に効率的な、教育分野の非営利団体です。",
- "why-donate-1": "freeCodeCamp にご寄付いただくことにより、新しい技能を学習して家族を支えようとしている人々を助けることに繋がります。",
- "why-donate-2": "また、あなた自身の技術スキルを高めるための、学習リソースの作成を支援することにもなります。",
+ "efficiency": "freeCodeCamp は非常に効率的な、教育分野の慈善団体です。",
+ "why-donate-1": "freeCodeCamp への寄付を通して、新しい技能を習得して家計を支えようと努力している人々を支援できます。",
+ "why-donate-2": "また、あなた自身の技術スキルを高める学習リソースの作成を支援することにもなります。",
"bigger-donation": "より多くの金額による一回の寄付や、小切手の送付、または他の方法をお考えでしょうか?",
- "other-ways": "<0>当非営利団体の使命をご支援いただける方法0> は他にも多数ございます。",
+ "other-ways": "<0>当団体の使命を支援する方法0> は他にも多数ございます。",
"failed-pay": "処理が完了しませんでした。再度お試しください。",
"try-again": "再試行してください。",
"card-number": "カード番号:",
"expiration": "有効期限:",
"secure-donation": "セキュアな寄付",
"faq": "よくある質問",
- "only-you": "このメッセージはあなただけに表示されています。認定証の獲得おめでとうございます。簡単な課題ではなかったことと思います。freeCodeCamp を運営することもまた、簡単ではありません。費用のかからないことでもありません。ぜひ、私たちがあなたを含む世界中の人々のお役に立てるようご支援ください。当非営利団体へのご寄付をお願い申し上げます。(場合により税控除可能)",
+ "only-you": "このメッセージはあなただけに表示されています。認定証の獲得おめでとうございます。簡単な課題ではなかったことと思います。freeCodeCamp を運営することもまた簡単ではなく、相当の費用もかかります。ぜひ私たちがあなたの、そして世界中の人々の役に立てるようご支援ください。当団体へのご寄付をお願いいたします。(場合により税控除可能)",
"get-help": "寄付に関してサポートが必要な場合はどうしたらいいですか?",
"how-transparent": "freeCodeCamp.org の透明性はどのような状態ですか?",
"very-transparent": "極めて高いと評価されています。私たちは GuideStar.org より、プラチナグレードの透明性評価を受けています。",
"download-irs": "<0>こちらで私たちの IRS Determination Letter をダウンロード0>できます。",
"download-990": "<0>こちらで私たちの最新の 990 (税金の年次報告書) をダウンロード0>できます。",
"how-efficient": "freeCodeCamp はどのくらい効率的なのでしょうか?",
- "fcc-budget": "freeCodeCamp の予算は、ほとんどの同規模の非営利団体と比べ非常に少ないです。私たちはプロの資金調達者に参加を依頼していません。代わりに、Quincy が自分自身ですべてを行っています。",
+ "fcc-budget": "freeCodeCamp の予算は、同規模の他の慈善団体に比べ非常に少ない状況です。私たちはプロの資金調達者の力を借りることなく、Quincy 自身がその役目を担っています。",
"help-millions": "しかしながら、私たちは年間わずか数十万ドルの予算で、数百万の人々を支援することができています。",
"how-one-time": "一回ごとの寄付を行うにはどうしたらいいですか?",
"one-time": "一回ごとの寄付をご希望の場合、いつでも経済的なゆとりがある時に、freeCodeCamp のミッションをご支援いただくことができます。<0>こちらのリンクから、PayPal を通して任意の金額を寄付することができます。0>",
@@ -400,7 +407,7 @@
"can-check": "小切手の郵送は可能でしょうか?",
"yes-check": "はい、小切手も歓迎しております。こちらの宛先までお送りください:",
"how-matching-gift": "どのようにして雇用者からの上乗せ贈与 (マッチングギフト) や、給与所得控除を設定できますか?",
- "employers-vary": "これは雇用者によって異なりますが、当非営利団体は大規模な寄付マッチングデータベースの多くに登録されています。",
+ "employers-vary": "これは雇用者によって異なりますが、当団体は大規模な寄付マッチングデータベースの多くに登録されています。",
"some-volunteer": "あるケースでは、freeCodeCamp のためにボランティアの活動を行うことができ、雇用者がボランティアの活動時間ごとの固定金額を寄付することにより上乗せ贈与します。または、雇用者が寄付者が用意した特定の金額の寄付金と同額を上乗せ贈与する場合もあります。",
"help-matching-gift": "本件に関してサポートが必要な場合、Quincy まで直接メールにてご連絡ください: quincy@freecodecamp.org",
"how-endowment": "freeCodeCamp.org のために基金を設立するにはどうしたらいいですか?",
@@ -411,13 +418,13 @@
"thank-wikimedia": "この正式な文面を私たちに提供して下さったウィキメディア財団に感謝申し上げます。",
"legacy-gift-questions": "この手順に関するお問い合わせにつきましては、Quincy 宛てに quincy@freecodecamp.org までメールにてご連絡ください。",
"how-stock": "株式を freeCodeCamp.org に寄付するにはどうしたらいいですか?",
- "welcome-stock": "株式による寄付も歓迎しております。Quincy 宛てに quincy@freecodecamp.org まで直接メールにてご連絡いただければ、当非営利団体の証券口座の詳細も含めご説明いたします。",
+ "welcome-stock": "株式による寄付も歓迎しております。Quincy 宛てに quincy@freecodecamp.org まで直接メールにてご連絡いただければ、当団体の証券口座の詳細等ご説明いたします。",
"how-receipt": "税金から寄付金を控除するために、寄付金の領収書を受け取ることはできますか?",
"just-forward": "もちろんです。取引時の領収書を donors@freecodecamp.org まで転送し、領収書を必要とされている旨と、その他特別なご指示がございましたらその点も併せてご連絡ください。領収書を添えて返信いたします。",
"how-update": "毎月の寄付を設定しましたが、月次の処理を変更または停止したいです。どうしたらいいですか?",
"take-care-of-this": "毎月の寄付の領収書を donors@freecodecamp.org まで転送し、ご希望の変更内容をお伝えください。こちらで処理を行い、確認のご連絡を差し上げます。",
"anything-else": "freeCodeCamp.org への寄付についてもっと知ることはできますか?",
- "other-support": "こちらに挙げた以外の方法で、当非営利団体とそのミッションを支援したいとお考えの場合、またはその他のお問い合わせつきましては、 Quincy 宛てに quincy@freecodecamp.org までメールでご連絡ください。"
+ "other-support": "こちらに挙げた以外の方法で当団体を支援したいとお考えの場合、またはその他のお問い合わせつきましては、Quincy 宛てに quincy@freecodecamp.org までメールでご連絡ください。"
},
"report": {
"sign-in": "ユーザーを報告するためにはサインインする必要があります",
@@ -460,7 +467,8 @@
"iframe-preview": "{{title}} のプレビュー",
"iframe-alert": "このリンクは通常の環境では他のウェブサイトを開きます。正しく動作しています。これは {{externalLink}} へのリンクです。",
"iframe-form-submit-alert": "通常はこれでフォームが送信されます。正しく動作しています。フォームは {{externalLink}} へ送信されます。",
- "document-notfound": "ドキュメントが見つかりませんでした"
+ "document-notfound": "ドキュメントが見つかりませんでした",
+ "slow-load-msg": "通常より処理に時間がかかっているようです。ページの再読み込みをお試しください。"
},
"icons": {
"gold-cup": "ゴールドカップ",
@@ -475,10 +483,11 @@
"hint": "ヒント",
"heart": "ハート",
"initial": "初期状態",
+ "input-reset": "検索キーワードをクリア",
"info": "導入情報",
"spacer": "スペーサー",
"toggle": "トグルチェックマーク",
- "magnifier": "虫眼鏡"
+ "magnifier": "検索キーワードを送信"
},
"aria": {
"fcc-curriculum": "freeCodeCamp のカリキュラム",
@@ -504,10 +513,11 @@
"step": "ステップ",
"steps": "ステップ一覧",
"steps-for": "「{{blockTitle}}」のステップ一覧",
- "code-example": "{{codeName}} code example"
+ "code-example": "{{codeName}} のコード例",
+ "opens-new-window": "新しいウィンドウで開く"
},
"flash": {
- "honest-first": "認定証を請求するには、まず学問的誠実性ポリシーに同意する必要があります。",
+ "honest-first": "To claim a certification, you must first agree to our academic honesty policy",
"really-weird": "予期しない問題が発生しました。この問題が何度も発生するようであれば、https://github.com/freeCodeCamp/freeCodeCamp/issues/new への Issue 登録をご検討ください。",
"not-right": "問題が発生しました。レポートが生成され、freeCodeCamp.org チームへ通知されました。",
"went-wrong": "問題が発生しました。ご確認の上もう一度お試しください。",
@@ -586,7 +596,8 @@
"editor-url": "動作可能なアプリの URL を提出してください。",
"http-url": "安全でない (http) URL は使用できません。",
"own-work-url": "あなた自身の作品を提出してください。",
- "publicly-visible-url": "公開されたアプリの URL を提出してください。"
+ "publicly-visible-url": "公開されたアプリの URL を提出してください。",
+ "path-url": "You probably want to submit the root path i.e. https://example.com, not https://example.com/path"
},
"certification": {
"executive": "freeCodeCamp.org エグゼクティブ・ディレクター",
@@ -594,12 +605,12 @@
"issued": "発行日",
"fulltext": "<0>ここに0> <1>{{user}}1> <2>が freeCodeCamp.org の約 {{time}} 時間の課程に相当する2> <3>{{title}}3> <4>開発者認定講座を修了したことを証明します。4>",
"project": {
- "heading-legacy-full-stack": "このレガシーフルスタック認定講座の一環として、{{user}} は以下の認定講座を修了しました:",
- "heading": "この認定講座の一環として、{{user}} は以下のプロジェクトを完成させ、すべての自動テストスイートに合格しました:",
+ "heading-legacy-full-stack": "レガシーフルスタック認定講座の一環として、{{user}} は以下の認定講座を修了しました:",
+ "heading": "この認定講座の一環として、{{user}} は以下のプロジェクトを完成させ、すべての自動テストスイートに合格しました。",
"solution": "解答",
"no-solution": "解答の表示中にエラーが発生しました。 support@freeCodeCamp.org までメールにてお問い合わせください。",
"source": "ソースコード",
- "footnote": "これらのプロジェクトのいずれかが <2>学問的誠実性ポリシー2> に違反すると思われる場合、<5>freeCodeCamp チームに報告5> してください。",
+ "footnote": "これらのプロジェクトのいずれかが<2>学問的誠実性ポリシー2>に反すると思われる場合は、<5>freeCodeCamp チームに報告5>してください。",
"title": {
"Build a Personal Portfolio Webpage": "個人ポートフォリオのウェブページを作成する",
"Build a Random Quote Machine": "ランダムクォートマシンを作成する",
@@ -668,8 +679,49 @@
"Cat and Dog Image Classifier": "猫と犬の画像分類プログラム",
"Book Recommendation Engine using KNN": "KNN を使用した書籍推薦エンジン",
"Linear Regression Health Costs Calculator": "線形回帰による医療費の計算プログラム",
- "Neural Network SMS Text Classifier": "ニューラルネットワークによる SMS テキスト分類プログラム"
+ "Neural Network SMS Text Classifier": "ニューラルネットワークによる SMS テキスト分類プログラム",
+ "Celestial Bodies Database": "天体データベース",
+ "World Cup Database": "ワールドカップデータベース",
+ "Salon Appointment Scheduler": "サロン予約スケジューラー",
+ "Periodic Table Database": "周期表データベース",
+ "Number Guessing Game": "数当てゲーム",
+ "Build a freeCodeCamp Forum Homepage": "freeCodeCamp フォーラムのホームページを作成する"
}
+ },
+ "title": {
+ "Responsive Web Design": "レスポンシブウェブデザイン",
+ "responsive-web-design": "レスポンシブウェブデザイン認定証",
+ "JavaScript Algorithms and Data Structures": "JavaScript のアルゴリズムとデータ構造",
+ "javascript-algorithms-and-data-structures": "JavaScript のアルゴリズムとデータ構造認定証",
+ "Front End Development Libraries": "フロントエンド開発ライブラリ",
+ "front-end-development-libraries": "フロントエンド開発ライブラリ認定証",
+ "Data Visualization": "データ可視化",
+ "data-visualization": "データ可視化認定証",
+ "Relational Database": "リレーショナルデータベース",
+ "relational-database-v8": "リレーショナルデータベース認定証",
+ "Back End Development and APIs": "バックエンド開発と API",
+ "back-end-development-and-apis": "バックエンド開発と API 認定証",
+ "Quality Assurance": "品質保証",
+ "quality-assurance-v7": "品質保証認定証",
+ "Scientific Computing with Python": "Python を用いた科学技術計算",
+ "scientific-computing-with-python-v7": "Python を用いた科学技術計算認定証",
+ "Data Analysis with Python": "Python を用いたデータ分析",
+ "data-analysis-with-python-v7": "Python を用いたデータ分析認定証",
+ "Information Security": "情報セキュリティ",
+ "information-security-v7": "情報セキュリティ認定証",
+ "Machine Learning with Python": "Python を用いた機械学習",
+ "machine-learning-with-python-v7": "Python を用いた機械学習認定証",
+ "Legacy Front End": "(レガシー) フロントエンド",
+ "legacy-front-end": "フロントエンド認定証",
+ "Legacy Back End": "(レガシー) バックエンド",
+ "legacy-back-end": "バックエンド認定証",
+ "Legacy Data Visualization": "(レガシー) データ可視化",
+ "legacy-data-visualization": "データ可視化認定証",
+ "Legacy Information Security and Quality Assurance": "(レガシー) 情報セキュリティと品質保証認定証",
+ "information-security-and-quality-assurance": "情報セキュリティと品質保証認定証",
+ "Legacy Full Stack Certification": "(レガシー) フルスタック認定証",
+ "Legacy Full Stack": "(レガシー) フルスタック",
+ "full-stack": "フルスタック認定証"
}
},
"certification-card": {
@@ -725,7 +777,7 @@
},
"signout": {
"heading": "アカウントからサインアウト",
- "p1": "注意: サインアウト後は進行状況が保存されません。",
+ "p1": "注意: サインアウト状態では進行状況が保存されません。",
"p2": "この操作では、このデバイスおよびブラウザーセッションのみを対象にサインアウトされます。サインアウトしてよろしいですか?",
"certain": "はい、サインアウトします",
"nevermind": "いいえ、サインアウトしません"
diff --git a/client/i18n/locales/portuguese/intro.json b/client/i18n/locales/portuguese/intro.json
index e6e28507998712..ec714009352a59 100644
--- a/client/i18n/locales/portuguese/intro.json
+++ b/client/i18n/locales/portuguese/intro.json
@@ -335,6 +335,10 @@
"learn-functional-programming-by-building-a-spreadsheet": {
"title": "Aprenda programação funcional criando uma planilha",
"intro": ["", ""]
+ },
+ "learn-advanced-array-methods-by-building-a-statistics-calculator": {
+ "title": "Aprenda métodos de arrays avançados criando uma calculadora de estatística",
+ "intro": ["", ""]
}
}
},
@@ -553,7 +557,7 @@
"intro": [
"Até esse ponto, você usou JavaScript apenas no front-end para adicionar interatividade a uma página, resolver desafios de algoritmos ou construir uma SPA. Mas o JavaScript também pode ser usado no back-end, ou servidor, para construir aplicações web inteiras.",
"Hoje em dia, uma das formas populares de se criar aplicações é através do uso de microsserviços, que são pequenas aplicações modulares que trabalham em conjunto para formar uma aplicação maior inteira.",
- "Na certificação de APIs e desenvolvimento de back-end, você aprenderá a escrever aplicações de back-end com o Node.js e o npm (Node Package Manager). Você também vai construir aplicações web com o framework Express e criará um microsserviço de localização de pessoas com o MongoDB e com a biblioteca Mongoose."
+ "Na certificação de APIs e desenvolvimento de back-end, você aprenderá a escrever aplicações de back-end com o Node.js e o npm. Você também vai construir aplicações web com o framework Express e criará um microsserviço de localização de pessoas com o MongoDB e com a biblioteca Mongoose."
],
"note": "",
"blocks": {
@@ -787,6 +791,24 @@
}
}
},
+ "the-odin-project": {
+ "title": "The Odin Project",
+ "intro": [
+ "The Odin Project é um daqueles recursos do tipo \"O que eu gostaria de ter visto quando estava aprendendo\". ",
+ "Nem todas as pessoas têm acesso à educação em ciência da computação ou aos fundos necessários para frequentar uma escola de programação intensiva. De qualquer modo, não necessariamente, essas duas sejam a solução final para todos que queiram aprender.",
+ "Este projeto destina-se a preencher a lacuna para aquelas pessoas que tentam buscar suas próprias soluções, mas que continuam procurando uma educação de alta qualidade."
+ ],
+ "blocks": {
+ "top-learn-html-foundations": {
+ "title": "Aprenda o básico de HTML",
+ "intro": ["Uma descrição deve ser determinada"]
+ },
+ "top-build-a-recipe-project": {
+ "title": "Aprenda o básico de HTML criando uma página de receitas",
+ "intro": ["Uma descrição deve ser determinada"]
+ }
+ }
+ },
"misc-text": {
"certification": "Certificação {{cert}}",
"browse-other": "Navegue por nossas outras certificações gratuitas\n(recomendamos fazer isto em sequência)",
diff --git a/client/i18n/locales/portuguese/translations.json b/client/i18n/locales/portuguese/translations.json
index 77041c9b3c0c7e..7e5f9e76452879 100644
--- a/client/i18n/locales/portuguese/translations.json
+++ b/client/i18n/locales/portuguese/translations.json
@@ -11,11 +11,12 @@
"view": "Visualizar",
"view-code": "Ver código",
"view-project": "Ver o projeto",
+ "view-cert-title": "Ver {{certTitle}}",
"show-cert": "Exibir certificado",
"claim-cert": "Solicitar certificação",
"save-progress": "Salvar progresso",
- "accepted-honesty": "Você aceitou nossa política de honestidade acadêmica.",
- "agree": "Aceitar",
+ "accepted-honesty": "Você concordou com nossa política de honestidade acadêmica.",
+ "agree-honesty": "Concordo com a Política de Honestidade Acadêmica do FreeCodeCamp.",
"save-portfolio": "Salvar esse item de portfólio",
"remove-portfolio": "Remover este item de portfólio",
"add-portfolio": "Adicionar um novo item de portfólio",
@@ -52,7 +53,7 @@
"check-code": "Verifique seu código (Ctrl + Enter)",
"check-code-2": "Verifique seu código",
"reset": "Redefinir",
- "reset-code": "Redefinir todo o código",
+ "reset-step": "Reiniciar este passo",
"help": "Ajuda",
"get-help": "Obter ajuda",
"watch-video": "Assistir a um vídeo",
@@ -157,7 +158,8 @@
"honesty": "Política de honestidade acadêmica",
"internet": "Sua presença na internet",
"portfolio": "Configurações do portfólio",
- "privacy": "Configurações de privacidade"
+ "privacy": "Configurações de privacidade",
+ "personal-info": "Informações pessoais"
},
"danger": {
"heading": "Zona de perigo",
@@ -222,16 +224,15 @@
"total-points_plural": "{{count}} pontos no total",
"points": "{{count}} ponto em {{date}}",
"points_plural": "{{count}} pontos em {{date}}",
- "screen-shot": "Uma captura de tela de {{title}}",
"page-number": "{{pageNumber}} de {{totalPages}}"
},
"footer": {
- "tax-exempt-status": "O freeCodeCamp é uma organização sem fins lucrativos apoiada por doadores e isenta de impostos 501(c)(3) (Número de identificação fiscal federal dos Estados Unidos: 82-0779546)",
+ "tax-exempt-status": "O freeCodeCamp é uma organização beneficente 501(c)(3), isenta de impostos e apoiada por doações (Número de identificação fiscal federal dos Estados Unidos: 82-0779546).",
"mission-statement": "Nossa missão: ajudar as pessoas a aprender a programar de graça. Nós conseguimos isso através da criação de milhares de vídeos, artigos e aulas interativas de programação – tudo disponível gratuitamente para o público. Também temos milhares de grupos de estudo do freeCodeCamp espalhados por todo o mundo.",
"donation-initiatives": "Doações para o freeCodeCamp vão para as nossas iniciativas educacionais e ajudam a pagar por servidores, serviços e equipe.",
"donate-text": "Você pode <1>fazer uma doação dedutível de imposto aqui1>.",
"trending-guides": "Guias em alta",
- "our-nonprofit": "Nossa organização sem fins lucrativos",
+ "our-nonprofit": "Nossa instituição",
"links": {
"about": "Sobre",
"alumni": "Rede de ex-alunos",
@@ -249,6 +250,7 @@
},
"learn": {
"heading": "Boas-vindas ao currículo do freeCodeCamp.",
+ "skip-to-content": "Ir para o conteúdo",
"welcome-1": "Bem-vindo(a) de volta, {{name}}.",
"welcome-2": "Boas-vindas ao freeCodeCamp.org",
"start-at-beginning": "Se você é novo em programação, recomendamos que você <0>comece no início0>.",
@@ -272,6 +274,9 @@
"add-subtitles": "Ajudar a melhorar ou adicionar legendas",
"wrong-answer": "Desculpe, essa não é a resposta correta. Quer tentar novamente?",
"check-answer": "Clique no botão abaixo para verificar sua resposta.",
+ "assignment-not-complete": "Termine as tarefas",
+ "assignments": "Tarefas",
+ "question": "Questão",
"solution-link": "Link da solução",
"github-link": "Link do GitHub",
"submit-and-go": "Enviar e ir para o meu próximo desafio",
@@ -297,7 +302,6 @@
"certs": "Certificação {{title}}"
},
"editor-tabs": {
- "info": "Informações",
"code": "Código",
"tests": "Testes",
"restart": "Reiniciar",
@@ -307,6 +311,10 @@
"notes": "Observações",
"preview": "Pré-visualizar"
},
+ "editor-alerts": {
+ "tab-trapped": "Ao apertar a tecla tab, agora, você vai inserir o caractere de tabulação",
+ "tab-free": "Ao apertar a tecla tab, agora, você moverá o foco para o próximo elemento que possa ser focado"
+ },
"help-translate": "Ainda estamos traduzindo as certificações a seguir.",
"help-translate-link": "Ajude-nos a traduzir.",
"project-preview-title": "Aqui está uma prévia do que você vai criar",
@@ -327,12 +335,12 @@
"sorry-dont-giveup": "Desculpe, seu código não passou nos testes. Não desista.",
"challenges-completed": "{{completedCount}} de {{totalChallenges}} desafios concluídos",
"season-greetings-fcc": "Boas festas de fim de ano, da comunidade do freeCodeCamp 🎉",
- "if-getting-value": "Se você está conseguindo tirar proveito do conteúdo do freeCodeCamp, agora é um ótimo momento para fazer sua doação e apoiar nossa missão sem fins lucrativos.",
+ "if-getting-value": "Se você está conseguindo tirar proveito do conteúdo do freeCodeCamp, agora é um ótimo momento para fazer sua doação e apoiar nossa missão beneficente.",
"building-a-university": "Estamos criando um programa gratuito de graduação em Ciência da Computação",
"if-help-university": "Já fizemos um progresso enorme. Apoie nossa organização sem fins lucrativos com o longo caminho que temos pela frente."
},
"donate": {
- "title": "Dê seu apoio à nossa organização sem fins lucrativos",
+ "title": "Ajude nossa instituição",
"processing": "Estamos processando a sua doação.",
"redirecting": "Redirecionando...",
"thanks": "Agradecemos por sua doação",
@@ -355,10 +363,9 @@
"your-donation-2": "Sua doação de US${{usd}} proporcionará {{hours}} horas mensais de aprendizado para pessoas ao redor do mundo.",
"your-donation-3": "Sua doação de US${{usd}} proporcionará {{hours}} horas anuais de aprendizado para pessoas ao redor do mundo.",
"become-supporter": "Torne-se um apoiador",
- "duration": "Torne-se um apoiador por doação única da nossa organização sem fins lucrativos.",
- "duration-2": "Torne-se um apoiador mensal da nossa organização sem fins lucrativos.",
- "duration-3": "Torne-se um apoiador anual da nossa organização sem fins lucrativos",
- "duration-4": "Torne-se um apoiador da nossa organização sem fins lucrativos",
+ "duration": "Torne-se um apoiador com uma doação única para nossa organização beneficente.",
+ "duration-2": "Torne-se um apoiador mensal da nossa organização beneficente.",
+ "duration-4": "Torne-se um apoiador da nossa organização beneficente",
"nicely-done": "Bom trabalho. Você acabou de completar {{block}}.",
"credit-card": "Cartão de crédito",
"credit-card-2": "Ou doe com um cartão de crédito:",
@@ -372,25 +379,25 @@
"email-receipt": "E-mail (enviaremos um comprovante de doação):",
"need-help": "Precisa de ajuda com suas doações atuais ou anteriores?",
"forward-receipt": "Envie uma cópia do recibo de sua doação para donors@freecodecamp.org e nos diga como podemos ajudar.",
- "efficiency": "O freeCodeCamp é uma organização educacional, sem fins lucrativos, e altamente eficiente.",
+ "efficiency": "O freeCodeCamp é uma organização educacional, beneficente e de grande eficácia.",
"why-donate-1": "Quando você doa para o freeCodeCamp, você ajuda as pessoas a aprender novas habilidades e sustentar suas famílias.",
"why-donate-2": "Você também nos ajuda a criar novos recursos que você pode usar para melhorar as suas próprias habilidades tecnológicas.",
"bigger-donation": "Quer fazer uma doação maior de uma única vez, enviar-nos um cheque ou doar de outras maneiras?",
- "other-ways": "Aqui estão muitas <0>outras maneiras para ajudar a nossa missão sem fins lucrativos0>.",
+ "other-ways": "Aqui estão muitas <0>outras maneiras para ajudar a nossa missão beneficente0>.",
"failed-pay": "Opa. Parece que a sua transação não funcionou. Você poderia tentar de novo?",
"try-again": "Tente novamente.",
"card-number": "Número do seu cartão:",
"expiration": "Data de validade:",
"secure-donation": "Doação segura",
"faq": "Perguntas frequentes",
- "only-you": "Só você pode ver esta mensagem. Parabéns por ganhar este certificado. Não é uma tarefa fácil. Manter o freeCodeCamp também não é fácil. Nem é barato. Ajude-nos a ajudar você e muitas outras pessoas ao redor do mundo. Faça uma dedução de impostos doando para nossa organização sem fins lucrativos hoje.",
+ "only-you": "Só você pode ver esta mensagem. Parabéns por ganhar este certificado. Não é uma tarefa fácil. Manter o freeCodeCamp também não é fácil. Nem é barato. Ajude-nos a ajudar você e muitas outras pessoas ao redor do mundo. Faça uma dedução de impostos doando para nossa organização beneficente hoje.",
"get-help": "Como posso obter ajuda com minhas doações?",
"how-transparent": "Qual é o nível de transparência do freeCodeCamp.org?",
"very-transparent": "Grande. Temos uma classificação de transparência Platinum do GuideStar.org.",
"download-irs": "Você pode <0>baixar nossa Carta de Determinação do IRS aqui0>.",
"download-990": "Você pode <0>baixar nosso último 990 (relatório anual de impostos) aqui0>.",
"how-efficient": "Qual é o nível de eficiência do freeCodeCamp?",
- "fcc-budget": "O orçamento do freeCodeCamp é muito menor do que o da maioria das organizações sem fins lucrativos. Não temos profissionais em arrecadação de fundos. Em vez disso, Quincy faz tudo por conta própria.",
+ "fcc-budget": "O orçamento do freeCodeCamp é muito menor do que o da maioria das organizações beneficentes. Não temos profissionais em arrecadação de fundos. Em vez disso, Quincy faz tudo por conta própria.",
"help-millions": "No entanto, com um orçamento de apenas algumas centenas de milhares de dólares por ano, conseguimos ajudar milhões de pessoas.",
"how-one-time": "Como posso fazer uma doação única?",
"one-time": "Se você preferir fazer doações únicas, pode apoiar a missão do freeCodeCamp sempre que tiver dinheiro sobrando. Você pode usar <0>este link para doar qualquer quantia que sentir que vale a pena através do PayPal0>.",
@@ -400,7 +407,7 @@
"can-check": "Posso enviar um cheque físico?",
"yes-check": "Sim, receberemos cheques com satisfação. Você pode nos enviar cheques pelo correio pelo endereço:",
"how-matching-gift": "Como eu posso configurar donativos correspondentes do meu empregador, ou deduções na folha de pagamento?",
- "employers-vary": "Isso varia de empregador para empregador. Nossa organização sem fins lucrativos já está listada em muitas das grandes bases de dados de doações correspondentes.",
+ "employers-vary": "Isso varia de empregador para empregador. Nossa organização beneficente já está listada em muitos dos grandes bancos de dados de doações correspondentes.",
"some-volunteer": "Algumas pessoas são capazes de se voluntariar para o freeCodeCamp e suas correspondências de empregador, doando uma quantidade fixa por hora que voluntariam. Outros empregadores corresponderão a quaisquer doações que os doadores pagarem até um certo valor",
"help-matching-gift": "Se você precisar de ajuda com isso, envie um e-mail para o Quincy diretamente: quincy@freecodecamp.org",
"how-endowment": "Como posso configurar um presente de dote para o freeCodeCamp.org?",
@@ -411,13 +418,13 @@
"thank-wikimedia": "Gostaríamos de agradecer à Wikimedia Foundation por nos fornecer esta linguagem formal para utilizarmos.",
"legacy-gift-questions": "Se você tiver alguma dúvida sobre este processo, envie um e-mail para quincy@freecodecamp.org.",
"how-stock": "Como posso doar ações para freeCodeCamp.org?",
- "welcome-stock": "Receberemos suas doações em ações com satisfação. Envie um e-mail para o Quincy diretamente e ele pode ajudá-lo com isso e compartilhar os detalhes de nossa conta de corretora sem fins lucrativos: quincy@freecodecamp.org.",
+ "welcome-stock": "Receberemos suas doações em ações com satisfação. Envie um e-mail para o Quincy diretamente e ele pode ajudá-lo com isso e compartilhar os detalhes da conta de corretora de nossa organização beneficente: quincy@freecodecamp.org.",
"how-receipt": "Posso obter um recibo de doação para deduzi-la dos meus impostos?",
"just-forward": "Claro. Basta encaminhar o recibo de sua transação para donors@freecodecamp.org, dizer que você gostaria de um recibo e quaisquer instruções especiais que você possa ter, e nós responderemos com um recibo para você.",
"how-update": "Criei uma doação mensal, mas preciso atualizar ou pausar a recorrência mensal. Como posso fazer isso?",
"take-care-of-this": "Apenas encaminhe um de seus recibos mensais para donors@freecodecamp.org e diga-nos o que você gostaria que fizéssemos. Cuidaremos disso para você e enviaremos sua confirmação.",
"anything-else": "Há mais alguma coisa que eu possa aprender sobre doações para freeCodeCamp.org?",
- "other-support": "Se você quiser apoiar a nossa organização sem fins lucrativos e a sua missão de alguma outra forma que não estiver listada aqui, ou se você tiver alguma dúvida, envie um e-mail para quincy@freecodecamp.org."
+ "other-support": "Se você quiser apoiar a nossa organização beneficente e a sua missão de alguma outra forma que não estiver listada aqui, ou se você tiver alguma dúvida, envie um e-mail para quincy@freecodecamp.org."
},
"report": {
"sign-in": "Você precisa estar logado para denunciar um usuário",
@@ -460,7 +467,8 @@
"iframe-preview": "Visualização de {{title}}",
"iframe-alert": "Normalmente, este link levaria você para outro site da web! Funciona. Esse é um link para: {{externalLink}}",
"iframe-form-submit-alert": "Normalmente, esse formulário seria enviado! Funciona. Ele será enviado para: {{externalLink}}",
- "document-notfound": "documento não encontrado"
+ "document-notfound": "documento não encontrado",
+ "slow-load-msg": "Parece que está demorando mais do que o normal. Tente atualizar a página."
},
"icons": {
"gold-cup": "Taça de ouro",
@@ -475,10 +483,11 @@
"hint": "Dica",
"heart": "Coração",
"initial": "Inicial",
+ "input-reset": "Limpar termos de pesquisa",
"info": "Informações introdutórias",
"spacer": "Espaçador",
"toggle": "Alternar marcação",
- "magnifier": "lupa"
+ "magnifier": "Enviar termos de pesquisa"
},
"aria": {
"fcc-curriculum": "Currículo do freeCodeCamp",
@@ -504,10 +513,11 @@
"step": "Passo",
"steps": "Passos",
"steps-for": "Passos para {{blockTitle}}",
- "code-example": "{{codeName}} code example"
+ "code-example": "Exemplo de código de {{codeName}}",
+ "opens-new-window": "Abre em uma nova janela"
},
"flash": {
- "honest-first": "Para solicitar uma certificação, você precisa primeiro aceitar nossa política de honestidade acadêmica",
+ "honest-first": "Para solicitar uma certificação, você precisa primeiro concordar com nossa política de honestidade acadêmica",
"really-weird": "Algo realmente estranho aconteceu. Se acontecer novamente, considere apresentar um problema pelo endereço https://github.com/freeCodeCamp/freeCodeCamp/issues/new",
"not-right": "Algo não está certo. Um relatório foi gerado e a equipe do freeCodeCamp.org foi notificada",
"went-wrong": "Algo deu errado. Verifique e tente novamente",
@@ -586,7 +596,8 @@
"editor-url": "Lembre-se de enviar o URL do aplicativo em produção.",
"http-url": "Não é possível usar um URL (http) inseguro.",
"own-work-url": "Lembre-se de enviar o seu próprio trabalho.",
- "publicly-visible-url": "Lembre-se de enviar o URL de um aplicativo publicamente visível."
+ "publicly-visible-url": "Lembre-se de enviar o URL de um aplicativo publicamente visível.",
+ "path-url": "Você provavelmente vai querer enviar o caminho raiz, ou seja, https://example.com em vez de https://example.com/path"
},
"certification": {
"executive": "Diretor executivo, freeCodeCamp.org",
@@ -668,8 +679,49 @@
"Cat and Dog Image Classifier": "Classificador de imagens de gatos e cachorros",
"Book Recommendation Engine using KNN": "Mecanismo de recomendação de livros usando KNN",
"Linear Regression Health Costs Calculator": "Calculadora de custos de saúde de regressão linear",
- "Neural Network SMS Text Classifier": "Classificador de texto SMS baseado em rede neural"
+ "Neural Network SMS Text Classifier": "Classificador de texto SMS baseado em rede neural",
+ "Celestial Bodies Database": "Banco de dados de corpos celestiais",
+ "World Cup Database": "Banco de dados da Copa do Mundo",
+ "Salon Appointment Scheduler": "Agendador de compromissos do salão de beleza",
+ "Periodic Table Database": "Banco de dados da tabela periódica",
+ "Number Guessing Game": "Jogo de adivinhação de números",
+ "Build a freeCodeCamp Forum Homepage": "Criar uma página inicial do fórum do freeCodeCamp"
}
+ },
+ "title": {
+ "Responsive Web Design": "Design responsivo para a web",
+ "responsive-web-design": "Certificação de design responsivo para a web",
+ "JavaScript Algorithms and Data Structures": "Algoritmos e estruturas de dados em JavaScript",
+ "javascript-algorithms-and-data-structures": "Certificação de algoritmos e estruturas de dados em JavaScript",
+ "Front End Development Libraries": "Bibliotecas de desenvolvimento em front-end",
+ "front-end-development-libraries": "Certificação de desenvolvimento com bibliotecas de front-end",
+ "Data Visualization": "Visualização de dados",
+ "data-visualization": "Certificação de visualização de dados",
+ "Relational Database": "Bancos de dados relacionais",
+ "relational-database-v8": "Certificação de bancos de dados relacionais",
+ "Back End Development and APIs": "APIs e desenvolvimento de back-end",
+ "back-end-development-and-apis": "Certificação de APIs e desenvolvimento de back-end",
+ "Quality Assurance": "Garantia de qualidade",
+ "quality-assurance-v7": "Certificação de garantia de qualidade",
+ "Scientific Computing with Python": "Computação científica em Python",
+ "scientific-computing-with-python-v7": "Certificação de computação científica em Python",
+ "Data Analysis with Python": "Análise de dados com Python",
+ "data-analysis-with-python-v7": "Certificação de análise de dados com Python",
+ "Information Security": "Segurança da informação",
+ "information-security-v7": "Certificação de segurança da informação",
+ "Machine Learning with Python": "Aprendizado de máquina com Python",
+ "machine-learning-with-python-v7": "Certificação de aprendizagem de máquina com Python",
+ "Legacy Front End": "Front-end legado",
+ "legacy-front-end": "Certificação de front-end",
+ "Legacy Back End": "Back-end legado",
+ "legacy-back-end": "Certificação de back-end",
+ "Legacy Data Visualization": "Visualização de dados legada",
+ "legacy-data-visualization": "Certificação de visualização de dados",
+ "Legacy Information Security and Quality Assurance": "Segurança da informação e garantia da qualidade legado",
+ "information-security-and-quality-assurance": "Certificação de segurança da informação e garantia da qualidade",
+ "Legacy Full Stack Certification": "Certificação de full-stack legada",
+ "Legacy Full Stack": "Full-stack legado",
+ "full-stack": "Certificação de full-stack"
}
},
"certification-card": {
diff --git a/client/i18n/locales/ukrainian/intro.json b/client/i18n/locales/ukrainian/intro.json
index b725c1a96c7792..7d87231daf963f 100644
--- a/client/i18n/locales/ukrainian/intro.json
+++ b/client/i18n/locales/ukrainian/intro.json
@@ -335,6 +335,10 @@
"learn-functional-programming-by-building-a-spreadsheet": {
"title": "Вивчіть функційне програмування, створивши електронну таблицю",
"intro": ["", ""]
+ },
+ "learn-advanced-array-methods-by-building-a-statistics-calculator": {
+ "title": "Вивчіть передові методи масиву, створивши статистичний калькулятор",
+ "intro": ["", ""]
}
}
},
@@ -553,7 +557,7 @@
"intro": [
"До цього моменту ви використовували JavaScript тільки для фронтенду, аби зробити вебсторінку інтерактивнішою, розв'язати завдання з алгоритмами, або створити SPA. Але JavaScript можна використовувати й в бекенд, або на сервері, для створення цілих вебзастосунків.",
"Сьогодні один із найпопулярніших способів створення застосунків – за допомогою мікросервісів, маленьких модульних застосунків, які разом формують єдине ціле.",
- "У сертифікації «Розробка Back End та API» ви навчитеся писати бекенд програми за допомогою Node.js та npm (Node Package Manager). Також, ви створите вебзастосунок за допомогою фреймворку Express та мікросервіс для пошуку людей за допомогою MongoDB і Mongoose library."
+ "У сертифікації «Розробка Back End та API» ви навчитеся писати бекенд програми за допомогою Node.js та npm. Ви також створите вебзастосунок за допомогою фреймворку Express та мікросервіс для пошуку людей за допомогою MongoDB і бібліотеки Mongoose."
],
"note": "",
"blocks": {
@@ -787,6 +791,24 @@
}
}
},
+ "the-odin-project": {
+ "title": "Проєкт «Odin»",
+ "intro": [
+ "Проєкт «Odin» є одним з тих ресурсів, про які хотіли б дізнатися ще коли навчались. ",
+ "Не кожен має доступ до технологічної освіти або коштів, необхідних для відвідування інтенсивної школи. Однак це не остаточне рішення для тих, хто хоче вчитися.",
+ "Цей проєкт розроблений, щоб заповнити прогалину для людей, які намагаються вчитись самостійно, але все ж таки хочуть високоякісну освіту."
+ ],
+ "blocks": {
+ "top-learn-html-foundations": {
+ "title": "Вивчіть основи HTML",
+ "intro": ["Опис буде надано пізніше"]
+ },
+ "top-build-a-recipe-project": {
+ "title": "Вивчіть основи HTML, побудувавши сторінку з рецептами",
+ "intro": ["Опис буде надано пізніше"]
+ }
+ }
+ },
"misc-text": {
"certification": "Сертифікація «{{cert}}»",
"browse-other": "Перегляньте інші безоплатні сертифікації\n(ми рекомендуємо виконувати їх послідовно)",
diff --git a/client/i18n/locales/ukrainian/translations.json b/client/i18n/locales/ukrainian/translations.json
index c92dcd89329fb3..5e05d9600c079f 100644
--- a/client/i18n/locales/ukrainian/translations.json
+++ b/client/i18n/locales/ukrainian/translations.json
@@ -11,11 +11,12 @@
"view": "Перегляд",
"view-code": "Переглянути код",
"view-project": "Переглянути проєкт",
+ "view-cert-title": "Переглянути {{certTitle}}",
"show-cert": "Показати сертифікацію",
"claim-cert": "Отримати сертифікацію",
"save-progress": "Зберегти прогрес",
- "accepted-honesty": "Ви прийняли нашу Політику академічної доброчесності.",
- "agree": "Прийняти",
+ "accepted-honesty": "Ви погодились з нашою політикою академічної доброчесності.",
+ "agree-honesty": "Я погоджуюсь з політикою академічної доброчесності freeCodeCamp.",
"save-portfolio": "Зберегти цей елемент портфоліо",
"remove-portfolio": "Видалити цей елемент портфоліо",
"add-portfolio": "Додати новий елемент портфоліо",
@@ -52,7 +53,7 @@
"check-code": "Перевірити код (Ctrl + Enter)",
"check-code-2": "Перевірити код",
"reset": "Скинути",
- "reset-code": "Скинути весь код",
+ "reset-step": "Скинути цей крок",
"help": "Допомога",
"get-help": "Отримати допомогу",
"watch-video": "Подивитися відео",
@@ -157,7 +158,8 @@
"honesty": "Політика академічної доброчесності",
"internet": "Ваші соціальні мережі",
"portfolio": "Налаштування портфоліо",
- "privacy": "Налаштування конфіденційності"
+ "privacy": "Налаштування конфіденційності",
+ "personal-info": "Особиста інформація"
},
"danger": {
"heading": "Небезпечна зона",
@@ -183,7 +185,7 @@
"check": "Будь ласка, перевірте свою електронну пошту, або <0>надішліть запит на новий лист для підтвердження0>.",
"current": "Поточна адреса електронної пошти",
"new": "Нова адреса електронної пошти",
- "confirm": "Підтвердити нову адресу електронної пошти",
+ "confirm": "Підтвердіть нову адресу електронної пошти",
"weekly": "Надсилати мені щотижневу розсилку від Квінсі"
},
"honesty": {
@@ -222,7 +224,6 @@
"total-points_plural": "Всього балів: {{count}}",
"points": "{{count}}х балів станом на {{date}}",
"points_plural": "{{count}}х балів станом на {{date}}",
- "screen-shot": "Знімок екрану {{title}}",
"page-number": "{{pageNumber}} з {{totalPages}}"
},
"footer": {
@@ -231,7 +232,7 @@
"donation-initiatives": "Внески до freeCodeCamp йдуть на наші освітні програми та допомагають оплачувати сервери, послуги та персонал.",
"donate-text": "Ви можете <1>зробити неоподаткований внесок тут1>.",
"trending-guides": "Популярні статті",
- "our-nonprofit": "Наша некомерційна організація",
+ "our-nonprofit": "Наша організація",
"links": {
"about": "Про нас",
"alumni": "Спільнота випускників",
@@ -249,9 +250,10 @@
},
"learn": {
"heading": "Ласкаво просимо до навчальної програми freeCodeCamp.",
+ "skip-to-content": "Перейти до змісту",
"welcome-1": "З поверненням, {{name}}.",
"welcome-2": "Ласкаво просимо до freeCodeCamp.org",
- "start-at-beginning": "Якщо ви новачок у програмуванні, ми рекомендуємо <0>почати з самого початку0>.",
+ "start-at-beginning": "Якщо ви новачок у програмуванні, ми рекомендуємо <0>почати з початку0>.",
"read-this": {
"heading": "Будь ласка, прочитайте це.",
"p1": "freeCodeCamp – це перевірений шлях до вашої першої роботи розробника програмного забезпечення.",
@@ -272,6 +274,9 @@
"add-subtitles": "Допомогти покращити або додати субтитри",
"wrong-answer": "Нам шкода, але це неправильна відповідь. Спробуєте ще раз?",
"check-answer": "Натисніть кнопку нижче, щоб перевірити свою відповідь.",
+ "assignment-not-complete": "Будь ласка, завершіть завдання",
+ "assignments": "Завдання",
+ "question": "Запитання",
"solution-link": "Посилання на рішення",
"github-link": "Посилання на GitHub",
"submit-and-go": "Відправити та перейти до мого наступного завдання",
@@ -297,7 +302,6 @@
"certs": "Сертифікація «{{title}}»"
},
"editor-tabs": {
- "info": "Інформація",
"code": "Код",
"tests": "Тести",
"restart": "Перезапустити",
@@ -307,6 +311,10 @@
"notes": "Примітки",
"preview": "Попередній перегляд"
},
+ "editor-alerts": {
+ "tab-trapped": "При натисканні клавіші tab ви вставите символ табуляції",
+ "tab-free": "При натисканні клавіші tab ви перемістите фокус на наступний елемент, який можна сфокусувати"
+ },
"help-translate": "Ми досі перекладаємо наступні сертифікації.",
"help-translate-link": "Допоможіть нам з перекладом.",
"project-preview-title": "Попередній перегляд того, що ви будете створювати",
@@ -332,7 +340,7 @@
"if-help-university": "Ми вже зробили багато роботи. Підтримайте довгий шлях нашої благодійної організації."
},
"donate": {
- "title": "Підтримати нашу некомерційну організацію",
+ "title": "Підтримайте нашу організацію",
"processing": "Ми опрацьовуємо ваш внесок.",
"redirecting": "Переадресація...",
"thanks": "Дякуємо за внесок",
@@ -357,7 +365,6 @@
"become-supporter": "Зробити внесок",
"duration": "Станьте одноразовим спонсором нашої некомерційної організації.",
"duration-2": "Станьте спонсором нашої некомерційної організації (щомісячний внесок).",
- "duration-3": "Станьте спонсором нашої некомерційної організації (щорічний внесок).",
"duration-4": "Станьте спонсором нашої некомерційної організації",
"nicely-done": "Чудово. Ви щойно завершили {{block}}.",
"credit-card": "Кредитна картка",
@@ -460,7 +467,8 @@
"iframe-preview": "Передперегляд {{title}}",
"iframe-alert": "Зазвичай це посилання перенесло б вас на інший вебсайт! Воно працює. Це посилання на: {{externalLink}}",
"iframe-form-submit-alert": "Зазвичай ця форма буде відправлена! Вона буде відправлена на: {{externalLink}}",
- "document-notfound": "документ не знайдено"
+ "document-notfound": "документ не знайдено",
+ "slow-load-msg": "Схоже, це займає більше часу, ніж зазвичай. Будь ласка, спробуйте оновити сторінку."
},
"icons": {
"gold-cup": "Золотий кубок",
@@ -475,10 +483,11 @@
"hint": "Підказка",
"heart": "Серце",
"initial": "Початковий",
+ "input-reset": "Очистити пошукові запити",
"info": "Інформація",
"spacer": "Роздільник",
"toggle": "Перемкнути галочку",
- "magnifier": "лупа"
+ "magnifier": "Надіслати пошукові запити"
},
"aria": {
"fcc-curriculum": "Навчальний план freeCodeCamp",
@@ -504,10 +513,11 @@
"step": "Крок",
"steps": "Кроки",
"steps-for": "Кроки для {{blockTitle}}",
- "code-example": "{{codeName}} code example"
+ "code-example": "Приклад коду {{codeName}}",
+ "opens-new-window": "Відкривається у новому вікні"
},
"flash": {
- "honest-first": "Щоб отримати сертифікацію, ви повинні спочатку прийняти нашу політику академічної доброчесності",
+ "honest-first": "Щоб отримати сертифікацію, ви повинні спочатку погодитись з нашою політикою академічної доброчесності",
"really-weird": "Щось пішло не так. Якщо це повториться, будь ласка, повідомте про це за посиланням: https://github.com/freeCodeCamp/freeCodeCamp/issues/new",
"not-right": "Щось пішло не так. Звіт було сформовано і команду freeCodeCamp.org вже сповістили.",
"went-wrong": "Щось пішло не так. Будь ласка, перевірте та повторіть спробу.",
@@ -586,7 +596,8 @@
"editor-url": "Не забудьте відправити Live App URL-адресу.",
"http-url": "Не можна використовувати ненадійну (http) URL-адресу.",
"own-work-url": "Не забудьте відправити власну роботу.",
- "publicly-visible-url": "Не забудьте відправити загальнодоступну URL-адресу додатку."
+ "publicly-visible-url": "Не забудьте відправити загальнодоступну URL-адресу додатку.",
+ "path-url": "Можливо, ви хочете надіслати кореневий шлях, тобто https://example.com, а не https://example.com/path"
},
"certification": {
"executive": "Виконавчий директор, freeCodeCamp.org",
@@ -668,8 +679,49 @@
"Cat and Dog Image Classifier": "Класифікатор зображень котів і собак",
"Book Recommendation Engine using KNN": "Інструмент рекомендацій книг із використанням KNN",
"Linear Regression Health Costs Calculator": "Калькулятор лінійної регресії витрат на охорону здоров'я",
- "Neural Network SMS Text Classifier": "Нейронна мережа для класифікації текстових SMS"
+ "Neural Network SMS Text Classifier": "Нейронна мережа для класифікації текстових SMS",
+ "Celestial Bodies Database": "База даних «Небесні тіла»",
+ "World Cup Database": "База даних «Чемпіонат світу»",
+ "Salon Appointment Scheduler": "Планувальник «Записи в салоні»",
+ "Periodic Table Database": "База даних «Періодична таблиця»",
+ "Number Guessing Game": "Гра «Вгадай число»",
+ "Build a freeCodeCamp Forum Homepage": "Створіть головну сторінку для форуму freeCodeCamp"
}
+ },
+ "title": {
+ "Responsive Web Design": "Адаптивний вебдизайн",
+ "responsive-web-design": "Сертифікація «Адаптивний вебдизайн»",
+ "JavaScript Algorithms and Data Structures": "Алгоритми JavaScript та структури даних",
+ "javascript-algorithms-and-data-structures": "Сертифікація «Алгоритми JavaScript та структури даних»",
+ "Front End Development Libraries": "Бібліотеки Front End",
+ "front-end-development-libraries": "Сертифікація «Бібліотеки Front End»",
+ "Data Visualization": "Візуалізація даних",
+ "data-visualization": "Сертифікація «Візуалізація даних»",
+ "Relational Database": "Реляційна база даних",
+ "relational-database-v8": "Сертифікація «Реляційна база даних»",
+ "Back End Development and APIs": "Розробка Back End та API",
+ "back-end-development-and-apis": "Сертифікація «Розробка Back End та API»",
+ "Quality Assurance": "Забезпечення якості",
+ "quality-assurance-v7": "Сертифікація «Забезпечення якості»",
+ "Scientific Computing with Python": "Наукові обчислення з Python",
+ "scientific-computing-with-python-v7": "Сертифікація «Наукові обчислення з Python»",
+ "Data Analysis with Python": "Аналіз даних з Python",
+ "data-analysis-with-python-v7": "Сертифікація «Аналіз даних з Python»",
+ "Information Security": "Інформаційна безпека",
+ "information-security-v7": "Сертифікація «Інформаційна безпека»",
+ "Machine Learning with Python": "Машинне навчання з Python",
+ "machine-learning-with-python-v7": "Сертифікація «Машинне навчання з Python»",
+ "Legacy Front End": "Застарілий Front End",
+ "legacy-front-end": "Сертифікація «Front End»",
+ "Legacy Back End": "Застарілий Back End",
+ "legacy-back-end": "Сертифікація «Back End»",
+ "Legacy Data Visualization": "Застаріла візуалізація даних",
+ "legacy-data-visualization": "Сертифікація «Візуалізація даних»",
+ "Legacy Information Security and Quality Assurance": "Застаріла інформаційна безпека та забезпечення якості",
+ "information-security-and-quality-assurance": "Сертифікація «Інформаційна безпека та забезпечення якості»",
+ "Legacy Full Stack Certification": "Застаріла сертифікація «Full Stack»",
+ "Legacy Full Stack": "Застарілий Full Stack",
+ "full-stack": "Сертифікація «Full Stack»"
}
},
"certification-card": {
diff --git a/client/i18n/schema-validation.ts b/client/i18n/schema-validation.ts
index 02c0e86a1b6835..d9ccd807d23e10 100644
--- a/client/i18n/schema-validation.ts
+++ b/client/i18n/schema-validation.ts
@@ -215,7 +215,7 @@ const schemaValidation = (
if (
fileName === 'motivation' &&
!(fileJson.motivationalQuotes as MotivationalQuotes).every(
- (object: object) =>
+ object =>
Object.prototype.hasOwnProperty.call(object, 'quote') &&
Object.prototype.hasOwnProperty.call(object, 'author')
)
diff --git a/client/package.json b/client/package.json
index e9a1870600e159..a625e27daf1f1e 100644
--- a/client/package.json
+++ b/client/package.json
@@ -6,7 +6,7 @@
"private": true,
"engines": {
"node": ">=16",
- "npm": ">=8"
+ "pnpm": "7"
},
"repository": {
"type": "git",
@@ -19,44 +19,48 @@
"author": "freeCodeCamp ",
"main": "none",
"scripts": {
- "prebuild": "npm --prefix ../ run create:config && npm run build:workers -- --env production",
+ "prebuild": "pnpm -w run create:config && pnpm run build:workers --env production",
"build": "cross-env NODE_OPTIONS=\"--max-old-space-size=7168\" gatsby build --prefix-paths",
"build:workers": "cross-env NODE_OPTIONS=\"--max-old-space-size=7168\" webpack --config ./webpack-workers.js",
"clean": "gatsby clean",
- "predevelop": "npm --prefix ../ run create:config && npm run build:workers -- --env development",
+ "predevelop": "pnpm -w run create:config && pnpm run build:workers --env development",
"develop": "cross-env NODE_OPTIONS=\"--max-old-space-size=5000\" gatsby develop --inspect=9230",
"lint": "ts-node ./i18n/schema-validation.ts",
"serve": "gatsby serve -p 8000",
"serve-ci": "serve -l 8000 -c serve.json public",
- "prestand-alone": "npm run prebuild",
+ "prestand-alone": "pnpm run prebuild",
"stand-alone": "gatsby develop",
"validate-keys": "ts-node --project ../tsconfig.json ../tools/scripts/lint/validate-keys"
},
"dependencies": {
"@babel/plugin-proposal-export-default-from": "7.18.10",
"@babel/plugin-proposal-function-bind": "7.18.9",
+ "@babel/plugin-transform-runtime": "^7.19.6",
"@babel/polyfill": "7.12.1",
"@babel/preset-env": "7.20.2",
"@babel/preset-react": "7.18.6",
- "@babel/standalone": "7.20.6",
- "@fortawesome/fontawesome-svg-core": "6.2.1",
- "@fortawesome/free-brands-svg-icons": "6.2.1",
- "@fortawesome/free-solid-svg-icons": "6.2.1",
+ "@babel/runtime": "^7.20.13",
+ "@babel/standalone": "7.20.15",
+ "@fortawesome/fontawesome-svg-core": "6.3.0",
+ "@fortawesome/free-brands-svg-icons": "6.3.0",
+ "@fortawesome/free-solid-svg-icons": "6.3.0",
"@fortawesome/react-fontawesome": "0.2.0",
"@freecodecamp/curriculum-helpers": "1.1.0",
"@freecodecamp/loop-protect": "3.0.0",
"@freecodecamp/react-bootstrap": "0.32.3",
- "@freecodecamp/react-calendar-heatmap": "1.0.0",
+ "@freecodecamp/react-calendar-heatmap": "1.1.0",
"@freecodecamp/strip-comments": "3.0.1",
- "@growthbook/growthbook-react": "0.10.1",
- "@loadable/component": "5.15.2",
+ "@growthbook/growthbook-react": "0.12.0",
+ "@loadable/component": "5.15.3",
"@reach/router": "1.3.4",
+ "@redux-saga/core": "^1.2.2",
"@sentry/gatsby": "6.19.7",
- "@stripe/react-stripe-js": "1.16.0",
- "@stripe/stripe-js": "1.46.0",
- "@types/react-scrollable-anchor": "0.6.1",
- "algoliasearch": "4.14.2",
+ "@stripe/react-stripe-js": "1.16.5",
+ "@stripe/stripe-js": "1.48.0",
+ "@testing-library/jest-dom": "5.16.5",
+ "algoliasearch": "4.15.0",
"assert": "2.0.0",
+ "babel-loader": "8.3.0",
"babel-plugin-preval": "5.1.0",
"babel-plugin-prismjs": "2.1.0",
"bezier-easing": "2.1.0",
@@ -64,34 +68,38 @@
"buffer": "6.0.3",
"chai": "4.3.7",
"crypto-browserify": "3.12.0",
- "date-fns": "2.27.0",
+ "date-fns": "2.29.3",
"enzyme": "3.11.0",
"enzyme-adapter-react-16": "1.15.7",
- "final-form": "4.20.7",
- "gatsby": "3.14.6",
- "gatsby-cli": "3.14.2",
+ "eslint": "7",
+ "final-form": "4.20.9",
+ "gatsby": "3.15.0",
+ "gatsby-cli": "3.15.0",
+ "gatsby-link": "3.15.0",
"gatsby-plugin-advanced-sitemap": "2.1.0",
- "gatsby-plugin-create-client-paths": "3.14.0",
- "gatsby-plugin-manifest": "3.14.0",
- "gatsby-plugin-postcss": "4.14.0",
- "gatsby-plugin-react-helmet": "4.14.0",
+ "gatsby-plugin-create-client-paths": "3.15.0",
+ "gatsby-plugin-manifest": "3.15.0",
+ "gatsby-plugin-pnpm": "^1.2.10",
+ "gatsby-plugin-postcss": "4.15.0",
+ "gatsby-plugin-react-helmet": "4.15.0",
"gatsby-plugin-remove-serviceworker": "1.0.0",
- "gatsby-remark-prismjs": "5.11.0",
- "gatsby-source-filesystem": "3.14.0",
- "gatsby-transformer-remark": "4.11.0",
+ "gatsby-remark-prismjs": "5.12.0",
+ "gatsby-source-filesystem": "3.15.0",
+ "gatsby-transformer-remark": "4.12.0",
"i18next": "20.6.1",
- "jquery": "3.6.1",
+ "jquery": "3.6.3",
"lodash": "4.17.21",
"lodash-es": "4.17.21",
"monaco-editor": "0.28.1",
"nanoid": "3.3.4",
"normalize-url": "4.5.1",
"path-browserify": "1.0.1",
- "postcss": "8.4.19",
+ "postcss": "8.4.21",
"prismjs": "1.29.0",
"process": "0.11.10",
"prop-types": "15.8.1",
- "query-string": "7.0.1",
+ "qrcode.react": "^3.1.0",
+ "query-string": "7.1.3",
"react": "16.14.0",
"react-dom": "16.14.0",
"react-final-form": "6.5.9",
@@ -100,8 +108,8 @@
"react-helmet": "6.1.0",
"react-hotkeys": "2.0.0",
"react-i18next": "11.18.6",
- "react-instantsearch-dom": "6.38.1",
- "react-lazy-load": "3.1.14",
+ "react-instantsearch-core": "6.39.0",
+ "react-instantsearch-dom": "6.39.0",
"react-monaco-editor": "0.40.0",
"react-redux": "5.1.2",
"react-reflex": "4.0.9",
@@ -111,30 +119,56 @@
"react-tooltip": "4.5.1",
"react-transition-group": "4.4.5",
"react-youtube": "7.14.0",
- "redux": "4.2.0",
+ "redux": "4.2.1",
"redux-actions": "2.6.5",
"redux-devtools-extension": "2.13.9",
"redux-observable": "1.2.0",
- "redux-saga": "1.2.1",
+ "redux-saga": "1.2.2",
"reselect": "4.1.7",
"rxjs": "6.6.7",
- "sanitize-html": "2.7.3",
+ "sanitize-html": "2.10.0",
"sass.js": "0.11.1",
"sha-1": "1.0.0",
"store": "2.0.12",
"stream-browserify": "3.0.0",
"tone": "14.7.77",
- "typescript": "4.9.3",
+ "typescript": "4.9.5",
"util": "0.12.5",
"uuid": "8.3.2",
- "validator": "13.7.0"
+ "validator": "13.9.0"
},
"devDependencies": {
- "@babel/types": "7.20.5",
- "@codesee/babel-plugin-instrument": "0.451.0",
- "@codesee/tracker": "0.451.0",
+ "@babel/types": "7.20.7",
+ "@codesee/babel-plugin-instrument": "0.525.0",
+ "@codesee/tracker": "0.525.0",
"@testing-library/jest-dom": "5.16.5",
"@testing-library/react": "12.1.5",
+ "@types/chai": "^4.3.4",
+ "@types/enzyme": "^3.10.12",
+ "@types/enzyme-adapter-react-16": "1.0.6",
+ "@types/jest": "27.5.2",
+ "@types/jquery": "^3.5.16",
+ "@types/loadable__component": "5.13.4",
+ "@types/lodash-es": "^4.17.6",
+ "@types/prismjs": "^1.26.0",
+ "@types/reach__router": "1.3.11",
+ "@types/react": "16.14.35",
+ "@types/react-dom": "16.9.18",
+ "@types/react-gtm-module": "2.0.1",
+ "@types/react-helmet": "6.1.6",
+ "@types/react-instantsearch-core": "6.26.3",
+ "@types/react-instantsearch-dom": "6.12.3",
+ "@types/react-redux": "7.1.25",
+ "@types/react-responsive": "8.0.5",
+ "@types/react-scrollable-anchor": "0.6.1",
+ "@types/react-spinkit": "3.0.7",
+ "@types/react-test-renderer": "16.9.5",
+ "@types/react-transition-group": "4.4.5",
+ "@types/redux-actions": "2.6.2",
+ "@types/sanitize-html": "^2.8.0",
+ "@types/store": "^2.0.2",
+ "@types/testing-library__jest-dom": "^5.14.5",
+ "@types/validator": "^13.7.12",
"autoprefixer": "10.4.13",
"babel-plugin-transform-imports": "2.0.0",
"chokidar": "3.5.3",
diff --git a/client/plugins/fcc-source-challenges/package.json b/client/plugins/fcc-source-challenges/package.json
index 03a6736cc502ad..8c5688335f0d64 100644
--- a/client/plugins/fcc-source-challenges/package.json
+++ b/client/plugins/fcc-source-challenges/package.json
@@ -6,7 +6,7 @@
"private": true,
"engines": {
"node": ">=16",
- "npm": ">=8"
+ "pnpm": "7"
},
"repository": {
"type": "git",
diff --git a/client/plugins/gatsby-remark-node-identity/package.json b/client/plugins/gatsby-remark-node-identity/package.json
index 0836df6b52206b..68d344bee43cc1 100644
--- a/client/plugins/gatsby-remark-node-identity/package.json
+++ b/client/plugins/gatsby-remark-node-identity/package.json
@@ -6,7 +6,7 @@
"private": true,
"engines": {
"node": ">=16",
- "npm": ">=8"
+ "pnpm": "7"
},
"repository": {
"type": "git",
diff --git a/client/src/__mocks__/completed-challenges.json b/client/src/__mocks__/completed-challenges.json
new file mode 100644
index 00000000000000..3f885759559618
--- /dev/null
+++ b/client/src/__mocks__/completed-challenges.json
@@ -0,0 +1,6572 @@
+[
+ {
+ "id": "bd7123c8c441eddfaeb5bdef",
+ "completedDate": 1475094716730,
+ "files": []
+ },
+ {
+ "id": "5895f70bf9fc0f352b528e64",
+ "completedDate": 1537207306322,
+ "files": []
+ },
+ {
+ "id": "5895f700f9fc0f352b528e63",
+ "completedDate": 1537206156261,
+ "files": []
+ },
+ {
+ "id": "587d8250367417b2b2512c5d",
+ "completedDate": 1537196341863,
+ "files": []
+ },
+ {
+ "id": "587d824f367417b2b2512c5c",
+ "completedDate": 1537196128255,
+ "files": []
+ },
+ {
+ "id": "587d824f367417b2b2512c5b",
+ "completedDate": 1537195761754,
+ "files": []
+ },
+ {
+ "id": "587d824f367417b2b2512c5a",
+ "completedDate": 1537194934561,
+ "files": []
+ },
+ {
+ "id": "587d824f367417b2b2512c59",
+ "completedDate": 1537191541514,
+ "files": []
+ },
+ {
+ "id": "587d824e367417b2b2512c58",
+ "completedDate": 1537191117061,
+ "files": []
+ },
+ {
+ "id": "587d824e367417b2b2512c57",
+ "completedDate": 1537156833598,
+ "files": []
+ },
+ {
+ "id": "587d824e367417b2b2512c56",
+ "completedDate": 1537156784572,
+ "files": []
+ },
+ {
+ "id": "587d824e367417b2b2512c55",
+ "completedDate": 1537156722004,
+ "files": []
+ },
+ {
+ "id": "587d824d367417b2b2512c54",
+ "completedDate": 1537156654992,
+ "files": []
+ },
+ {
+ "id": "587d824d367417b2b2512c53",
+ "completedDate": 1537156621303,
+ "files": []
+ },
+ {
+ "id": "587d824d367417b2b2512c52",
+ "completedDate": 1537156534601,
+ "files": []
+ },
+ {
+ "id": "587d824d367417b2b2512c51",
+ "completedDate": 1537156456357,
+ "files": []
+ },
+ {
+ "id": "587d824d367417b2b2512c50",
+ "completedDate": 1537156425359,
+ "files": []
+ },
+ {
+ "id": "587d824c367417b2b2512c4f",
+ "completedDate": 1537156351862,
+ "files": []
+ },
+ {
+ "id": "587d824c367417b2b2512c4e",
+ "completedDate": 1537155828325,
+ "files": []
+ },
+ {
+ "id": "587d824c367417b2b2512c4d",
+ "completedDate": 1537155787245,
+ "files": []
+ },
+ {
+ "id": "587d824c367417b2b2512c4c",
+ "completedDate": 1537155713207,
+ "files": []
+ },
+ {
+ "id": "587d824b367417b2b2512c4b",
+ "completedDate": 1537155677686,
+ "files": []
+ },
+ {
+ "id": "587d824b367417b2b2512c4a",
+ "completedDate": 1537155558649,
+ "files": []
+ },
+ {
+ "id": "587d824b367417b2b2512c49",
+ "completedDate": 1537155417358,
+ "files": []
+ },
+ {
+ "id": "587d824b367417b2b2512c48",
+ "completedDate": 1537155376892,
+ "files": []
+ },
+ {
+ "id": "587d824b367417b2b2512c47",
+ "completedDate": 1537155346597,
+ "files": []
+ },
+ {
+ "id": "587d824a367417b2b2512c46",
+ "completedDate": 1537155223667,
+ "files": []
+ },
+ {
+ "id": "5e9a0e9ef99a403d019610cd",
+ "completedDate": 1594737025062,
+ "files": []
+ },
+ {
+ "id": "5e9a0e9ef99a403d019610cc",
+ "completedDate": 1594737019383,
+ "files": []
+ },
+ {
+ "id": "5e9a0e9ef99a403d019610cb",
+ "completedDate": 1594737013076,
+ "files": []
+ },
+ {
+ "id": "5e9a0e9ef99a403d019610ca",
+ "completedDate": 1594737007379,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72da6",
+ "completedDate": 1594736997931,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72da5",
+ "completedDate": 1594736991766,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72da4",
+ "completedDate": 1594736985764,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72da3",
+ "completedDate": 1594736981667,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72da2",
+ "completedDate": 1594736977865,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72da1",
+ "completedDate": 1594736973679,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72da0",
+ "completedDate": 1594736951770,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72d9f",
+ "completedDate": 1594736947277,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72d9e",
+ "completedDate": 1594736941520,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72d9d",
+ "completedDate": 1594736936531,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72d9c",
+ "completedDate": 1594736931464,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72d9b",
+ "completedDate": 1594736928913,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72d9a",
+ "completedDate": 1594736926241,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72d99",
+ "completedDate": 1594736922879,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72d98",
+ "completedDate": 1594736916015,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72d97",
+ "completedDate": 1594736913489,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72d96",
+ "completedDate": 1594736911022,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72d95",
+ "completedDate": 1594736906356,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72d94",
+ "completedDate": 1594736902879,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72d93",
+ "completedDate": 1594736899068,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72d92",
+ "completedDate": 1594736892768,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72d91",
+ "completedDate": 1594736887031,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72d90",
+ "completedDate": 1594736881826,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72d8f",
+ "completedDate": 1594736878283,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72d8e",
+ "completedDate": 1594736870814,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72d8d",
+ "completedDate": 1594736867216,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72d8c",
+ "completedDate": 1594736860834,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72d8b",
+ "completedDate": 1594736854454,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72d8a",
+ "completedDate": 1594736850998,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72d89",
+ "completedDate": 1594736845393,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72d88",
+ "completedDate": 1594736783329,
+ "files": []
+ },
+ {
+ "id": "5e8f2f13c4cdbe86b5c72d87",
+ "completedDate": 1594736780706,
+ "files": []
+ },
+ {
+ "id": "5ea9997bbec2e9bc47e94db4",
+ "completedDate": 1594736766657,
+ "files": []
+ },
+ {
+ "id": "5ea9997bbec2e9bc47e94db3",
+ "completedDate": 1594736760393,
+ "files": []
+ },
+ {
+ "id": "5ea9997bbec2e9bc47e94db2",
+ "completedDate": 1594736756583,
+ "files": []
+ },
+ {
+ "id": "5ea9997bbec2e9bc47e94db1",
+ "completedDate": 1594736752876,
+ "files": []
+ },
+ {
+ "id": "5ea9997bbec2e9bc47e94db0",
+ "completedDate": 1594736746497,
+ "files": []
+ },
+ {
+ "id": "5ea9997bbec2e9bc47e94daf",
+ "completedDate": 1594736741574,
+ "files": []
+ },
+ {
+ "id": "5ea9997bbec2e9bc47e94dae",
+ "completedDate": 1594736737468,
+ "files": []
+ },
+ {
+ "id": "5e9a0a8e09c5df3cc3600eda",
+ "completedDate": 1594736722645,
+ "files": []
+ },
+ {
+ "id": "5e9a0a8e09c5df3cc3600ed9",
+ "completedDate": 1594736717640,
+ "files": []
+ },
+ {
+ "id": "5e9a0a8e09c5df3cc3600ed8",
+ "completedDate": 1594736714767,
+ "files": []
+ },
+ {
+ "id": "5e9a0a8e09c5df3cc3600ed7",
+ "completedDate": 1594736707875,
+ "files": []
+ },
+ {
+ "id": "5e9a0a8e09c5df3cc3600ed6",
+ "completedDate": 1594736702192,
+ "files": []
+ },
+ {
+ "id": "5e9a0a8e09c5df3cc3600ed5",
+ "completedDate": 1594736698412,
+ "files": []
+ },
+ {
+ "id": "5e9a0a8e09c5df3cc3600ed4",
+ "completedDate": 1594736694389,
+ "files": []
+ },
+ {
+ "id": "5e9a0a8e09c5df3cc3600ed3",
+ "completedDate": 1594736687971,
+ "files": []
+ },
+ {
+ "id": "5e9a0a8e09c5df3cc3600ed2",
+ "completedDate": 1594736682613,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c167",
+ "completedDate": 1594736675575,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c166",
+ "completedDate": 1594736668250,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c165",
+ "completedDate": 1594736665022,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c164",
+ "completedDate": 1594736659263,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c163",
+ "completedDate": 1594736655408,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c162",
+ "completedDate": 1594736649726,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c161",
+ "completedDate": 1594736645479,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c160",
+ "completedDate": 1594736641203,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c15f",
+ "completedDate": 1594736636454,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c15e",
+ "completedDate": 1594736632226,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c15d",
+ "completedDate": 1594736627710,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c15c",
+ "completedDate": 1594736622070,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c15b",
+ "completedDate": 1594736618054,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c15a",
+ "completedDate": 1594736614700,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c159",
+ "completedDate": 1594736608320,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c158",
+ "completedDate": 1594736602219,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c157",
+ "completedDate": 1594736598552,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c156",
+ "completedDate": 1594736593024,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c155",
+ "completedDate": 1594736580318,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c154",
+ "completedDate": 1594736568877,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c153",
+ "completedDate": 1594736563755,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c152",
+ "completedDate": 1594736552154,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c151",
+ "completedDate": 1594736546567,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c150",
+ "completedDate": 1594736539257,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c14f",
+ "completedDate": 1594736536366,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c14e",
+ "completedDate": 1594736532795,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c14d",
+ "completedDate": 1594736530152,
+ "files": []
+ },
+ {
+ "id": "5e9a093a74c4063ca6f7c14c",
+ "completedDate": 1594736526774,
+ "files": []
+ },
+ {
+ "id": "5e7b9f6a0b6c005b0e76f097",
+ "completedDate": 1594736494981,
+ "files": []
+ },
+ {
+ "id": "5e7b9f6a0b6c005b0e76f096",
+ "completedDate": 1594736491249,
+ "files": []
+ },
+ {
+ "id": "5e7b9f690b6c005b0e76f095",
+ "completedDate": 1594736486246,
+ "files": []
+ },
+ {
+ "id": "5e7b9f190b6c005b0e76f090",
+ "completedDate": 1594736476917,
+ "files": []
+ },
+ {
+ "id": "5e7b9f180b6c005b0e76f08f",
+ "completedDate": 1594736461881,
+ "files": []
+ },
+ {
+ "id": "5e7b9f180b6c005b0e76f08e",
+ "completedDate": 1594736452018,
+ "files": []
+ },
+ {
+ "id": "5e7b9f180b6c005b0e76f08d",
+ "completedDate": 1594736444874,
+ "files": []
+ },
+ {
+ "id": "5e7b9f180b6c005b0e76f08c",
+ "completedDate": 1594736437803,
+ "files": []
+ },
+ {
+ "id": "5e7b9f170b6c005b0e76f08b",
+ "completedDate": 1594736432528,
+ "files": []
+ },
+ {
+ "id": "5e7b9f170b6c005b0e76f08a",
+ "completedDate": 1594736422051,
+ "files": []
+ },
+ {
+ "id": "5e7b9f170b6c005b0e76f088",
+ "completedDate": 1594736417716,
+ "files": []
+ },
+ {
+ "id": "5e7b9f170b6c005b0e76f087",
+ "completedDate": 1594736414175,
+ "files": []
+ },
+ {
+ "id": "5e7b9f160b6c005b0e76f086",
+ "completedDate": 1594736410906,
+ "files": []
+ },
+ {
+ "id": "5e7b9f160b6c005b0e76f085",
+ "completedDate": 1594736379721,
+ "files": []
+ },
+ {
+ "id": "5e7b9f150b6c005b0e76f080",
+ "completedDate": 1594736373639,
+ "files": []
+ },
+ {
+ "id": "5e7b9f150b6c005b0e76f07f",
+ "completedDate": 1594736365244,
+ "files": []
+ },
+ {
+ "id": "5e7b9f140b6c005b0e76f07e",
+ "completedDate": 1594736358778,
+ "files": []
+ },
+ {
+ "id": "5e7b9f140b6c005b0e76f07d",
+ "completedDate": 1594736353015,
+ "files": []
+ },
+ {
+ "id": "5e7b9f0e0b6c005b0e76f07c",
+ "completedDate": 1594736348722,
+ "files": []
+ },
+ {
+ "id": "5e7b9f0e0b6c005b0e76f07b",
+ "completedDate": 1594736342374,
+ "files": []
+ },
+ {
+ "id": "5e7b9f0e0b6c005b0e76f07a",
+ "completedDate": 1594736336127,
+ "files": []
+ },
+ {
+ "id": "5e7b9f0d0b6c005b0e76f076",
+ "completedDate": 1594736332128,
+ "files": []
+ },
+ {
+ "id": "5e7b9f0d0b6c005b0e76f075",
+ "completedDate": 1594736324629,
+ "files": []
+ },
+ {
+ "id": "5e7b9f0c0b6c005b0e76f074",
+ "completedDate": 1594736317130,
+ "files": []
+ },
+ {
+ "id": "5e7b9f0c0b6c005b0e76f073",
+ "completedDate": 1594736312374,
+ "files": []
+ },
+ {
+ "id": "5e7b9f0c0b6c005b0e76f072",
+ "completedDate": 1594736298454,
+ "files": []
+ },
+ {
+ "id": "5e7b9f0c0b6c005b0e76f071",
+ "completedDate": 1594736291062,
+ "files": []
+ },
+ {
+ "id": "5e7b9f0b0b6c005b0e76f070",
+ "completedDate": 1594736281756,
+ "files": []
+ },
+ {
+ "id": "5e7b9f0b0b6c005b0e76f06f",
+ "completedDate": 1594736276938,
+ "files": []
+ },
+ {
+ "id": "5e7b9f0b0b6c005b0e76f06e",
+ "completedDate": 1594736270403,
+ "files": []
+ },
+ {
+ "id": "5e7b9f0b0b6c005b0e76f06d",
+ "completedDate": 1594736266728,
+ "files": []
+ },
+ {
+ "id": "5e7b9f0a0b6c005b0e76f06c",
+ "completedDate": 1594736256389,
+ "files": []
+ },
+ {
+ "id": "5e7b9f0a0b6c005b0e76f069",
+ "completedDate": 1594736249458,
+ "files": []
+ },
+ {
+ "id": "5e7b9f090b6c005b0e76f068",
+ "completedDate": 1594736240329,
+ "files": []
+ },
+ {
+ "id": "5e7b9f090b6c005b0e76f067",
+ "completedDate": 1594736231416,
+ "files": []
+ },
+ {
+ "id": "5e7b9f090b6c005b0e76f066",
+ "completedDate": 1594736222820,
+ "files": []
+ },
+ {
+ "id": "5e7b9f090b6c005b0e76f065",
+ "completedDate": 1594736189335,
+ "files": []
+ },
+ {
+ "id": "5e7b9f080b6c005b0e76f064",
+ "completedDate": 1594736184197,
+ "files": []
+ },
+ {
+ "id": "5e7b9f080b6c005b0e76f063",
+ "completedDate": 1594736179115,
+ "files": []
+ },
+ {
+ "id": "5e7b9f080b6c005b0e76f062",
+ "completedDate": 1594736170111,
+ "files": []
+ },
+ {
+ "id": "5e7b9f070b6c005b0e76f061",
+ "completedDate": 1594736166777,
+ "files": []
+ },
+ {
+ "id": "5e7b9f070b6c005b0e76f060",
+ "completedDate": 1594736155841,
+ "files": []
+ },
+ {
+ "id": "5e7b9f070b6c005b0e76f05f",
+ "completedDate": 1594736151207,
+ "files": []
+ },
+ {
+ "id": "5e7b9f070b6c005b0e76f05e",
+ "completedDate": 1594736139632,
+ "files": []
+ },
+ {
+ "id": "5e7b9f070b6c005b0e76f05d",
+ "completedDate": 1594736134513,
+ "files": []
+ },
+ {
+ "id": "5e7b9f060b6c005b0e76f05c",
+ "completedDate": 1594736127815,
+ "files": []
+ },
+ {
+ "id": "5e7b9f060b6c005b0e76f05b",
+ "completedDate": 1594736121855,
+ "files": []
+ },
+ {
+ "id": "5e7b9f060b6c005b0e76f05a",
+ "completedDate": 1594736116852,
+ "files": []
+ },
+ {
+ "id": "5e7b9f060b6c005b0e76f059",
+ "completedDate": 1594736110114,
+ "files": []
+ },
+ {
+ "id": "5e7b9f050b6c005b0e76f058",
+ "completedDate": 1594736099389,
+ "files": []
+ },
+ {
+ "id": "5e7b9f050b6c005b0e76f057",
+ "completedDate": 1594736079471,
+ "files": []
+ },
+ {
+ "id": "5e7b9f050b6c005b0e76f056",
+ "completedDate": 1594736073962,
+ "files": []
+ },
+ {
+ "id": "5e6a54c358d3af90110a60a3",
+ "completedDate": 1594736049167,
+ "files": []
+ },
+ {
+ "id": "5e6a54ba58d3af90110a60a2",
+ "completedDate": 1594736044195,
+ "files": []
+ },
+ {
+ "id": "5e6a54af58d3af90110a60a1",
+ "completedDate": 1594736040286,
+ "files": []
+ },
+ {
+ "id": "5e6a54a558d3af90110a60a0",
+ "completedDate": 1594736018884,
+ "files": []
+ },
+ {
+ "id": "58a25bcff9fc0f352b528e7e",
+ "completedDate": 1537204939276,
+ "files": []
+ },
+ {
+ "id": "58a25bcff9fc0f352b528e7d",
+ "completedDate": 1537204689114,
+ "files": []
+ },
+ {
+ "id": "587d7db3367417b2b2512b8f",
+ "completedDate": 1528836297983,
+ "files": []
+ },
+ {
+ "id": "587d7db3367417b2b2512b8e",
+ "completedDate": 1528836242517,
+ "files": []
+ },
+ {
+ "id": "587d8251367417b2b2512c64",
+ "completedDate": 1584724916681,
+ "files": []
+ },
+ {
+ "id": "5a23c84252665b21eecc8040",
+ "completedDate": 1581377129224,
+ "files": []
+ },
+ {
+ "id": "5900f3881000cf542c50fe9b",
+ "completedDate": 1581267049205,
+ "files": []
+ },
+ {
+ "id": "5900f3851000cf542c50fe98",
+ "completedDate": 1581261142636,
+ "files": []
+ },
+ {
+ "id": "5a51eabcad78bf416f316e2a",
+ "completedDate": 1581259050886,
+ "files": []
+ },
+ {
+ "id": "5900f37b1000cf542c50fe8e",
+ "completedDate": 1581220627138,
+ "files": []
+ },
+ {
+ "id": "5900f37a1000cf542c50fe8c",
+ "completedDate": 1563131237063,
+ "files": []
+ },
+ {
+ "id": "5900f3781000cf542c50fe8b",
+ "completedDate": 1581209840334,
+ "files": []
+ },
+ {
+ "id": "5900f3761000cf542c50fe89",
+ "completedDate": 1581200258395,
+ "files": []
+ },
+ {
+ "id": "5900f3741000cf542c50fe87",
+ "completedDate": 1581197527928,
+ "files": []
+ },
+ {
+ "id": "5900f3731000cf542c50fe86",
+ "completedDate": 1581194166358,
+ "files": []
+ },
+ {
+ "id": "5900f3721000cf542c50fe85",
+ "completedDate": 1581192983102,
+ "files": []
+ },
+ {
+ "id": "5900f3711000cf542c50fe84",
+ "completedDate": 1581107068452,
+ "files": []
+ },
+ {
+ "id": "5cdafbb0291309899753167f",
+ "completedDate": 1574302240996,
+ "files": []
+ },
+ {
+ "id": "5ccfad82bb2dc6c965a848e5",
+ "completedDate": 1574302514181,
+ "files": []
+ },
+ {
+ "id": "5c3dda8b4d8df89bea71600f",
+ "completedDate": 1574302492985,
+ "files": []
+ },
+ {
+ "id": "5cdafbe72913098997531682",
+ "completedDate": 1574302346019,
+ "files": []
+ },
+ {
+ "id": "5cdafbd72913098997531681",
+ "completedDate": 1574302316716,
+ "files": []
+ },
+ {
+ "id": "5cdafbc32913098997531680",
+ "completedDate": 1574302286941,
+ "files": []
+ },
+ {
+ "id": "5cddbfd622f1a59093ec611d",
+ "completedDate": 1574302200001,
+ "files": []
+ },
+ {
+ "id": "5cfa550e84205a357704ccb6",
+ "completedDate": 1574302164631,
+ "files": []
+ },
+ {
+ "id": "5cd9a70215d3c4e65518328f",
+ "completedDate": 1574302134656,
+ "files": []
+ },
+ {
+ "id": "5cc0bd7a49b71cb96132e54c",
+ "completedDate": 1574302122706,
+ "files": []
+ },
+ {
+ "id": "5c6c06847491271903d37cfd",
+ "completedDate": 1574301689702,
+ "files": []
+ },
+ {
+ "id": "5cfa3679138e7d9595b9d9d4",
+ "completedDate": 1572140656699,
+ "files": []
+ },
+ {
+ "id": "597f24c1dda4e70f53c79c81",
+ "completedDate": 1568427791545,
+ "files": []
+ },
+ {
+ "id": "5a23c84252665b21eecc7e82",
+ "completedDate": 1568426995929,
+ "files": []
+ },
+ {
+ "id": "59669d08d75b60482359409f",
+ "completedDate": 1568390166116,
+ "files": []
+ },
+ {
+ "id": "594d8d0ab97724821379b1e6",
+ "completedDate": 1568387040347,
+ "files": []
+ },
+ {
+ "id": "594810f028c0303b75339ad1",
+ "completedDate": 1568346223877,
+ "files": []
+ },
+ {
+ "id": "596e457071c35c882915b3e4",
+ "completedDate": 1568334942324,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf0887a",
+ "completedDate": 1475094757107,
+ "files": []
+ },
+ {
+ "id": "bd7123c9c441eddfaeb4bdef",
+ "completedDate": 1475173147497,
+ "files": []
+ },
+ {
+ "id": "587d7b89367417b2b2512b49",
+ "completedDate": 1528729165835,
+ "files": []
+ },
+ {
+ "id": "587d7b8c367417b2b2512b58",
+ "completedDate": 1528742042170,
+ "files": []
+ },
+ {
+ "id": "587d7b8c367417b2b2512b57",
+ "completedDate": 1528741796573,
+ "files": []
+ },
+ {
+ "id": "587d7b8c367417b2b2512b56",
+ "completedDate": 1528740437095,
+ "files": []
+ },
+ {
+ "id": "587d7b8c367417b2b2512b55",
+ "completedDate": 1528740387410,
+ "files": []
+ },
+ {
+ "id": "5a24bbe0dba28a8d3cbd4c5d",
+ "completedDate": 1528936352198,
+ "files": []
+ },
+ {
+ "id": "587d7dbc367417b2b2512bb1",
+ "completedDate": 1528936259926,
+ "files": []
+ },
+ {
+ "id": "5a94fe1369fb03452672e45d",
+ "completedDate": 1528726237694,
+ "files": []
+ },
+ {
+ "id": "5a94fe0569fb03452672e45c",
+ "completedDate": 1528726188458,
+ "files": []
+ },
+ {
+ "id": "5a94fdf869fb03452672e45b",
+ "completedDate": 1528726170915,
+ "files": []
+ },
+ {
+ "id": "5a90376038fddaf9a66b5d3c",
+ "completedDate": 1528726156897,
+ "files": []
+ },
+ {
+ "id": "5a90375238fddaf9a66b5d3b",
+ "completedDate": 1528726139703,
+ "files": []
+ },
+ {
+ "id": "5a90374338fddaf9a66b5d3a",
+ "completedDate": 1528726130365,
+ "files": []
+ },
+ {
+ "id": "5a90373638fddaf9a66b5d39",
+ "completedDate": 1528726091369,
+ "files": []
+ },
+ {
+ "id": "5a90372638fddaf9a66b5d38",
+ "completedDate": 1528726069769,
+ "files": []
+ },
+ {
+ "id": "5a9036ee38fddaf9a66b5d37",
+ "completedDate": 1528726049483,
+ "files": []
+ },
+ {
+ "id": "5a9036ee38fddaf9a66b5d36",
+ "completedDate": 1528726030349,
+ "files": []
+ },
+ {
+ "id": "5a9036ee38fddaf9a66b5d35",
+ "completedDate": 1528726016678,
+ "files": []
+ },
+ {
+ "id": "5a9036ee38fddaf9a66b5d34",
+ "completedDate": 1528725989219,
+ "files": []
+ },
+ {
+ "id": "5a9036e138fddaf9a66b5d33",
+ "completedDate": 1528725967520,
+ "files": []
+ },
+ {
+ "id": "5a9036d038fddaf9a66b5d32",
+ "completedDate": 1528725949737,
+ "files": []
+ },
+ {
+ "id": "5a858944d96184f06fd60d61",
+ "completedDate": 1528725909984,
+ "files": []
+ },
+ {
+ "id": "587d8255367417b2b2512c73",
+ "completedDate": 1544535146554,
+ "files": []
+ },
+ {
+ "id": "587d8254367417b2b2512c71",
+ "completedDate": 1544451674921,
+ "files": []
+ },
+ {
+ "id": "587d825b367417b2b2512c8d",
+ "completedDate": 1544365302994,
+ "files": []
+ },
+ {
+ "id": "587d8254367417b2b2512c70",
+ "completedDate": 1544279548091,
+ "files": []
+ },
+ {
+ "id": "587d8255367417b2b2512c72",
+ "completedDate": 1544128168268,
+ "files": []
+ },
+ {
+ "id": "587d8253367417b2b2512c6b",
+ "completedDate": 1544016209200,
+ "files": []
+ },
+ {
+ "id": "8d1323c8c441eddfaeb5bdef",
+ "completedDate": 1543963893788,
+ "files": []
+ },
+ {
+ "id": "8d1923c8c441eddfaeb5bdef",
+ "completedDate": 1543842286217,
+ "files": []
+ },
+ {
+ "id": "587d8255367417b2b2512c74",
+ "completedDate": 1539709034423,
+ "files": []
+ },
+ {
+ "id": "587d8250367417b2b2512c60",
+ "completedDate": 1539311762179,
+ "files": []
+ },
+ {
+ "id": "587d824a367417b2b2512c45",
+ "completedDate": 1538239274460,
+ "solution": "https://fcc-message-bored.glitch.me/",
+ "githubLink": "https://github.com/moT01/FCC-Message-Board",
+ "challengeType": 4,
+ "files": []
+ },
+ {
+ "id": "587d824a367417b2b2512c44",
+ "completedDate": 1537981270657,
+ "solution": "https://fcc-stock-check.glitch.me/",
+ "githubLink": "https://github.com/moT01/FCC-Stock-Checker",
+ "challengeType": 4,
+ "files": []
+ },
+ {
+ "id": "587d824a367417b2b2512c43",
+ "completedDate": 1537758214498,
+ "solution": "https://fcc-person-library.glitch.me/",
+ "githubLink": "https://github.com/moT01/FCC-Personal-Library",
+ "challengeType": 4,
+ "files": []
+ },
+ {
+ "id": "587d8249367417b2b2512c42",
+ "completedDate": 1537738041237,
+ "solution": "https://fcc-issues-tracker.glitch.me/",
+ "githubLink": "https://github.com/moT01/FCC-Issue-Tracker",
+ "challengeType": 4,
+ "files": []
+ },
+ {
+ "id": "5b7d72c338cd7e35b63f3e14",
+ "completedDate": 1537653616955,
+ "files": []
+ },
+ {
+ "id": "587d8249367417b2b2512c41",
+ "completedDate": 1537559766968,
+ "solution": "https://fcc-metric-convert.glitch.me/",
+ "githubLink": "https://github.com/moT01/FCC-Metric-Converter",
+ "challengeType": 4,
+ "files": []
+ },
+ {
+ "id": "58966a17f9fc0f352b528e6d",
+ "completedDate": 1537230386653,
+ "solution": "https://torch-player.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "589690e6f9fc0f352b528e6e",
+ "completedDate": 1537223809877,
+ "solution": "https://eager-harmony.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "58a25c98f9fc0f352b528e7f",
+ "completedDate": 1537222634385,
+ "solution": "https://eager-harmony.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "58965611f9fc0f352b528e6c",
+ "completedDate": 1537214717318,
+ "solution": "https://eager-harmony.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "5895f70ef9fc0f352b528e6b",
+ "completedDate": 1537214579404,
+ "solution": "https://eager-harmony.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "5895f70df9fc0f352b528e6a",
+ "completedDate": 1537211858590,
+ "solution": "https://eager-harmony.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "5895f70df9fc0f352b528e69",
+ "completedDate": 1537210025542,
+ "solution": "https://eager-harmony.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "5895f70df9fc0f352b528e68",
+ "completedDate": 1537209494409,
+ "solution": "https://eager-harmony.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "5895f70cf9fc0f352b528e67",
+ "completedDate": 1537208702252,
+ "solution": "https://eager-harmony.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "5895f70cf9fc0f352b528e66",
+ "completedDate": 1537208136182,
+ "solution": "https://eager-harmony.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "5895f70cf9fc0f352b528e65",
+ "completedDate": 1537207848068,
+ "solution": "https://eager-harmony.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "58a25bcef9fc0f352b528e7c",
+ "completedDate": 1537200206872,
+ "solution": "https://seemly-fighter.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d8249367417b2b2512c40",
+ "completedDate": 1537199372195,
+ "solution": "https://tidy-roadway.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d8249367417b2b2512c3f",
+ "completedDate": 1537199285395,
+ "solution": "https://tidy-roadway.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d8249367417b2b2512c3e",
+ "completedDate": 1537198926071,
+ "solution": "https://tidy-roadway.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d8248367417b2b2512c3d",
+ "completedDate": 1537198824551,
+ "solution": "https://tidy-roadway.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d8248367417b2b2512c3c",
+ "completedDate": 1537198750481,
+ "solution": "https://tidy-roadway.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d8248367417b2b2512c3b",
+ "completedDate": 1537198630082,
+ "solution": "https://tidy-roadway.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d8248367417b2b2512c3a",
+ "completedDate": 1537198391567,
+ "solution": "https://tidy-roadway.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d8247367417b2b2512c39",
+ "completedDate": 1537198316053,
+ "solution": "https://tidy-roadway.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d8247367417b2b2512c38",
+ "completedDate": 1537197942090,
+ "solution": "https://tidy-roadway.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d8247367417b2b2512c37",
+ "completedDate": 1537197832144,
+ "solution": "https://tidy-roadway.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d8247367417b2b2512c36",
+ "completedDate": 1537196939178,
+ "solution": "https://tidy-roadway.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fa6367417b2b2512bbf",
+ "completedDate": 1537144978531,
+ "solution": "https://codepen.io/moT01/full/rZxZMq/",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "587d7dae367417b2b2512b7c",
+ "completedDate": 1528904752503,
+ "files": []
+ },
+ {
+ "id": "5a5d02bd919fcf9ca8cf46cb",
+ "completedDate": 1535377692723,
+ "solution": "https://mot01.github.io/FCC-Light-Bright/",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "bd7168d8c242eddfaeb5bd13",
+ "completedDate": 1488665231772,
+ "solution": "http://codepen.io/moT01/pen/JEMxoj?editors=1010",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "bd7178d8c242eddfaeb5bd13",
+ "completedDate": 1488665256488,
+ "solution": "http://codepen.io/moT01/pen/zNLPmV",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "bd7188d8c242eddfaeb5bd13",
+ "completedDate": 1488665304243,
+ "solution": "http://codepen.io/moT01/pen/NdLxNB",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "587d7fa6367417b2b2512bc0",
+ "completedDate": 1535244078849,
+ "solution": "https://codepen.io/moT01/full/rrKwzy/",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "587d825a367417b2b2512c89",
+ "completedDate": 1534614153746,
+ "files": []
+ },
+ {
+ "id": "587d8259367417b2b2512c86",
+ "completedDate": 1534256923082,
+ "files": []
+ },
+ {
+ "id": "587d8259367417b2b2512c85",
+ "completedDate": 1534253945342,
+ "files": []
+ },
+ {
+ "id": "8d5123c8c441eddfaeb5bdef",
+ "completedDate": 1534222674479,
+ "files": []
+ },
+ {
+ "id": "bd7158d8c443edefaeb5bdef",
+ "completedDate": 1498077591986,
+ "solution": "https://mixed-tadpole.glitch.me/",
+ "challengeType": 4,
+ "files": []
+ },
+ {
+ "id": "bd7158d8c443edefaeb5bdff",
+ "completedDate": 1498090900090,
+ "solution": "https://phase-continent.glitch.me/",
+ "challengeType": 4,
+ "files": []
+ },
+ {
+ "id": "bd7158d8c443edefaeb5bd0e",
+ "completedDate": 1499384769762,
+ "solution": "https://ash-airport.glitch.me/",
+ "challengeType": 4,
+ "files": []
+ },
+ {
+ "id": "bd7158d8c443edefaeb5bd0f",
+ "completedDate": 1500911711138,
+ "solution": "https://zenith-double.glitch.me/",
+ "challengeType": 4,
+ "files": []
+ },
+ {
+ "id": "5a8b073d06fa14fcfde687aa",
+ "completedDate": 1533833478381,
+ "solution": "https://fcc-exercise-tracker.herokuapp.com/",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "587d7faf367417b2b2512be9",
+ "completedDate": 1533313441660,
+ "files": []
+ },
+ {
+ "id": "587d7faf367417b2b2512be8",
+ "completedDate": 1533313429792,
+ "files": []
+ },
+ {
+ "id": "587d7fae367417b2b2512be7",
+ "completedDate": 1533313418548,
+ "files": []
+ },
+ {
+ "id": "587d7fae367417b2b2512be6",
+ "completedDate": 1533313409789,
+ "files": []
+ },
+ {
+ "id": "587d7fae367417b2b2512be5",
+ "completedDate": 1533313394341,
+ "files": []
+ },
+ {
+ "id": "587d7fae367417b2b2512be4",
+ "completedDate": 1533313287461,
+ "files": []
+ },
+ {
+ "id": "587d7fae367417b2b2512be3",
+ "completedDate": 1533312971665,
+ "files": []
+ },
+ {
+ "id": "587d7fad367417b2b2512be2",
+ "completedDate": 1533312379130,
+ "files": []
+ },
+ {
+ "id": "587d7fad367417b2b2512be1",
+ "completedDate": 1533305186377,
+ "files": []
+ },
+ {
+ "id": "587d7fad367417b2b2512bdf",
+ "completedDate": 1533305081870,
+ "files": []
+ },
+ {
+ "id": "587d7fac367417b2b2512bde",
+ "completedDate": 1533304893213,
+ "files": []
+ },
+ {
+ "id": "587d7fac367417b2b2512bdd",
+ "completedDate": 1533304473980,
+ "files": []
+ },
+ {
+ "id": "587d7fac367417b2b2512bdc",
+ "completedDate": 1533304357934,
+ "files": []
+ },
+ {
+ "id": "587d7fac367417b2b2512bdb",
+ "completedDate": 1533304277919,
+ "files": []
+ },
+ {
+ "id": "587d7fab367417b2b2512bda",
+ "completedDate": 1533304195179,
+ "files": []
+ },
+ {
+ "id": "587d7fab367417b2b2512bd9",
+ "completedDate": 1533304040401,
+ "files": []
+ },
+ {
+ "id": "587d7fab367417b2b2512bd8",
+ "completedDate": 1533303510955,
+ "files": []
+ },
+ {
+ "id": "587d7fab367417b2b2512bd7",
+ "completedDate": 1533303204725,
+ "files": []
+ },
+ {
+ "id": "587d7faa367417b2b2512bd6",
+ "completedDate": 1533302881077,
+ "files": []
+ },
+ {
+ "id": "587d7faa367417b2b2512bd4",
+ "completedDate": 1533302797436,
+ "files": []
+ },
+ {
+ "id": "587d7faa367417b2b2512bd3",
+ "completedDate": 1533302682051,
+ "files": []
+ },
+ {
+ "id": "587d7faa367417b2b2512bd2",
+ "completedDate": 1533302419381,
+ "files": []
+ },
+ {
+ "id": "587d7fa9367417b2b2512bd1",
+ "completedDate": 1533302159045,
+ "files": []
+ },
+ {
+ "id": "587d7fa9367417b2b2512bd0",
+ "completedDate": 1533302136821,
+ "files": []
+ },
+ {
+ "id": "587d7fa9367417b2b2512bcf",
+ "completedDate": 1533301974907,
+ "files": []
+ },
+ {
+ "id": "587d7fa9367417b2b2512bce",
+ "completedDate": 1533301957042,
+ "files": []
+ },
+ {
+ "id": "587d7fa8367417b2b2512bcd",
+ "completedDate": 1533301918702,
+ "files": []
+ },
+ {
+ "id": "587d7fa8367417b2b2512bcc",
+ "completedDate": 1533301841955,
+ "files": []
+ },
+ {
+ "id": "587d7fa8367417b2b2512bcb",
+ "completedDate": 1533301722365,
+ "files": []
+ },
+ {
+ "id": "587d7fa8367417b2b2512bca",
+ "completedDate": 1533301610183,
+ "files": []
+ },
+ {
+ "id": "587d7fa8367417b2b2512bc9",
+ "completedDate": 1533301532665,
+ "files": []
+ },
+ {
+ "id": "587d7fa7367417b2b2512bc8",
+ "completedDate": 1533301461772,
+ "files": []
+ },
+ {
+ "id": "587d7fa7367417b2b2512bc7",
+ "completedDate": 1533301438297,
+ "files": []
+ },
+ {
+ "id": "587d7fa7367417b2b2512bc6",
+ "completedDate": 1533301332393,
+ "files": []
+ },
+ {
+ "id": "587d7fa7367417b2b2512bc5",
+ "completedDate": 1533301304031,
+ "files": []
+ },
+ {
+ "id": "587d7fa7367417b2b2512bc4",
+ "completedDate": 1533301245248,
+ "files": []
+ },
+ {
+ "id": "587d78b0367417b2b2512b05",
+ "completedDate": 1533273771014,
+ "solution": "https://codepen.io/moT01/full/JBvzNL/",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "587d78af367417b2b2512b04",
+ "completedDate": 1533265342064,
+ "solution": "https://codepen.io/moT01/full/qKyKYL/",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedc08830",
+ "completedDate": 1475096459663,
+ "files": []
+ },
+ {
+ "id": "587d7fb9367417b2b2512c12",
+ "completedDate": 1533055320751,
+ "solution": "https://fcc-mongo-mongoose.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb8367417b2b2512c11",
+ "completedDate": 1533055049560,
+ "solution": "https://fcc-mongo-mongoose.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb8367417b2b2512c10",
+ "completedDate": 1533055004536,
+ "solution": "https://fcc-mongo-mongoose.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb8367417b2b2512c0f",
+ "completedDate": 1533054957664,
+ "solution": "https://fcc-mongo-mongoose.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb8367417b2b2512c0e",
+ "completedDate": 1533054810266,
+ "solution": "https://fcc-mongo-mongoose.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb7367417b2b2512c0d",
+ "completedDate": 1533054731172,
+ "solution": "https://fcc-mongo-mongoose.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb7367417b2b2512c0c",
+ "completedDate": 1533054681787,
+ "solution": "https://fcc-mongo-mongoose.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb7367417b2b2512c0b",
+ "completedDate": 1533054615086,
+ "solution": "https://fcc-mongo-mongoose.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb7367417b2b2512c0a",
+ "completedDate": 1533054496430,
+ "solution": "https://fcc-mongo-mongoose.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb6367417b2b2512c09",
+ "completedDate": 1533054359282,
+ "solution": "https://fcc-mongo-mongoose.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb6367417b2b2512c07",
+ "completedDate": 1533053012175,
+ "solution": "https://fcc-mongo-mongoose.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb6367417b2b2512c06",
+ "completedDate": 1533049464594,
+ "solution": "https://fcc-mongo-mongoose.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb2367417b2b2512bf8",
+ "completedDate": 1533047350131,
+ "solution": "https://fcc-basic-node-and-express.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb2367417b2b2512bf7",
+ "completedDate": 1533047240645,
+ "solution": "https://fcc-basic-node-and-express.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb2367417b2b2512bf6",
+ "completedDate": 1533046595396,
+ "solution": "https://fcc-basic-node-and-express.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb2367417b2b2512bf5",
+ "completedDate": 1533046425247,
+ "solution": "https://fcc-basic-node-and-express.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb1367417b2b2512bf4",
+ "completedDate": 1533044706441,
+ "solution": "https://fcc-basic-node-and-express.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb1367417b2b2512bf3",
+ "completedDate": 1533044029688,
+ "solution": "https://fcc-basic-node-and-express.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb1367417b2b2512bf2",
+ "completedDate": 1533043449812,
+ "solution": "https://fcc-basic-node-and-express.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb1367417b2b2512bf1",
+ "completedDate": 1533043268417,
+ "solution": "https://fcc-basic-node-and-express.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb0367417b2b2512bf0",
+ "completedDate": 1533042013904,
+ "solution": "https://fcc-basic-node-and-express.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb0367417b2b2512bef",
+ "completedDate": 1533041880166,
+ "solution": "https://fcc-basic-node-and-express.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb0367417b2b2512bee",
+ "completedDate": 1533041574196,
+ "solution": "https://fcc-basic-node-and-express.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb0367417b2b2512bed",
+ "completedDate": 1533041397592,
+ "solution": "https://fcc-basic-node-and-express.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb5367417b2b2512c04",
+ "completedDate": 1533041014569,
+ "solution": "https://fcc-manage-npm-packages.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb5367417b2b2512c03",
+ "completedDate": 1533040923088,
+ "solution": "https://fcc-manage-npm-packages.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb5367417b2b2512c02",
+ "completedDate": 1533040901236,
+ "solution": "https://fcc-manage-npm-packages.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb5367417b2b2512c01",
+ "completedDate": 1533040847451,
+ "solution": "https://fcc-manage-npm-packages.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb4367417b2b2512c00",
+ "completedDate": 1533040209131,
+ "solution": "https://fcc-manage-npm-packages.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb4367417b2b2512bff",
+ "completedDate": 1533040168518,
+ "solution": "https://fcc-manage-npm-packages.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb4367417b2b2512bfe",
+ "completedDate": 1533040145047,
+ "solution": "https://fcc-manage-npm-packages.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb4367417b2b2512bfd",
+ "completedDate": 1533040107526,
+ "solution": "https://fcc-manage-npm-packages.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb3367417b2b2512bfc",
+ "completedDate": 1533040049025,
+ "solution": "https://fcc-manage-npm-packages.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7fb3367417b2b2512bfb",
+ "completedDate": 1533039944300,
+ "solution": "https://fcc-manage-npm-packages.glitch.me/",
+ "files": []
+ },
+ {
+ "id": "587d7dbc367417b2b2512bae",
+ "completedDate": 1532961147572,
+ "solution": "https://fcc-drum-machine.herokuapp.com/",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d403614a",
+ "completedDate": 1532794780112,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036149",
+ "completedDate": 1532794700815,
+ "files": []
+ },
+ {
+ "id": "587d7fa6367417b2b2512bc3",
+ "completedDate": 1531937190203,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036148",
+ "completedDate": 1531489006830,
+ "files": []
+ },
+ {
+ "id": "587d7b83367417b2b2512b37",
+ "completedDate": 1531486599992,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036147",
+ "completedDate": 1531482969362,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036146",
+ "completedDate": 1531482790969,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036145",
+ "completedDate": 1531481644030,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036144",
+ "completedDate": 1531481355387,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036143",
+ "completedDate": 1531453571962,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036142",
+ "completedDate": 1531453316042,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036141",
+ "completedDate": 1531445056603,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d403615b",
+ "completedDate": 1531443499567,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d403615a",
+ "completedDate": 1531433896792,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036159",
+ "completedDate": 1531433516627,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036158",
+ "completedDate": 1531433335857,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036157",
+ "completedDate": 1531432774927,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036156",
+ "completedDate": 1531432281650,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036155",
+ "completedDate": 1531431898900,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036154",
+ "completedDate": 1531429369572,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036153",
+ "completedDate": 1531429194225,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036152",
+ "completedDate": 1531429071050,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036151",
+ "completedDate": 1531428817943,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036150",
+ "completedDate": 1531428663065,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d403614c",
+ "completedDate": 1531428487038,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d403614b",
+ "completedDate": 1531428433090,
+ "files": []
+ },
+ {
+ "id": "5900f3701000cf542c50fe83",
+ "completedDate": 1530277993244,
+ "files": []
+ },
+ {
+ "id": "5900f36f1000cf542c50fe82",
+ "completedDate": 1530277838465,
+ "files": []
+ },
+ {
+ "id": "5900f36e1000cf542c50fe81",
+ "completedDate": 1530222499479,
+ "files": []
+ },
+ {
+ "id": "5900f36e1000cf542c50fe80",
+ "completedDate": 1530221644777,
+ "files": []
+ },
+ {
+ "id": "594810f028c0303b75339acb",
+ "completedDate": 1530015953369,
+ "files": []
+ },
+ {
+ "id": "587d78af367417b2b2512b03",
+ "completedDate": 1529938009424,
+ "solution": "https://codepen.io/moT01/pen/LrrjGz?editors=1010",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "5a9d7286424fe3d0e10cad13",
+ "completedDate": 1528719842749,
+ "files": []
+ },
+ {
+ "id": "587d8250367417b2b2512c5f",
+ "completedDate": 1529584582909,
+ "files": []
+ },
+ {
+ "id": "587d8250367417b2b2512c5e",
+ "completedDate": 1529584233498,
+ "files": []
+ },
+ {
+ "id": "587d8253367417b2b2512c6a",
+ "completedDate": 1529584147462,
+ "files": []
+ },
+ {
+ "id": "587d7fa6367417b2b2512bc2",
+ "completedDate": 1529186003814,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d403614f",
+ "completedDate": 1529179243536,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d403614e",
+ "completedDate": 1528981776099,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d403614d",
+ "completedDate": 1528981744994,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d403618d",
+ "completedDate": 1528950851660,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d403618c",
+ "completedDate": 1528950719262,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d403618b",
+ "completedDate": 1528950396682,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d403618a",
+ "completedDate": 1528950304924,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036189",
+ "completedDate": 1528949805386,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036188",
+ "completedDate": 1528949697883,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036187",
+ "completedDate": 1528949067606,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036185",
+ "completedDate": 1528948451001,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036184",
+ "completedDate": 1528946998407,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036183",
+ "completedDate": 1528946875698,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036182",
+ "completedDate": 1528946566042,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036181",
+ "completedDate": 1528946437132,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036180",
+ "completedDate": 1528946299272,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d403617f",
+ "completedDate": 1528946192923,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d403617e",
+ "completedDate": 1528945856282,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d403617d",
+ "completedDate": 1528945678448,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d403617c",
+ "completedDate": 1528945645295,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d403617b",
+ "completedDate": 1528945579541,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d403617a",
+ "completedDate": 1528945447719,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036179",
+ "completedDate": 1528945385287,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036178",
+ "completedDate": 1528945197650,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036177",
+ "completedDate": 1528944290718,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036176",
+ "completedDate": 1528943870093,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036174",
+ "completedDate": 1528943740058,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036173",
+ "completedDate": 1528943671264,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036172",
+ "completedDate": 1528943603260,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036171",
+ "completedDate": 1528943535660,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036170",
+ "completedDate": 1528943507508,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d403616f",
+ "completedDate": 1528943479564,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d403616e",
+ "completedDate": 1528943277939,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d403616d",
+ "completedDate": 1528943091046,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d403616c",
+ "completedDate": 1528942897945,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d403616b",
+ "completedDate": 1528942802253,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d403616a",
+ "completedDate": 1528942758495,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036169",
+ "completedDate": 1528942646063,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036168",
+ "completedDate": 1528937140246,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036167",
+ "completedDate": 1528936992425,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036166",
+ "completedDate": 1528936887008,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036165",
+ "completedDate": 1528936818982,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036164",
+ "completedDate": 1528936765216,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036163",
+ "completedDate": 1528936729634,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036162",
+ "completedDate": 1528936661343,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036161",
+ "completedDate": 1528936547644,
+ "files": []
+ },
+ {
+ "id": "5a24c314108439a4d4036160",
+ "completedDate": 1528936507205,
+ "files": []
+ },
+ {
+ "id": "5a24bbe0dba28a8d3cbd4c5f",
+ "completedDate": 1528936468035,
+ "files": []
+ },
+ {
+ "id": "5a24bbe0dba28a8d3cbd4c5e",
+ "completedDate": 1528936381238,
+ "files": []
+ },
+ {
+ "id": "587d7fa5367417b2b2512bbd",
+ "completedDate": 1528934178753,
+ "files": []
+ },
+ {
+ "id": "587d7dbf367417b2b2512bbc",
+ "completedDate": 1528934096231,
+ "files": []
+ },
+ {
+ "id": "587d7dbf367417b2b2512bbb",
+ "completedDate": 1528934051468,
+ "files": []
+ },
+ {
+ "id": "587d7dbf367417b2b2512bba",
+ "completedDate": 1528933852430,
+ "files": []
+ },
+ {
+ "id": "587d7dbe367417b2b2512bb9",
+ "completedDate": 1528933741473,
+ "files": []
+ },
+ {
+ "id": "587d7dbe367417b2b2512bb8",
+ "completedDate": 1528933566151,
+ "files": []
+ },
+ {
+ "id": "587d7dbd367417b2b2512bb6",
+ "completedDate": 1528933360001,
+ "files": []
+ },
+ {
+ "id": "587d7dbd367417b2b2512bb5",
+ "completedDate": 1528933151245,
+ "files": []
+ },
+ {
+ "id": "587d7dbd367417b2b2512bb4",
+ "completedDate": 1528933108643,
+ "files": []
+ },
+ {
+ "id": "587d7dab367417b2b2512b70",
+ "completedDate": 1528930450509,
+ "files": []
+ },
+ {
+ "id": "587d7dab367417b2b2512b6f",
+ "completedDate": 1528930224869,
+ "files": []
+ },
+ {
+ "id": "587d7dab367417b2b2512b6e",
+ "completedDate": 1528929785830,
+ "files": []
+ },
+ {
+ "id": "587d7dab367417b2b2512b6d",
+ "completedDate": 1528929659099,
+ "files": []
+ },
+ {
+ "id": "587d7daa367417b2b2512b6c",
+ "completedDate": 1528927786126,
+ "files": []
+ },
+ {
+ "id": "587d7daa367417b2b2512b6b",
+ "completedDate": 1528927735717,
+ "files": []
+ },
+ {
+ "id": "587d7da9367417b2b2512b6a",
+ "completedDate": 1528927426415,
+ "files": []
+ },
+ {
+ "id": "587d7da9367417b2b2512b69",
+ "completedDate": 1528927327998,
+ "files": []
+ },
+ {
+ "id": "587d7da9367417b2b2512b68",
+ "completedDate": 1528927215860,
+ "files": []
+ },
+ {
+ "id": "587d7da9367417b2b2512b67",
+ "completedDate": 1528926108930,
+ "files": []
+ },
+ {
+ "id": "587d7da9367417b2b2512b66",
+ "completedDate": 1528926045666,
+ "files": []
+ },
+ {
+ "id": "9d7123c8c441eeafaeb5bdef",
+ "completedDate": 1528925941088,
+ "files": []
+ },
+ {
+ "id": "587d7b90367417b2b2512b65",
+ "completedDate": 1528925068599,
+ "files": []
+ },
+ {
+ "id": "587d7b8f367417b2b2512b64",
+ "completedDate": 1528924576412,
+ "files": []
+ },
+ {
+ "id": "587d7b8f367417b2b2512b63",
+ "completedDate": 1528917162952,
+ "files": []
+ },
+ {
+ "id": "587d7b8f367417b2b2512b62",
+ "completedDate": 1528916520035,
+ "files": []
+ },
+ {
+ "id": "587d7b8f367417b2b2512b61",
+ "completedDate": 1528916239317,
+ "files": []
+ },
+ {
+ "id": "587d7b8f367417b2b2512b60",
+ "completedDate": 1528909518505,
+ "files": []
+ },
+ {
+ "id": "587d7b8e367417b2b2512b5f",
+ "completedDate": 1528909162568,
+ "files": []
+ },
+ {
+ "id": "587d7b8e367417b2b2512b5e",
+ "completedDate": 1528909113205,
+ "files": []
+ },
+ {
+ "id": "587d7b8e367417b2b2512b5d",
+ "completedDate": 1528908970552,
+ "files": []
+ },
+ {
+ "id": "587d7b8e367417b2b2512b5c",
+ "completedDate": 1528908568106,
+ "files": []
+ },
+ {
+ "id": "587d7b8d367417b2b2512b5b",
+ "completedDate": 1528908421803,
+ "files": []
+ },
+ {
+ "id": "587d7db2367417b2b2512b8c",
+ "completedDate": 1528908345735,
+ "files": []
+ },
+ {
+ "id": "587d7db2367417b2b2512b8b",
+ "completedDate": 1528908123161,
+ "files": []
+ },
+ {
+ "id": "587d7db2367417b2b2512b8a",
+ "completedDate": 1528908033352,
+ "files": []
+ },
+ {
+ "id": "587d7db2367417b2b2512b89",
+ "completedDate": 1528907854219,
+ "files": []
+ },
+ {
+ "id": "587d7db1367417b2b2512b88",
+ "completedDate": 1528907672414,
+ "files": []
+ },
+ {
+ "id": "587d7db1367417b2b2512b87",
+ "completedDate": 1528907527117,
+ "files": []
+ },
+ {
+ "id": "587d7db1367417b2b2512b86",
+ "completedDate": 1528905869367,
+ "files": []
+ },
+ {
+ "id": "587d7db1367417b2b2512b85",
+ "completedDate": 1528905798962,
+ "files": []
+ },
+ {
+ "id": "587d7db0367417b2b2512b84",
+ "completedDate": 1528905563215,
+ "files": []
+ },
+ {
+ "id": "587d7db0367417b2b2512b83",
+ "completedDate": 1528905463958,
+ "files": []
+ },
+ {
+ "id": "587d7db0367417b2b2512b82",
+ "completedDate": 1528905321583,
+ "files": []
+ },
+ {
+ "id": "587d7db0367417b2b2512b81",
+ "completedDate": 1528905197504,
+ "files": []
+ },
+ {
+ "id": "587d7daf367417b2b2512b80",
+ "completedDate": 1528905158628,
+ "files": []
+ },
+ {
+ "id": "587d7daf367417b2b2512b7f",
+ "completedDate": 1528905128321,
+ "files": []
+ },
+ {
+ "id": "587d7daf367417b2b2512b7e",
+ "completedDate": 1528905019142,
+ "files": []
+ },
+ {
+ "id": "587d7daf367417b2b2512b7d",
+ "completedDate": 1528904850131,
+ "files": []
+ },
+ {
+ "id": "587d7dae367417b2b2512b7b",
+ "completedDate": 1528904663799,
+ "files": []
+ },
+ {
+ "id": "587d7dae367417b2b2512b7a",
+ "completedDate": 1528904554118,
+ "files": []
+ },
+ {
+ "id": "587d7dae367417b2b2512b79",
+ "completedDate": 1528904459368,
+ "files": []
+ },
+ {
+ "id": "587d7dad367417b2b2512b78",
+ "completedDate": 1528904402413,
+ "files": []
+ },
+ {
+ "id": "587d7dad367417b2b2512b77",
+ "completedDate": 1528904383963,
+ "files": []
+ },
+ {
+ "id": "587d7dad367417b2b2512b76",
+ "completedDate": 1528904346017,
+ "files": []
+ },
+ {
+ "id": "587d7dad367417b2b2512b75",
+ "completedDate": 1528904316135,
+ "files": []
+ },
+ {
+ "id": "587d7dac367417b2b2512b74",
+ "completedDate": 1528904261166,
+ "files": []
+ },
+ {
+ "id": "587d7dac367417b2b2512b73",
+ "completedDate": 1528904235855,
+ "files": []
+ },
+ {
+ "id": "579e2a2c335b9d72dd32e05c",
+ "completedDate": 1528904005293,
+ "files": []
+ },
+ {
+ "id": "587d7b7d367417b2b2512b1f",
+ "completedDate": 1528902841678,
+ "files": []
+ },
+ {
+ "id": "587d7b7d367417b2b2512b1e",
+ "completedDate": 1528902745590,
+ "files": []
+ },
+ {
+ "id": "587d7b7d367417b2b2512b1d",
+ "completedDate": 1528902722538,
+ "files": []
+ },
+ {
+ "id": "587d7b7d367417b2b2512b1c",
+ "completedDate": 1528902424707,
+ "files": []
+ },
+ {
+ "id": "587d7b7c367417b2b2512b1b",
+ "completedDate": 1528902294822,
+ "files": []
+ },
+ {
+ "id": "587d7b7c367417b2b2512b1a",
+ "completedDate": 1528902266174,
+ "files": []
+ },
+ {
+ "id": "587d7b7c367417b2b2512b19",
+ "completedDate": 1528902204888,
+ "files": []
+ },
+ {
+ "id": "587d7b7c367417b2b2512b18",
+ "completedDate": 1528902177052,
+ "files": []
+ },
+ {
+ "id": "587d7b7b367417b2b2512b16",
+ "completedDate": 1528901096407,
+ "files": []
+ },
+ {
+ "id": "587d7b7b367417b2b2512b15",
+ "completedDate": 1528900938052,
+ "files": []
+ },
+ {
+ "id": "587d7b7b367417b2b2512b14",
+ "completedDate": 1528900292192,
+ "files": []
+ },
+ {
+ "id": "587d7b7b367417b2b2512b17",
+ "completedDate": 1528900239045,
+ "files": []
+ },
+ {
+ "id": "587d7b7b367417b2b2512b13",
+ "completedDate": 1528900119504,
+ "files": []
+ },
+ {
+ "id": "587d7b7a367417b2b2512b12",
+ "completedDate": 1528900024682,
+ "files": []
+ },
+ {
+ "id": "587d78b3367417b2b2512b11",
+ "completedDate": 1528899739768,
+ "files": []
+ },
+ {
+ "id": "587d7b86367417b2b2512b3d",
+ "completedDate": 1528899440260,
+ "files": []
+ },
+ {
+ "id": "587d7b86367417b2b2512b3c",
+ "completedDate": 1528899295294,
+ "files": []
+ },
+ {
+ "id": "587d7b86367417b2b2512b3b",
+ "completedDate": 1528899043297,
+ "files": []
+ },
+ {
+ "id": "587d7b85367417b2b2512b3a",
+ "completedDate": 1528898859706,
+ "files": []
+ },
+ {
+ "id": "587d7b85367417b2b2512b39",
+ "completedDate": 1528898815395,
+ "files": []
+ },
+ {
+ "id": "587d7b85367417b2b2512b38",
+ "completedDate": 1528898783470,
+ "files": []
+ },
+ {
+ "id": "587d7b84367417b2b2512b37",
+ "completedDate": 1528898766004,
+ "files": []
+ },
+ {
+ "id": "587d7b84367417b2b2512b36",
+ "completedDate": 1528898255471,
+ "files": []
+ },
+ {
+ "id": "587d7b84367417b2b2512b35",
+ "completedDate": 1528897930802,
+ "files": []
+ },
+ {
+ "id": "587d7b84367417b2b2512b34",
+ "completedDate": 1528897909366,
+ "files": []
+ },
+ {
+ "id": "587d7b83367417b2b2512b33",
+ "completedDate": 1528897491942,
+ "files": []
+ },
+ {
+ "id": "587d7dbb367417b2b2512bac",
+ "completedDate": 1528858212055,
+ "files": []
+ },
+ {
+ "id": "587d7dbb367417b2b2512bab",
+ "completedDate": 1528857340061,
+ "files": []
+ },
+ {
+ "id": "587d7dbb367417b2b2512baa",
+ "completedDate": 1528857023208,
+ "files": []
+ },
+ {
+ "id": "587d7dba367417b2b2512ba9",
+ "completedDate": 1528845356403,
+ "files": []
+ },
+ {
+ "id": "587d7dba367417b2b2512ba8",
+ "completedDate": 1528843914026,
+ "files": []
+ },
+ {
+ "id": "587d7db9367417b2b2512ba7",
+ "completedDate": 1528843852819,
+ "files": []
+ },
+ {
+ "id": "587d7db9367417b2b2512ba6",
+ "completedDate": 1528843812163,
+ "files": []
+ },
+ {
+ "id": "587d7db9367417b2b2512ba5",
+ "completedDate": 1528843718606,
+ "files": []
+ },
+ {
+ "id": "587d7db9367417b2b2512ba4",
+ "completedDate": 1528842968052,
+ "files": []
+ },
+ {
+ "id": "587d7db8367417b2b2512ba3",
+ "completedDate": 1528842950539,
+ "files": []
+ },
+ {
+ "id": "587d7db8367417b2b2512ba2",
+ "completedDate": 1528842903133,
+ "files": []
+ },
+ {
+ "id": "587d7db8367417b2b2512ba1",
+ "completedDate": 1528842665151,
+ "files": []
+ },
+ {
+ "id": "5d712346c441eddfaeb5bdef",
+ "completedDate": 1528842647554,
+ "files": []
+ },
+ {
+ "id": "587d7db8367417b2b2512ba0",
+ "completedDate": 1528842629216,
+ "files": []
+ },
+ {
+ "id": "587d7db7367417b2b2512b9f",
+ "completedDate": 1528842603772,
+ "files": []
+ },
+ {
+ "id": "587d7db7367417b2b2512b9e",
+ "completedDate": 1528842544267,
+ "files": []
+ },
+ {
+ "id": "587d7db7367417b2b2512b9d",
+ "completedDate": 1528842515275,
+ "files": []
+ },
+ {
+ "id": "587d7db7367417b2b2512b9c",
+ "completedDate": 1528840984420,
+ "files": []
+ },
+ {
+ "id": "587d7db6367417b2b2512b9b",
+ "completedDate": 1528840909886,
+ "files": []
+ },
+ {
+ "id": "587d7db6367417b2b2512b9a",
+ "completedDate": 1528840649575,
+ "files": []
+ },
+ {
+ "id": "587d7db6367417b2b2512b99",
+ "completedDate": 1528839703992,
+ "files": []
+ },
+ {
+ "id": "587d7db6367417b2b2512b98",
+ "completedDate": 1528839624615,
+ "files": []
+ },
+ {
+ "id": "587d7db5367417b2b2512b97",
+ "completedDate": 1528839545835,
+ "files": []
+ },
+ {
+ "id": "587d7db5367417b2b2512b96",
+ "completedDate": 1528839487667,
+ "files": []
+ },
+ {
+ "id": "587d7db5367417b2b2512b95",
+ "completedDate": 1528836793048,
+ "files": []
+ },
+ {
+ "id": "587d7db5367417b2b2512b94",
+ "completedDate": 1528836647039,
+ "files": []
+ },
+ {
+ "id": "587d7db4367417b2b2512b93",
+ "completedDate": 1528836578373,
+ "files": []
+ },
+ {
+ "id": "587d7db4367417b2b2512b92",
+ "completedDate": 1528836503102,
+ "files": []
+ },
+ {
+ "id": "587d7db4367417b2b2512b91",
+ "completedDate": 1528836411536,
+ "files": []
+ },
+ {
+ "id": "587d7db4367417b2b2512b90",
+ "completedDate": 1528836347810,
+ "files": []
+ },
+ {
+ "id": "587d78b2367417b2b2512b10",
+ "completedDate": 1528745824285,
+ "files": []
+ },
+ {
+ "id": "587d78b2367417b2b2512b0f",
+ "completedDate": 1528742744006,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78b2367417b2b2512b0e",
+ "completedDate": 1528742701214,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "5a661e0f1068aca922b3ef17",
+ "completedDate": 1528742156096,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7b7e367417b2b2512b20",
+ "completedDate": 1528742135455,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7b8d367417b2b2512b59",
+ "completedDate": 1528742085698,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7b8c367417b2b2512b54",
+ "completedDate": 1528734640861,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7b8b367417b2b2512b53",
+ "completedDate": 1528733256806,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7b8b367417b2b2512b50",
+ "completedDate": 1528732942662,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7b8a367417b2b2512b4f",
+ "completedDate": 1528732804161,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7b8a367417b2b2512b4e",
+ "completedDate": 1528732349407,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7b8a367417b2b2512b4d",
+ "completedDate": 1528732036101,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7b8a367417b2b2512b4c",
+ "completedDate": 1528731931778,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7b89367417b2b2512b4b",
+ "completedDate": 1528729490152,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7b89367417b2b2512b4a",
+ "completedDate": 1528729413355,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7b89367417b2b2512b48",
+ "completedDate": 1528729040300,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7b88367417b2b2512b47",
+ "completedDate": 1528728452978,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7b88367417b2b2512b46",
+ "completedDate": 1528727990105,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7b88367417b2b2512b45",
+ "completedDate": 1528727957080,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7b88367417b2b2512b44",
+ "completedDate": 1528727575858,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7b87367417b2b2512b43",
+ "completedDate": 1528727550058,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "598f48a36c8c40764b4e52b3",
+ "completedDate": 1528727417343,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7b87367417b2b2512b42",
+ "completedDate": 1528727376633,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7b87367417b2b2512b41",
+ "completedDate": 1528727272659,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7b87367417b2b2512b40",
+ "completedDate": 1528727249380,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7b87367417b2b2512b3f",
+ "completedDate": 1528727222148,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7b7e367417b2b2512b21",
+ "completedDate": 1528727058038,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7b7e367417b2b2512b24",
+ "completedDate": 1528726960708,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7b7e367417b2b2512b22",
+ "completedDate": 1528726712992,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7b7e367417b2b2512b23",
+ "completedDate": 1528726687584,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "5a2efd662fb457916e1fe604",
+ "completedDate": 1528726654446,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "599a789b454f2bbd91a3ff4d",
+ "completedDate": 1528726636685,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "598e8944f009e646fc236146",
+ "completedDate": 1528726619417,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "5a94fe8569fb03452672e464",
+ "completedDate": 1528726554461,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "5a94fe7769fb03452672e463",
+ "completedDate": 1528726497738,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "5a94fe6269fb03452672e462",
+ "completedDate": 1528726457422,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "5a94fe5469fb03452672e461",
+ "completedDate": 1528726444838,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "5a94fe4469fb03452672e460",
+ "completedDate": 1528726409080,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "5a94fe3669fb03452672e45f",
+ "completedDate": 1528726361621,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "5a94fe2669fb03452672e45e",
+ "completedDate": 1528726329537,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78af367417b2b2512b00",
+ "completedDate": 1528725885250,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78ae367417b2b2512aff",
+ "completedDate": 1528725862565,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78ae367417b2b2512afe",
+ "completedDate": 1528725844043,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78ae367417b2b2512afd",
+ "completedDate": 1528725812152,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78ae367417b2b2512afc",
+ "completedDate": 1528725789525,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78ad367417b2b2512afb",
+ "completedDate": 1528725762069,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78ad367417b2b2512afa",
+ "completedDate": 1528725687987,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78ad367417b2b2512af9",
+ "completedDate": 1528725643242,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78ad367417b2b2512af8",
+ "completedDate": 1528725613909,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78ac367417b2b2512af7",
+ "completedDate": 1528725556408,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78ac367417b2b2512af6",
+ "completedDate": 1528725501244,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78ac367417b2b2512af5",
+ "completedDate": 1528725475416,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78ac367417b2b2512af4",
+ "completedDate": 1528725460248,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78ab367417b2b2512af3",
+ "completedDate": 1528725430078,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78ab367417b2b2512af2",
+ "completedDate": 1528725404445,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78ab367417b2b2512af1",
+ "completedDate": 1528725386000,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78ab367417b2b2512af0",
+ "completedDate": 1528725349292,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78b1367417b2b2512b0c",
+ "completedDate": 1528725216220,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78b1367417b2b2512b0a",
+ "completedDate": 1528725059356,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78b1367417b2b2512b09",
+ "completedDate": 1528724874946,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78b0367417b2b2512b08",
+ "completedDate": 1528724820768,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7790367417b2b2512ab1",
+ "completedDate": 1528724720753,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7790367417b2b2512ab0",
+ "completedDate": 1528724642030,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7790367417b2b2512aaf",
+ "completedDate": 1528724605739,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d778f367417b2b2512aae",
+ "completedDate": 1528724413398,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d778f367417b2b2512aad",
+ "completedDate": 1528724356893,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d778f367417b2b2512aac",
+ "completedDate": 1528724320641,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d778e367417b2b2512aab",
+ "completedDate": 1528724190931,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d778d367417b2b2512aaa",
+ "completedDate": 1528724078184,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d778c367417b2b2512aa9",
+ "completedDate": 1528723974611,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d778b367417b2b2512aa8",
+ "completedDate": 1528723909826,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d778b367417b2b2512aa7",
+ "completedDate": 1528723549159,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d778a367417b2b2512aa6",
+ "completedDate": 1528723491384,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d778a367417b2b2512aa5",
+ "completedDate": 1528723445304,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7789367417b2b2512aa4",
+ "completedDate": 1528723391089,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7788367417b2b2512aa3",
+ "completedDate": 1528723213266,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7788367417b2b2512aa2",
+ "completedDate": 1528723191539,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7787367417b2b2512aa1",
+ "completedDate": 1528723128518,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d774e367417b2b2512aa0",
+ "completedDate": 1528723095947,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d774e367417b2b2512a9f",
+ "completedDate": 1528723074570,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d774d367417b2b2512a9e",
+ "completedDate": 1528723032367,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d774c367417b2b2512a9d",
+ "completedDate": 1528723016297,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d774c367417b2b2512a9c",
+ "completedDate": 1528722884705,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a9367417b2b2512ae9",
+ "completedDate": 1528722189711,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a9367417b2b2512aea",
+ "completedDate": 1528722142299,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a9367417b2b2512ae8",
+ "completedDate": 1528722053070,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a8367417b2b2512ae7",
+ "completedDate": 1528722032467,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a8367417b2b2512ae6",
+ "completedDate": 1528721995155,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a8367417b2b2512ae5",
+ "completedDate": 1528721976152,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a8367417b2b2512ae4",
+ "completedDate": 1528721951775,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a8367417b2b2512ae3",
+ "completedDate": 1528721899118,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a7367417b2b2512ae2",
+ "completedDate": 1528721881145,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a7367417b2b2512ae1",
+ "completedDate": 1528721845732,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "58a7a6ebf9a6318348e2d5aa",
+ "completedDate": 1528721796290,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a7367417b2b2512ae0",
+ "completedDate": 1528721775709,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a7367417b2b2512adf",
+ "completedDate": 1528721631734,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a6367417b2b2512ade",
+ "completedDate": 1528721516690,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a6367417b2b2512add",
+ "completedDate": 1528721308692,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a6367417b2b2512adc",
+ "completedDate": 1528721257100,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a6367417b2b2512adb",
+ "completedDate": 1528721238402,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a5367417b2b2512ada",
+ "completedDate": 1528721220923,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a5367417b2b2512ad9",
+ "completedDate": 1528721198021,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a5367417b2b2512ad8",
+ "completedDate": 1528721176164,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a5367417b2b2512ad7",
+ "completedDate": 1528721108378,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a5367417b2b2512ad6",
+ "completedDate": 1528721076608,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a4367417b2b2512ad5",
+ "completedDate": 1528721029351,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a4367417b2b2512ad4",
+ "completedDate": 1528720989595,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a4367417b2b2512ad3",
+ "completedDate": 1528720962932,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a4367417b2b2512ad2",
+ "completedDate": 1528720915835,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a3367417b2b2512ad1",
+ "completedDate": 1528720843738,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a3367417b2b2512ad0",
+ "completedDate": 1528720815216,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a3367417b2b2512acf",
+ "completedDate": 1528720802544,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78a3367417b2b2512ace",
+ "completedDate": 1528720790009,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d781e367417b2b2512acc",
+ "completedDate": 1528720770993,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d781e367417b2b2512acb",
+ "completedDate": 1528720747104,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d781e367417b2b2512aca",
+ "completedDate": 1528720721929,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d781e367417b2b2512ac9",
+ "completedDate": 1528720703105,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d781d367417b2b2512ac8",
+ "completedDate": 1528720670005,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d781d367417b2b2512ac5",
+ "completedDate": 1528720645332,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d781c367417b2b2512ac4",
+ "completedDate": 1528720634778,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d781c367417b2b2512ac3",
+ "completedDate": 1528720625208,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d781c367417b2b2512ac2",
+ "completedDate": 1528720592433,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d781c367417b2b2512ac0",
+ "completedDate": 1528720543076,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d781c367417b2b2512abf",
+ "completedDate": 1528720526234,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d781b367417b2b2512abe",
+ "completedDate": 1528720510632,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d781b367417b2b2512abd",
+ "completedDate": 1528720467749,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d781b367417b2b2512abc",
+ "completedDate": 1528720453878,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d781b367417b2b2512abb",
+ "completedDate": 1528720413342,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d781b367417b2b2512aba",
+ "completedDate": 1528720403159,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d781a367417b2b2512ab9",
+ "completedDate": 1528720194712,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d781a367417b2b2512ab8",
+ "completedDate": 1528720178074,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d781a367417b2b2512ab7",
+ "completedDate": 1528720151746,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7791367417b2b2512ab5",
+ "completedDate": 1528720134400,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7791367417b2b2512ab4",
+ "completedDate": 1528720124159,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d7791367417b2b2512ab3",
+ "completedDate": 1528720108175,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "5a9d72ad424fe3d0e10cad16",
+ "completedDate": 1528720042777,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "5a9d72a1424fe3d0e10cad15",
+ "completedDate": 1528719982834,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "5a9d7295424fe3d0e10cad14",
+ "completedDate": 1528719930392,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "5a9d727a424fe3d0e10cad12",
+ "completedDate": 1528719809651,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "5a9d726c424fe3d0e10cad11",
+ "completedDate": 1528719689520,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "5a9d725e424fe3d0e10cad10",
+ "completedDate": 1528719579787,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad82fee1322bd9aedf08721",
+ "completedDate": 1528719519470,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "58c383d33e2e3259241f3076",
+ "completedDate": 1528719468043,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78aa367417b2b2512aec",
+ "completedDate": 1528719392137,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "587d78aa367417b2b2512aed",
+ "completedDate": 1528719352474,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad88fee1348bd9aedf08816",
+ "completedDate": 1528685796989,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aecf08801",
+ "completedDate": 1528684512716,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244dd",
+ "completedDate": 1475258032598,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "660add10cb82ac38a17513be",
+ "completedDate": 1515450994243,
+ "solution": null,
+ "challengeType": 7,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244de",
+ "completedDate": 1475258201433,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08801",
+ "completedDate": 1475094786951,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08804",
+ "completedDate": 1475094833566,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08833",
+ "completedDate": 1475094870641,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fed1348bd9aedf08833",
+ "completedDate": 1475094890483,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08803",
+ "completedDate": 1475094925451,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08805",
+ "completedDate": 1475095000824,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aecf08806",
+ "completedDate": 1475095068584,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aefe08806",
+ "completedDate": 1475095126954,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08806",
+ "completedDate": 1475095220729,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aede08807",
+ "completedDate": 1475095251313,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08807",
+ "completedDate": 1475095315463,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08808",
+ "completedDate": 1475095349372,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08812",
+ "completedDate": 1475095439395,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9acdf08812",
+ "completedDate": 1475095537795,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9bedf08813",
+ "completedDate": 1475095645490,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08814",
+ "completedDate": 1475095674621,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08815",
+ "completedDate": 1475095702447,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08816",
+ "completedDate": 1475095780920,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aede08817",
+ "completedDate": 1475095851150,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08817",
+ "completedDate": 1475095890671,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08820",
+ "completedDate": 1475095950614,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08827",
+ "completedDate": 1475096026221,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08828",
+ "completedDate": 1475096146254,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08829",
+ "completedDate": 1475096175545,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08830",
+ "completedDate": 1475096220710,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aede08830",
+ "completedDate": 1475096258812,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedd08830",
+ "completedDate": 1475096412586,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08834",
+ "completedDate": 1475096574019,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08835",
+ "completedDate": 1475096736280,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedd08835",
+ "completedDate": 1475096767113,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aede08835",
+ "completedDate": 1475096824274,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fed1348bd9aede07836",
+ "completedDate": 1475096878286,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87eee1348bd9aede07836",
+ "completedDate": 1475096925946,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87dee1348bd9aede07836",
+ "completedDate": 1475096968597,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad88fee1348bd9aedf08825",
+ "completedDate": 1475097030436,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08822",
+ "completedDate": 1475097048908,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08823",
+ "completedDate": 1475097079567,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08824",
+ "completedDate": 1475097122623,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1248bd9aedf08824",
+ "completedDate": 1475097163693,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08826",
+ "completedDate": 1475097197806,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9afdf08726",
+ "completedDate": 1475097220823,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08736",
+ "completedDate": 1475097245742,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08746",
+ "completedDate": 1475097305636,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08756",
+ "completedDate": 1475097367679,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf04756",
+ "completedDate": 1475097441406,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd8aedf06756",
+ "completedDate": 1475097504209,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf06756",
+ "completedDate": 1475097605201,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf07756",
+ "completedDate": 1475097675710,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08726",
+ "completedDate": 1475102179284,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08721",
+ "completedDate": 1475102344318,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08719",
+ "completedDate": 1475102399325,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aede08718",
+ "completedDate": 1475102447915,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad82fee1348bd9aedf08721",
+ "completedDate": 1475102528619,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9acde08712",
+ "completedDate": 1475102639748,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9acde08812",
+ "completedDate": 1475102771357,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd8acde08812",
+ "completedDate": 1475102802266,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348cd8acdf08812",
+ "completedDate": 1475102852811,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348cd8acef08812",
+ "completedDate": 1475102997685,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348cd8acef08811",
+ "completedDate": 1475103090510,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348cd8acef08813",
+ "completedDate": 1475103173521,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348ce8acef08814",
+ "completedDate": 1475103241775,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad88fee1348ce8acef08815",
+ "completedDate": 1475103767585,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1347bd9aedf08845",
+ "completedDate": 1475103941867,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08845",
+ "completedDate": 1475104193824,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "560add10cb82ac38a17513be",
+ "completedDate": 1475104385115,
+ "solution": null,
+ "challengeType": 7,
+ "files": []
+ },
+ {
+ "id": "560add37cb82ac38a17513bf",
+ "completedDate": 1475105708678,
+ "solution": null,
+ "challengeType": 7,
+ "files": []
+ },
+ {
+ "id": "560add56cb82ac38a17513c0",
+ "completedDate": 1475105917537,
+ "solution": null,
+ "challengeType": 7,
+ "files": []
+ },
+ {
+ "id": "560add71cb82ac38a17513c2",
+ "completedDate": 1475105957457,
+ "solution": null,
+ "challengeType": 7,
+ "files": []
+ },
+ {
+ "id": "560adf65cb82ac38a17513c2",
+ "completedDate": 1475106219178,
+ "solution": null,
+ "challengeType": 7,
+ "files": []
+ },
+ {
+ "id": "560add8ccb82ac38a17513c4",
+ "completedDate": 1475106445148,
+ "solution": null,
+ "challengeType": 7,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aede08845",
+ "completedDate": 1475107618308,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedd08845",
+ "completedDate": 1475107867871,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedc08845",
+ "completedDate": 1475108019303,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedb08845",
+ "completedDate": 1475108135358,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aeda08845",
+ "completedDate": 1475108802536,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aed908845",
+ "completedDate": 1475108989462,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aec908845",
+ "completedDate": 1475109094598,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aec908846",
+ "completedDate": 1475109155433,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aec908746",
+ "completedDate": 1475109179986,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9bec908846",
+ "completedDate": 1475109200468,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aec908847",
+ "completedDate": 1475109232567,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aec908848",
+ "completedDate": 1475109272839,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aec908849",
+ "completedDate": 1475109317110,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aec908850",
+ "completedDate": 1475109360603,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aec908852",
+ "completedDate": 1475109405858,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aec908853",
+ "completedDate": 1475109460239,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aec908854",
+ "completedDate": 1475109523665,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aec908855",
+ "completedDate": 1475109597253,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aec908856",
+ "completedDate": 1475109699779,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aec908857",
+ "completedDate": 1475109754181,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "573c96eac9a6be092d7830c1",
+ "completedDate": 1475120191143,
+ "solution": null,
+ "challengeType": 7,
+ "files": []
+ },
+ {
+ "id": "560ade65cb82ac38a17513c2",
+ "completedDate": 1475120213223,
+ "solution": null,
+ "challengeType": 7,
+ "files": []
+ },
+ {
+ "id": "570add8ccb82ac38a17513c3",
+ "completedDate": 1475120317675,
+ "solution": null,
+ "challengeType": 7,
+ "files": []
+ },
+ {
+ "id": "560add8ccb81ac38a17513c4",
+ "completedDate": 1475120349142,
+ "solution": null,
+ "challengeType": 7,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9acdd08826",
+ "completedDate": 1475120453111,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9bedc08826",
+ "completedDate": 1475120559183,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedc08826",
+ "completedDate": 1475120631184,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aeda08826",
+ "completedDate": 1475120755306,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aeda08726",
+ "completedDate": 1475120779449,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aed908626",
+ "completedDate": 1475121062291,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aed918626",
+ "completedDate": 1475121104072,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aed908826",
+ "completedDate": 1475121170178,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aed808826",
+ "completedDate": 1475121219834,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "564944c91be2204b269d51e3",
+ "completedDate": 1475121806404,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aed708826",
+ "completedDate": 1475121839535,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aed608826",
+ "completedDate": 1475121896777,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aed508826",
+ "completedDate": 1475121971349,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aed308826",
+ "completedDate": 1475122255862,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aed208826",
+ "completedDate": 1475122353496,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aed108826",
+ "completedDate": 1475122451433,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aed008826",
+ "completedDate": 1475122549646,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aecb08826",
+ "completedDate": 1475122606323,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "bd7158d8c442eddfbeb5bd1f",
+ "completedDate": 1475123013392,
+ "solution": null,
+ "challengeType": 7,
+ "files": []
+ },
+ {
+ "id": "bd7158d8c442eddfaeb5bd18",
+ "completedDate": 1475164643824,
+ "solution": "https://codepen.io/moT01/pen/ZpJpKp",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "bd7123c9c443eddfaeb5bdef",
+ "completedDate": 1475173197683,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244a8",
+ "completedDate": 1475173236795,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244a9",
+ "completedDate": 1475173254001,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244aa",
+ "completedDate": 1475173281010,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244ab",
+ "completedDate": 1475173381082,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c11feddfaeb3bdef",
+ "completedDate": 1475173390858,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c11feddfaeb4bdef",
+ "completedDate": 1475173413711,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1231c1c11feddfaeb5bdef",
+ "completedDate": 1475173423698,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c11feddfaeb6bdef",
+ "completedDate": 1475173438268,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244ac",
+ "completedDate": 1475173465003,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244ad",
+ "completedDate": 1475173477062,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1391c1c11feddfaeb4bdef",
+ "completedDate": 1475173519510,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "bd7993c9c69feddfaeb7bdef",
+ "completedDate": 1475173533104,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "bd7993c9ca9feddfaeb7bdef",
+ "completedDate": 1475173564954,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244ae",
+ "completedDate": 1475176291002,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244af",
+ "completedDate": 1475176331489,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244b0",
+ "completedDate": 1475176352871,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244b1",
+ "completedDate": 1475176403989,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244b2",
+ "completedDate": 1475176422046,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244b3",
+ "completedDate": 1475176590196,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "bd7123c9c444eddfaeb5bdef",
+ "completedDate": 1475176632734,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244b5",
+ "completedDate": 1475176719867,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244b4",
+ "completedDate": 1475176819114,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244b6",
+ "completedDate": 1475176908316,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244b7",
+ "completedDate": 1475176990858,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244b8",
+ "completedDate": 1475177105048,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244b9",
+ "completedDate": 1475177174580,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244ed",
+ "completedDate": 1475177236572,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "bd7123c9c448eddfaeb5bdef",
+ "completedDate": 1475177278183,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "bd7123c9c549eddfaeb5bdef",
+ "completedDate": 1475179313868,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244ba",
+ "completedDate": 1475179482988,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "bd7123c9c450eddfaeb5bdef",
+ "completedDate": 1475179518666,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "bd7123c9c451eddfaeb5bdef",
+ "completedDate": 1475179613795,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "bd7123c9c452eddfaeb5bdef",
+ "completedDate": 1475179659278,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244bb",
+ "completedDate": 1475179965317,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "bd7993c9c69feddfaeb8bdef",
+ "completedDate": 1475180000714,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c11feddfaeb7bdef",
+ "completedDate": 1475180039289,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56bbb991ad1ed5201cd392ca",
+ "completedDate": 1475180095658,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c11feddfaeb8bdef",
+ "completedDate": 1475181698926,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56592a60ddddeae28f7aa8e1",
+ "completedDate": 1475181780041,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56bbb991ad1ed5201cd392cb",
+ "completedDate": 1475181833413,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56bbb991ad1ed5201cd392cc",
+ "completedDate": 1475183501952,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56bbb991ad1ed5201cd392cd",
+ "completedDate": 1475183525070,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56bbb991ad1ed5201cd392ce",
+ "completedDate": 1475183590132,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244bc",
+ "completedDate": 1475183698232,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56bbb991ad1ed5201cd392cf",
+ "completedDate": 1475183805400,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244bd",
+ "completedDate": 1475246542486,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244be",
+ "completedDate": 1475246816353,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244bf",
+ "completedDate": 1475246928293,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244c0",
+ "completedDate": 1475246987475,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244c2",
+ "completedDate": 1475247140834,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244c3",
+ "completedDate": 1475247240302,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244c6",
+ "completedDate": 1475249114465,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "bd7123c9c441eddfaeb5bdef",
+ "completedDate": 1475249172491,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c12feddfaeb3bdef",
+ "completedDate": 1475249802320,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244d0",
+ "completedDate": 1475255137391,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244d1",
+ "completedDate": 1475255166071,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244d2",
+ "completedDate": 1475255268194,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244d3",
+ "completedDate": 1475255346517,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244d4",
+ "completedDate": 1475255395602,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244d5",
+ "completedDate": 1475255430440,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244d6",
+ "completedDate": 1475255447772,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244d7",
+ "completedDate": 1475255476799,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244d8",
+ "completedDate": 1475255568397,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244d9",
+ "completedDate": 1475255614997,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244da",
+ "completedDate": 1475255683109,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244db",
+ "completedDate": 1475255732118,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "5690307fddb111c6084545d7",
+ "completedDate": 1475255808973,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244dc",
+ "completedDate": 1475256242575,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "5664820f61c48e80c9fa476c",
+ "completedDate": 1475256945917,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "bd7158d8c443eddfaeb5bdee",
+ "completedDate": 1515450964126,
+ "solution": "https://pinter.herokuapp.com/#/",
+ "challengeType": 4,
+ "files": []
+ },
+ {
+ "id": "bad87fee1348bd9aedf08802",
+ "completedDate": 1475094814477,
+ "solution": null,
+ "challengeType": null,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244df",
+ "completedDate": 1475258308371,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244e0",
+ "completedDate": 1475258479391,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "5679ceb97cbaa8c51670a16b",
+ "completedDate": 1475259156604,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244c4",
+ "completedDate": 1475259288195,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "565bbe00e9cc8ac0725390f4",
+ "completedDate": 1475262913431,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56bbb991ad1ed5201cd392d0",
+ "completedDate": 1475266763329,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244c7",
+ "completedDate": 1475266806568,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244c8",
+ "completedDate": 1475266879713,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244c9",
+ "completedDate": 1475267928028,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56bbb991ad1ed5201cd392d1",
+ "completedDate": 1475267998292,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56bbb991ad1ed5201cd392d2",
+ "completedDate": 1475268069965,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56bbb991ad1ed5201cd392d3",
+ "completedDate": 1475268145412,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244ca",
+ "completedDate": 1475297124064,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "567af2437cbaa8c51670a16c",
+ "completedDate": 1475297309457,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244cb",
+ "completedDate": 1475297597704,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244cc",
+ "completedDate": 1475297776784,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244cd",
+ "completedDate": 1475297918874,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244cf",
+ "completedDate": 1475519963758,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c11feddfaeb5bdef",
+ "completedDate": 1475520469953,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56104e9e514f539506016a5c",
+ "completedDate": 1475520549003,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56105e7b514f539506016a5e",
+ "completedDate": 1475520602983,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "5675e877dbd60be8ad28edc6",
+ "completedDate": 1475520969902,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244e1",
+ "completedDate": 1475521239678,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c11feddfaeb1bdef",
+ "completedDate": 1475521320287,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "5688e62ea601b2482ff8422b",
+ "completedDate": 1475524381505,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c11feddfaeb9bdef",
+ "completedDate": 1475524515916,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c12feddfaeb1bdef",
+ "completedDate": 1475524655165,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c12feddfaeb2bdef",
+ "completedDate": 1475543615965,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c12feddfaeb6bdef",
+ "completedDate": 1475543695668,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "bd7128d8c441eddfbeb5bddf",
+ "completedDate": 1475544021850,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c12feddfaeb7bdef",
+ "completedDate": 1475544296945,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c12feddfaeb8bdef",
+ "completedDate": 1475544467549,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c13feddfaeb3bdef",
+ "completedDate": 1475544513783,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c15feddfaeb1bdef",
+ "completedDate": 1475544570212,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c15feddfaeb2bdef",
+ "completedDate": 1475544847062,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c15feddfaeb4bdef",
+ "completedDate": 1475545110298,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "563cfb55594311ffcb333c70",
+ "completedDate": 1475545212806,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c15feddfaeb3bdef",
+ "completedDate": 1475547779361,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c15feddfaeb7bdef",
+ "completedDate": 1475547932256,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c15feddfaeb8bdef",
+ "completedDate": 1475548117909,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c15feddfaeb9bdef",
+ "completedDate": 1475548202572,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c16feddfaeb1bdef",
+ "completedDate": 1475548720499,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c16feddfaeb2bdef",
+ "completedDate": 1475548785961,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c16feddfaeb3bdef",
+ "completedDate": 1475548816796,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c16feddfaeb4bdef",
+ "completedDate": 1475548955141,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c16feddfaeb5bdef",
+ "completedDate": 1475549004864,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "bd7158d2c442eddfbeb5bd1f",
+ "completedDate": 1475549039674,
+ "solution": null,
+ "challengeType": 7,
+ "files": []
+ },
+ {
+ "id": "a202eed8fc186c8434cb6d61",
+ "completedDate": 1475549776986,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "a302f7aae1aa3152a5b413bc",
+ "completedDate": 1475550618044,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "aaa48de84e1ecc7c742e1124",
+ "completedDate": 1475551824473,
+ "solution": "\nfunction palindrome(str) {\n \n //remove all punctuation and spaces\n var str1 = str.replace(/[^A-Za-z0-9]/g, '');\n //make all lower case\n var str2 = str1.toLowerCase();\n console.log(str2);\n \n var str3 = str2.split('').reverse().join('');\n console.log(str3);\n \n if (str2 === str3)\n {\n return true;\n }\n \n else\n { \n return false;\n }\n}\n\n\n\npalindrome(\"eye\");\n",
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "a26cbbe9ad8655a977e1ceb5",
+ "completedDate": 1475552516511,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "ab6137d4e35944e21037b769",
+ "completedDate": 1475553251232,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "a789b3483989747d63b0e427",
+ "completedDate": 1475553881835,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "acda2fb1324d9b0fa741e6b5",
+ "completedDate": 1475554349724,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "afcc8d540bea9ea2669306b6",
+ "completedDate": 1475555795487,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "af2170cad53daa0770fabdea",
+ "completedDate": 1475594634836,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "ac6993d51946422351508a41",
+ "completedDate": 1475598636059,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "a9bd25c716030ec90084d8a1",
+ "completedDate": 1475622950421,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "ab31c21b530c0dafa9e241ee",
+ "completedDate": 1475628875890,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "adf08ec01beb4f99fc7a68f2",
+ "completedDate": 1475634954182,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "a39963a4c10bc8b4d4f06d7e",
+ "completedDate": 1476834441854,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "a24c1a4622e3c05097f71d67",
+ "completedDate": 1476839147914,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "56533eb9ac21ba0edf2244e2",
+ "completedDate": 1476843234983,
+ "solution": "\nfunction rot13(str) { // LBH QVQ VG!\n //var arr0 = str.split(\"\");\n var arr = [];\n var arr2 = [];\n var newstr = \"\";\n //concat array to string\n //var str3 = String.fromCharCode(65);\n //var str2 = 'did'.charCodeAt(0);\n \n for (i=0; i= 65 && str.charCodeAt(i) <= 77) //A-M\n {\n filler = str.charCodeAt(i) + 13;\n arr.push(filler);\n }\n else if (str.charCodeAt(i) > 77 && str.charCodeAt(i) <= 90) //N-Z\n {\n filler = str.charCodeAt(i) - 13;\n arr.push(filler);\n }\n else //all other characters !, .*?\n {\n filler = str.charCodeAt(i);\n arr.push(filler);\n }\n }\n \n for (j=0; j=1000) {\n newArr.push(\"M\"); \n num -= 1000;\n }\n \n if (num >= 900) {\n newArr.push(\"CM\");\n num -= 900;\n }\n \n if (num >= 500) {\n newArr.push(\"D\");\n num -= 500;\n }\n \n if (num >= 400) {\n newArr.push(\"CD\");\n num -= 400;\n }\n \n while (num >= 100) { \n newArr.push(\"C\");\n num -= 100;\n }\n\n if (num >= 90) {\n newArr.push(\"XC\");\n num -= 90;\n }\n \n if (num >= 50) {\n newArr.push(\"L\");\n num -= 50;\n }\n \n if (num >= 40) {\n newArr.push(\"XL\");\n num -= 40;\n }\n \n while (num >= 10) {\n newArr.push(\"X\");\n num -= 10;\n }\n \n if (num >= 9) {\n newArr.push(\"IX\");\n num -= 9;\n }\n \n if (num >= 5) {\n newArr.push(\"V\");\n num -= 5;\n }\n \n if (num >= 4) {\n newArr.push(\"IV\");\n num -= 4;\n }\n \n while (num > 0) {\n newArr.push(\"I\");\n num -= 1;\n }\n \n result = newArr.join();\n result = result.replace(/,/g,\"\");\n console.log(result);\n return result;\n}\n\nconvertToRoman(36);\n",
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "a0b5010f579e69b815e7c5d6",
+ "completedDate": 1477512598599,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "aa7697ea2477d1316795783b",
+ "completedDate": 1477516427303,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "afd15382cdfb22c9efe8b7de",
+ "completedDate": 1477519032167,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "af7588ade1100bde429baf20",
+ "completedDate": 1477520894164,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "a77dbc43c33f39daa4429b4f",
+ "completedDate": 1477521441905,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "a105e963526e7de52b219be9",
+ "completedDate": 1477523752866,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "a6b0bb188d873cb2c8729495",
+ "completedDate": 1477529331616,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "a5229172f011153519423690",
+ "completedDate": 1477535395217,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "a8d97bd4c764e91f9d2bda01",
+ "completedDate": 1477592139677,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "af4afb223120f7348cdfc9fd",
+ "completedDate": 1478129569493,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "bd7158d8c442eddfaeb5bd19",
+ "completedDate": 1479175997023,
+ "solution": "http://codepen.io/moT01/pen/LRoxrQ",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "a8e512fbe388ac2f9198f0fa",
+ "completedDate": 1481583669528,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "a103376db3ba46b2d50db289",
+ "completedDate": 1481587010971,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "a3bfc1673c0526e06d3ac698",
+ "completedDate": 1481608493885,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "ae9defd7acaf69703ab432ea",
+ "completedDate": 1481736052042,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "a6e40f1041b06c996f7b2406",
+ "completedDate": 1481736237406,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "a5deed1811a43193f9f1c841",
+ "completedDate": 1481740006290,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "ab306dbdcc907c7ddfc30830",
+ "completedDate": 1481745472605,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "a10d2431ad0c6a099a4b8b52",
+ "completedDate": 1481746815383,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "a97fd23d9b809dac9921074f",
+ "completedDate": 1481758984188,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "a3f503de51cfab748ff001aa",
+ "completedDate": 1481824947299,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "a56138aff60341a09ed6c480",
+ "completedDate": 1481837456810,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "a3f503de51cf954ede28891d",
+ "completedDate": 1481845736605,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "56b15f15632298c12f315184",
+ "completedDate": 1481860652201,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "56b15f15632298c12f315185",
+ "completedDate": 1481860854284,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "56b15f15632298c12f31518f",
+ "completedDate": 1481861004554,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "56b15f15632298c12f31518e",
+ "completedDate": 1481862599572,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "56b15f15632298c12f31518c",
+ "completedDate": 1481862758623,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "56b15f15632298c12f31518d",
+ "completedDate": 1481862797677,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "56b15f15632298c12f31518b",
+ "completedDate": 1481862861505,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "56b15f15632298c12f31518a",
+ "completedDate": 1481862919212,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "56b15f15632298c12f315189",
+ "completedDate": 1481863139471,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "56b15f15632298c12f315188",
+ "completedDate": 1481863215509,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "56b15f15632298c12f315187",
+ "completedDate": 1481863487868,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "56b15f15632298c12f315186",
+ "completedDate": 1481863524852,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "bd7129d8a441eddfbeb5bddf",
+ "completedDate": 1481863610234,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "bd7126d8c441eddfbeb5bddf",
+ "completedDate": 1481863731854,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "bd7125d8c441eddfbeb5bddf",
+ "completedDate": 1481864211145,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "bd7122d8c441eddfbeb5bddf",
+ "completedDate": 1481864321324,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "bd7124d8c441eddfbeb5bddf",
+ "completedDate": 1481864475753,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "bd7123d8c441eddfbeb5bddf",
+ "completedDate": 1481864582256,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "bd7121d8c441eddfbeb5bddf",
+ "completedDate": 1481864696095,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "bd7120d8c441eddfbeb5bddf",
+ "completedDate": 1481864846892,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "bd712fd8c441eddfbeb5bddf",
+ "completedDate": 1481864954292,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "bd712ed8c441eddfbeb5bddf",
+ "completedDate": 1481865043747,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "bd712dd8c441eddfbeb5bddf",
+ "completedDate": 1481865144055,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "bd712cd8c441eddfbeb5bddf",
+ "completedDate": 1481865164967,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "56b15f15632298c12f31510f",
+ "completedDate": 1481865503851,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "bd7129d80441eddfbeb5bddf",
+ "completedDate": 1481865687477,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "bd7129d8b441eddfbeb5bddf",
+ "completedDate": 1481866381587,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "bd7029d8c441eddfbeb5bddf",
+ "completedDate": 1481868133911,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "bd712ad8c441eddfbeb5bddf",
+ "completedDate": 1481868315911,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "bd7119d8c441eddfbeb5bddf",
+ "completedDate": 1481868379586,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "bd712bd8c441eddfbeb5bddf",
+ "completedDate": 1481868532739,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "bd7129d89441eddfbeb5bddf",
+ "completedDate": 1481868862816,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "56b15f15632298c12f315183",
+ "completedDate": 1481897167093,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "56b15f15632298c12f315182",
+ "completedDate": 1481897290924,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "56b15f15632298c12f315181",
+ "completedDate": 1481897771281,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "56b15f15632298c12f315180",
+ "completedDate": 1481898177819,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "56b15f15632298c12f31517f",
+ "completedDate": 1481898276836,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "56b15f15632298c12f31517e",
+ "completedDate": 1481898787535,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "56b15f15632298c12f31517d",
+ "completedDate": 1481898913196,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "56b15f15632298c12f31517c",
+ "completedDate": 1481899378324,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "56b15f15632298c12f31517b",
+ "completedDate": 1481899595427,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "56b15f15632298c12f31517a",
+ "completedDate": 1481900212775,
+ "solution": null,
+ "challengeType": 6,
+ "files": []
+ },
+ {
+ "id": "a2f1d72d9b908d0bd72bb9f6",
+ "completedDate": 1481903430810,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "aff0395860f5d3034dc0bfc9",
+ "completedDate": 1482122509252,
+ "solution": "\nfunction telephoneCheck(str) {\n \n var tests = /^(1|1[\\s-])?(\\d{3}|\\d{3}[\\s-]|\\(\\d{3}\\)|\\(\\d{3}\\)\\s)(\\d{3}|\\d{3}[\\s-])\\d{4}$/g;\n return tests.test(str);\n}\n\n\n\ntelephoneCheck(\"555-555-5555\");\n",
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "a7bf700cd123b9a54eef01d5",
+ "completedDate": 1482185656510,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "a19f0fbe1872186acd434d5a",
+ "completedDate": 1482201811080,
+ "solution": null,
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "aa2e6f85cab2ab736c9a9b24",
+ "completedDate": 1482248818632,
+ "solution": "\nfunction checkCashRegister(price, cash, cid) {\n var changeleft = Math.round((cash-price)*100)/100, changetotal = Math.round((cash-price)*100)/100, totalcid = 0, arr = [], temp = 0, temp2 = 0;\n\n var values = [[\"PENNY\", 0.01], \n [\"NICKEL\", 0.05], \n [\"DIME\", 0.10], \n [\"QUARTER\", 0.25], \n [\"ONE\", 1.00], \n [\"FIVE\", 5.00], \n [\"TEN\", 10.00], \n [\"TWENTY\", 20.00], \n [\"ONE HUNDRED\", 100.00]];\n \n //this get the cash in the till\n for(var i=0; i= value && cid[j][1] >= value) {\n changeleft = Math.round((changeleft-value)*100)/100;\n cid[j][1] = Math.round((cid[j][1]-value)*100)/ 100;\n totalcid = Math.round((totalcid-value)*100)/100;\n temp = Math.round((temp+value)*100)/100;\n }\n temp2 = Math.round((temp2+temp)*100)/100;\n if(temp !== 0) {\n arr.push([values[j][0],temp]);\n }\n }\n \n for(var k=8; k>=0; k--) {\n getchange(k, values[k][1]);\n }\n\n if(temp2 < changetotal) {\n return \"Insufficient Funds\";\n }\n if(totalcid !== 0) {\n return arr;\n } else {\n return \"Closed\";\n }\n}",
+ "challengeType": 5,
+ "files": []
+ },
+ {
+ "id": "bd7158d8c442eddfaeb5bd1c",
+ "completedDate": 1484354051397,
+ "solution": "http://codepen.io/moT01/pen/jyqrNr",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "bd7158d8c442eddfaeb5bd1f",
+ "completedDate": 1484776063352,
+ "solution": "http://codepen.io/moT01/pen/WRGERp",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "bd7158d8c442eddfaeb5bd0f",
+ "completedDate": 1485204463074,
+ "solution": "http://codepen.io/moT01/pen/PbrzQo",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "bd7158d8c442eedfaeb5bd1c",
+ "completedDate": 1485204700866,
+ "solution": "http://codepen.io/moT01/pen/egOKqO",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "bd7158d8c442eddfaeb5bd17",
+ "completedDate": 1485289601534,
+ "solution": "http://codepen.io/moT01/pen/rWxJoa",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "bd7158d8c242eddfaeb5bd13",
+ "completedDate": 1485315439137,
+ "solution": "http://codepen.io/moT01/pen/vgOaoJ",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "561add10cb82ac38a17513be",
+ "completedDate": 1485316065499,
+ "solution": null,
+ "challengeType": 7,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c16feddfaeb6bdef",
+ "completedDate": 1485467383567,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "cf1111c1c16feddfaeb7bdef",
+ "completedDate": 1485467595207,
+ "solution": null,
+ "challengeType": 1,
+ "files": []
+ },
+ {
+ "id": "bd7154d8c242eddfaeb5bd13",
+ "completedDate": 1488664622012,
+ "solution": "http://codepen.io/moT01/pen/aJzJQg",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "bd7155d8c242eddfaeb5bd13",
+ "completedDate": 1488665107117,
+ "solution": "http://codepen.io/moT01/pen/ygwEaK",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "bd7157d8c242eddfaeb5bd13",
+ "completedDate": 1488665153261,
+ "solution": "http://codepen.io/moT01/pen/egrZzr",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "bd7156d8c242eddfaeb5bd13",
+ "completedDate": 1488665196848,
+ "solution": "http://codepen.io/moT01/pen/ggBEWY",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "58d9cc820ce2197370032a13",
+ "completedDate": 1490789539522,
+ "solution": null,
+ "challengeType": 7,
+ "files": []
+ },
+ {
+ "id": "bd7198d8c242eddfaeb5bd13",
+ "completedDate": 1490790216213,
+ "solution": "http://codepen.io/moT01/pen/EWmYPq",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "bd7108d8c242eddfaeb5bd13",
+ "completedDate": 1491529027827,
+ "solution": "http://codepen.io/moT01/full/dvEgav/",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "bd7153d8c242eddfaeb5bd13",
+ "completedDate": 1491530360535,
+ "solution": "http://codepen.io/moT01/full/OpOOxg/",
+ "challengeType": 3,
+ "files": []
+ },
+ {
+ "id": "561add10cb82ac38a17513b3",
+ "completedDate": 1491530482152,
+ "solution": null,
+ "challengeType": 7,
+ "files": []
+ },
+ {
+ "id": "bd7353d8c341eddeaeb5bd0f",
+ "completedDate": 1496195906794,
+ "solution": null,
+ "challengeType": 2,
+ "files": []
+ },
+ {
+ "id": "bd7153d8c441eddfaeb5bd0f",
+ "completedDate": 1496235235066,
+ "solution": null,
+ "challengeType": 2,
+ "files": []
+ },
+ {
+ "id": "bd7153d8c441eddfaeb5bdff",
+ "completedDate": 1496603882718,
+ "solution": null,
+ "challengeType": 2,
+ "files": []
+ },
+ {
+ "id": "bd7153d8c441eddfaeb5bdfe",
+ "completedDate": 1496603911653,
+ "solution": null,
+ "challengeType": 2,
+ "files": []
+ },
+ {
+ "id": "bd7153d8c441eddfaeb5bdfd",
+ "completedDate": 1496603991361,
+ "solution": null,
+ "challengeType": 2,
+ "files": []
+ },
+ {
+ "id": "bd7153d8c441eddfaeb5bd1f",
+ "completedDate": 1496752318061,
+ "solution": null,
+ "challengeType": 2,
+ "files": []
+ },
+ {
+ "id": "bd7243d8c341eddeaeb5bd0f",
+ "completedDate": 1497409186851,
+ "solution": null,
+ "challengeType": 2,
+ "files": []
+ },
+ {
+ "id": "576d6e1b12fd92c4207a9cbd",
+ "completedDate": 1497411084548,
+ "solution": null,
+ "challengeType": 7,
+ "files": []
+ },
+ {
+ "id": "bd7158d8c443edefaeb5bdee",
+ "completedDate": 1500083078110,
+ "solution": "https://web-searcher.glitch.me/",
+ "challengeType": 4,
+ "files": []
+ },
+ {
+ "id": "bd7158d8c443eddfaeb5bcef",
+ "completedDate": 1500911842686,
+ "solution": null,
+ "challengeType": 7,
+ "files": []
+ },
+ {
+ "id": "bd7158d8c443eddfaeb5bdef",
+ "completedDate": 1503596314310,
+ "solution": "https://vote-app.glitch.me/",
+ "challengeType": 4,
+ "files": []
+ },
+ {
+ "id": "bd7158d8c443eddfaeb5bd0e",
+ "completedDate": 1504564623846,
+ "solution": "http://mystocks.glitch.me/",
+ "challengeType": 4,
+ "files": []
+ },
+ {
+ "id": "bd7158d8c443eddfaeb5bdff",
+ "completedDate": 1509469714079,
+ "solution": "https://yoyo44.herokuapp.com/",
+ "challengeType": 4,
+ "files": []
+ },
+ {
+ "id": "bd7158d8c443eddfaeb5bd0f",
+ "completedDate": 1513966678577,
+ "solution": "https://book-fcc.herokuapp.com/",
+ "challengeType": 4,
+ "files": []
+ },
+ {
+ "id": "561abd10cb81ac38a17513bc",
+ "completedDate": 1528930836376,
+ "challengeType": 7,
+ "files": []
+ },
+ {
+ "id": "561acd10cb82ac38a17513bc",
+ "completedDate": 1532961178690,
+ "challengeType": 7,
+ "files": []
+ },
+ {
+ "id": "561add10cb82ac38a17513bc",
+ "completedDate": 1533273784477,
+ "challengeType": 7,
+ "files": []
+ },
+ {
+ "id": "561add10cb82ac38a17523bc",
+ "completedDate": 1533833480936,
+ "challengeType": 7,
+ "files": []
+ },
+ {
+ "id": "5a553ca864b52e1d8bceea14",
+ "completedDate": 1537145017407,
+ "challengeType": 7,
+ "files": []
+ },
+ {
+ "id": "561add10cb82ac38a17213bc",
+ "completedDate": 1538239301985,
+ "challengeType": 7,
+ "files": []
+ },
+ {
+ "id": "602da04c22201c65d2a019f4",
+ "completedDate": 1642566694752,
+ "files": []
+ },
+ {
+ "id": "602d9ff222201c65d2a019f2",
+ "completedDate": 1642566450182,
+ "files": []
+ },
+ {
+ "id": "5fa323cdaf6a73463d590659",
+ "completedDate": 1642566442917,
+ "files": []
+ },
+ {
+ "id": "5f32db63eb37f7e17323f459",
+ "completedDate": 1642566429622,
+ "files": []
+ },
+ {
+ "id": "5f87ac112ae598023a42df1a",
+ "completedDate": 1642566416673,
+ "files": []
+ },
+ {
+ "id": "5f5b969a05380d2179fe6e18",
+ "completedDate": 1642566406680,
+ "files": []
+ },
+ {
+ "id": "602da0de22201c65d2a019f6",
+ "completedDate": 1642566390464,
+ "files": []
+ },
+ {
+ "id": "5f9771307d4d22b9d2b75a94",
+ "completedDate": 1642566369992,
+ "files": []
+ },
+ {
+ "id": "618590adb0730ca724e37672",
+ "completedDate": 1642566358706,
+ "files": []
+ },
+ {
+ "id": "602da0c222201c65d2a019f5",
+ "completedDate": 1642566353635,
+ "files": []
+ },
+ {
+ "id": "5f5904ac738bc2fa9efecf5a",
+ "completedDate": 1642566336874,
+ "files": []
+ },
+ {
+ "id": "5f1a4ef5d5d6b5ab580fc6ae",
+ "completedDate": 1642566305566,
+ "files": []
+ },
+ {
+ "id": "5f2c289f164c29556da632fd",
+ "completedDate": 1642566297762,
+ "files": []
+ },
+ {
+ "id": "5ea8adfab628f68d805bfc5e",
+ "completedDate": 1642566255203,
+ "files": []
+ },
+ {
+ "id": "606243f50267e718b1e755f4",
+ "completedDate": 1642615978255,
+ "challengeType": 7,
+ "files": []
+ },
+ {
+ "id": "6145f685797bd30df9784e8c",
+ "completedDate": 1668803655086,
+ "files": []
+ }
+]
diff --git a/client/src/__mocks__/edges.json b/client/src/__mocks__/edges.json
new file mode 100644
index 00000000000000..13c3dfaf155b20
--- /dev/null
+++ b/client/src/__mocks__/edges.json
@@ -0,0 +1,32462 @@
+[
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-accessibility/add-a-text-alternative-to-images-for-visually-impaired-accessibility",
+ "blockName": "Applied Accessibility"
+ },
+ "id": "587d774c367417b2b2512a9c",
+ "title": "Add a Text Alternative to Images for Visually Impaired Accessibility"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-accessibility/add-an-accessible-date-picker",
+ "blockName": "Applied Accessibility"
+ },
+ "id": "587d778b367417b2b2512aa8",
+ "title": "Add an Accessible Date Picker"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-accessibility/avoid-colorblindness-issues-by-carefully-choosing-colors-that-convey-information",
+ "blockName": "Applied Accessibility"
+ },
+ "id": "587d778f367417b2b2512aad",
+ "title": "Avoid Colorblindness Issues by Carefully Choosing Colors that Convey Information"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-accessibility/avoid-colorblindness-issues-by-using-sufficient-contrast",
+ "blockName": "Applied Accessibility"
+ },
+ "id": "587d778f367417b2b2512aac",
+ "title": "Avoid Colorblindness Issues by Using Sufficient Contrast"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-accessibility/give-links-meaning-by-using-descriptive-link-text",
+ "blockName": "Applied Accessibility"
+ },
+ "id": "587d778f367417b2b2512aae",
+ "title": "Give Links Meaning by Using Descriptive Link Text"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-accessibility/improve-accessibility-of-audio-content-with-the-audio-element",
+ "blockName": "Applied Accessibility"
+ },
+ "id": "587d7789367417b2b2512aa4",
+ "title": "Improve Accessibility of Audio Content with the audio Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-accessibility/improve-chart-accessibility-with-the-figure-element",
+ "blockName": "Applied Accessibility"
+ },
+ "id": "587d778a367417b2b2512aa5",
+ "title": "Improve Chart Accessibility with the figure Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-accessibility/improve-form-field-accessibility-with-the-label-element",
+ "blockName": "Applied Accessibility"
+ },
+ "id": "587d778a367417b2b2512aa6",
+ "title": "Improve Form Field Accessibility with the label Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-accessibility/improve-readability-with-high-contrast-text",
+ "blockName": "Applied Accessibility"
+ },
+ "id": "587d778e367417b2b2512aab",
+ "title": "Improve Readability with High Contrast Text"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-accessibility/jump-straight-to-the-content-using-the-main-element",
+ "blockName": "Applied Accessibility"
+ },
+ "id": "587d774e367417b2b2512a9f",
+ "title": "Jump Straight to the Content Using the main Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-accessibility/know-when-alt-text-should-be-left-blank",
+ "blockName": "Applied Accessibility"
+ },
+ "id": "587d774c367417b2b2512a9d",
+ "title": "Know When Alt Text Should be Left Blank"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-accessibility/make-elements-only-visible-to-a-screen-reader-by-using-custom-css",
+ "blockName": "Applied Accessibility"
+ },
+ "id": "587d778d367417b2b2512aaa",
+ "title": "Make Elements Only Visible to a Screen Reader by Using Custom CSS"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-accessibility/make-links-navigable-with-html-access-keys",
+ "blockName": "Applied Accessibility"
+ },
+ "id": "587d7790367417b2b2512aaf",
+ "title": "Make Links Navigable with HTML Access Keys"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-accessibility/make-screen-reader-navigation-easier-with-the-footer-landmark",
+ "blockName": "Applied Accessibility"
+ },
+ "id": "587d7788367417b2b2512aa3",
+ "title": "Make Screen Reader Navigation Easier with the footer Landmark"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-accessibility/make-screen-reader-navigation-easier-with-the-header-landmark",
+ "blockName": "Applied Accessibility"
+ },
+ "id": "587d7787367417b2b2512aa1",
+ "title": "Make Screen Reader Navigation Easier with the header Landmark"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-accessibility/make-screen-reader-navigation-easier-with-the-nav-landmark",
+ "blockName": "Applied Accessibility"
+ },
+ "id": "587d7788367417b2b2512aa2",
+ "title": "Make Screen Reader Navigation Easier with the nav Landmark"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-accessibility/standardize-times-with-the-html5-datetime-attribute",
+ "blockName": "Applied Accessibility"
+ },
+ "id": "587d778c367417b2b2512aa9",
+ "title": "Standardize Times with the HTML5 datetime Attribute"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-accessibility/use-headings-to-show-hierarchical-relationships-of-content",
+ "blockName": "Applied Accessibility"
+ },
+ "id": "587d774d367417b2b2512a9e",
+ "title": "Use Headings to Show Hierarchical Relationships of Content"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-accessibility/use-tabindex-to-add-keyboard-focus-to-an-element",
+ "blockName": "Applied Accessibility"
+ },
+ "id": "587d7790367417b2b2512ab0",
+ "title": "Use tabindex to Add Keyboard Focus to an Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-accessibility/use-tabindex-to-specify-the-order-of-keyboard-focus-for-several-elements",
+ "blockName": "Applied Accessibility"
+ },
+ "id": "587d7790367417b2b2512ab1",
+ "title": "Use tabindex to Specify the Order of Keyboard Focus for Several Elements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-accessibility/wrap-content-in-the-article-element",
+ "blockName": "Applied Accessibility"
+ },
+ "id": "587d774e367417b2b2512aa0",
+ "title": "Wrap Content in the article Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-accessibility/wrap-radio-buttons-in-a-fieldset-element-for-better-accessibility",
+ "blockName": "Applied Accessibility"
+ },
+ "id": "587d778b367417b2b2512aa7",
+ "title": "Wrap Radio Buttons in a fieldset Element for Better Accessibility"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/add-a-box-shadow-to-a-card-like-element",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d781b367417b2b2512abe",
+ "title": "Add a box-shadow to a Card-like Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/adjust-the-background-color-property-of-text",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d781b367417b2b2512abc",
+ "title": "Adjust the background-color Property of Text"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/adjust-the-color-of-various-elements-to-complementary-colors",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a4367417b2b2512ad3",
+ "title": "Adjust the Color of Various Elements to Complementary Colors"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/adjust-the-height-of-an-element-using-the-height-property",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d7791367417b2b2512ab5",
+ "title": "Adjust the Height of an Element Using the height Property"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/adjust-the-hover-state-of-an-anchor-tag",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d781d367417b2b2512ac8",
+ "title": "Adjust the Hover State of an Anchor Tag"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/adjust-the-hue-of-a-color",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a4367417b2b2512ad4",
+ "title": "Adjust the Hue of a Color"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/adjust-the-size-of-a-heading-element-versus-a-paragraph-element",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d781b367417b2b2512abd",
+ "title": "Adjust the Size of a Heading Element Versus a Paragraph Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/adjust-the-tone-of-a-color",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a4367417b2b2512ad5",
+ "title": "Adjust the Tone of a Color"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/adjust-the-width-of-an-element-using-the-width-property",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d7791367417b2b2512ab4",
+ "title": "Adjust the Width of an Element Using the width Property"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/animate-elements-at-variable-rates",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a8367417b2b2512ae5",
+ "title": "Animate Elements at Variable Rates"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/animate-elements-continually-using-an-infinite-animation-count",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a8367417b2b2512ae3",
+ "title": "Animate Elements Continually Using an Infinite Animation Count"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/animate-multiple-elements-at-variable-rates",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a8367417b2b2512ae6",
+ "title": "Animate Multiple Elements at Variable Rates"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/center-an-element-horizontally-using-the-margin-property",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a3367417b2b2512ad0",
+ "title": "Center an Element Horizontally Using the margin Property"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/change-an-elements-relative-position",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d781e367417b2b2512ac9",
+ "title": "Change an Element's Relative Position"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/change-animation-timing-with-keywords",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a8367417b2b2512ae7",
+ "title": "Change Animation Timing with Keywords"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/change-the-position-of-overlapping-elements-with-the-z-index-property",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a3367417b2b2512acf",
+ "title": "Change the Position of Overlapping Elements with the z-index Property"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/create-a-gradual-css-linear-gradient",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a5367417b2b2512ad6",
+ "title": "Create a Gradual CSS Linear Gradient"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/create-a-graphic-using-css",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a6367417b2b2512add",
+ "title": "Create a Graphic Using CSS"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/create-a-horizontal-line-using-the-hr-element",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d781b367417b2b2512abb",
+ "title": "Create a Horizontal Line Using the hr Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/create-a-more-complex-shape-using-css-and-html",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a6367417b2b2512ade",
+ "title": "Create a More Complex Shape Using CSS and HTML"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/create-movement-using-css-animation",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a7367417b2b2512ae1",
+ "title": "Create Movement Using CSS Animation"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/create-texture-by-adding-a-subtle-pattern-as-a-background-image",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a5367417b2b2512ad8",
+ "title": "Create Texture by Adding a Subtle Pattern as a Background Image"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/create-visual-balance-using-the-text-align-property",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d7791367417b2b2512ab3",
+ "title": "Create Visual Balance Using the text-align Property"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/create-visual-direction-by-fading-an-element-from-left-to-right",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a7367417b2b2512ae2",
+ "title": "Create Visual Direction by Fading an Element from Left to Right"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/decrease-the-opacity-of-an-element",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d781c367417b2b2512abf",
+ "title": "Decrease the Opacity of an Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/learn-about-complementary-colors",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a3367417b2b2512ad1",
+ "title": "Learn about Complementary Colors"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/learn-about-tertiary-colors",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a4367417b2b2512ad2",
+ "title": "Learn about Tertiary Colors"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/learn-how-bezier-curves-work",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a9367417b2b2512ae8",
+ "title": "Learn How Bezier Curves Work"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/learn-how-the-css-keyframes-and-animation-properties-work",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a7367417b2b2512adf",
+ "title": "Learn How the CSS @keyframes and animation Properties Work"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/lock-an-element-to-its-parent-with-absolute-positioning",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d781e367417b2b2512acb",
+ "title": "Lock an Element to its Parent with Absolute Positioning"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/lock-an-element-to-the-browser-window-with-fixed-positioning",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d781e367417b2b2512acc",
+ "title": "Lock an Element to the Browser Window with Fixed Positioning"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/make-a-css-heartbeat-using-an-infinite-animation-count",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a8367417b2b2512ae4",
+ "title": "Make a CSS Heartbeat using an Infinite Animation Count"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/make-motion-more-natural-using-a-bezier-curve",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a9367417b2b2512aea",
+ "title": "Make Motion More Natural Using a Bezier Curve"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/modify-fill-mode-of-an-animation",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "58a7a6ebf9a6318348e2d5aa",
+ "title": "Modify Fill Mode of an Animation"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/move-a-relatively-positioned-element-with-css-offsets",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d781e367417b2b2512aca",
+ "title": "Move a Relatively Positioned Element with CSS Offsets"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/push-elements-left-or-right-with-the-float-property",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a3367417b2b2512ace",
+ "title": "Push Elements Left or Right with the float Property"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/set-the-font-size-for-multiple-heading-elements",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d781c367417b2b2512ac2",
+ "title": "Set the font-size for Multiple Heading Elements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/set-the-font-size-of-paragraph-text",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d781c367417b2b2512ac4",
+ "title": "Set the font-size of Paragraph Text"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/set-the-font-weight-for-multiple-heading-elements",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d781c367417b2b2512ac3",
+ "title": "Set the font-weight for Multiple Heading Elements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/set-the-line-height-of-paragraphs",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d781d367417b2b2512ac5",
+ "title": "Set the line-height of Paragraphs"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/use-a-bezier-curve-to-move-a-graphic",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a9367417b2b2512ae9",
+ "title": "Use a Bezier Curve to Move a Graphic"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/use-a-css-linear-gradient-to-create-a-striped-element",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a5367417b2b2512ad7",
+ "title": "Use a CSS Linear Gradient to Create a Striped Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/use-css-animation-to-change-the-hover-state-of-a-button",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a7367417b2b2512ae0",
+ "title": "Use CSS Animation to Change the Hover State of a Button"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/use-the-css-transform-property-skewx-to-skew-an-element-along-the-x-axis",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a6367417b2b2512adb",
+ "title": "Use the CSS Transform Property skewX to Skew an Element Along the X-Axis"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/use-the-css-transform-property-skewy-to-skew-an-element-along-the-y-axis",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a6367417b2b2512adc",
+ "title": "Use the CSS Transform Property skewY to Skew an Element Along the Y-Axis"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/use-the-css-transform-scale-property-to-change-the-size-of-an-element",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a5367417b2b2512ad9",
+ "title": "Use the CSS Transform scale Property to Change the Size of an Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/use-the-css-transform-scale-property-to-scale-an-element-on-hover",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d78a5367417b2b2512ada",
+ "title": "Use the CSS Transform scale Property to Scale an Element on Hover"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/use-the-em-tag-to-italicize-text",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d781a367417b2b2512ab9",
+ "title": "Use the em Tag to Italicize Text"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/use-the-s-tag-to-strikethrough-text",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d781b367417b2b2512aba",
+ "title": "Use the s Tag to Strikethrough Text"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/use-the-strong-tag-to-make-text-bold",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d781a367417b2b2512ab7",
+ "title": "Use the strong Tag to Make Text Bold"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/use-the-text-transform-property-to-make-text-uppercase",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d781c367417b2b2512ac0",
+ "title": "Use the text-transform Property to Make Text Uppercase"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/applied-visual-design/use-the-u-tag-to-underline-text",
+ "blockName": "Applied Visual Design"
+ },
+ "id": "587d781a367417b2b2512ab8",
+ "title": "Use the u Tag to Underline Text"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/add-a-negative-margin-to-an-element",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9aedf08823",
+ "title": "Add a Negative Margin to an Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/add-borders-around-your-elements",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9bedf08813",
+ "title": "Add Borders Around Your Elements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/add-different-margins-to-each-side-of-an-element",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1248bd9aedf08824",
+ "title": "Add Different Margins to Each Side of an Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/add-different-padding-to-each-side-of-an-element",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9aedf08824",
+ "title": "Add Different Padding to Each Side of an Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/add-rounded-corners-with-border-radius",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9aedf08814",
+ "title": "Add Rounded Corners with border-radius"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/adjust-the-margin-of-an-element",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9aedf08822",
+ "title": "Adjust the Margin of an Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/adjust-the-padding-of-an-element",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad88fee1348bd9aedf08825",
+ "title": "Adjust the Padding of an Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/attach-a-fallback-value-to-a-css-variable",
+ "blockName": "Basic CSS"
+ },
+ "id": "5a9d7286424fe3d0e10cad13",
+ "title": "Attach a Fallback value to a CSS Variable"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/change-a-variable-for-a-specific-area",
+ "blockName": "Basic CSS"
+ },
+ "id": "5a9d72a1424fe3d0e10cad15",
+ "title": "Change a variable for a specific area"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/change-the-color-of-text",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9aedf08803",
+ "title": "Change the Color of Text"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/change-the-font-size-of-an-element",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9aedf08806",
+ "title": "Change the Font Size of an Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/create-a-custom-css-variable",
+ "blockName": "Basic CSS"
+ },
+ "id": "5a9d726c424fe3d0e10cad11",
+ "title": "Create a custom CSS Variable"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/give-a-background-color-to-a-div-element",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fed1348bd9aede07836",
+ "title": "Give a Background Color to a div Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/import-a-google-font",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9aedf08807",
+ "title": "Import a Google Font"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/improve-compatibility-with-browser-fallbacks",
+ "blockName": "Basic CSS"
+ },
+ "id": "5b7d72c338cd7e35b63f3e14",
+ "title": "Improve Compatibility with Browser Fallbacks"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/inherit-css-variables",
+ "blockName": "Basic CSS"
+ },
+ "id": "5a9d7295424fe3d0e10cad14",
+ "title": "Inherit CSS Variables"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/inherit-styles-from-the-body-element",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9aedf08746",
+ "title": "Inherit Styles from the Body Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/make-circular-images-with-a-border-radius",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9aedf08815",
+ "title": "Make Circular Images with a border-radius"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/override-all-other-styles-by-using-important",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9aedf07756",
+ "title": "Override All Other Styles by using Important"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/override-class-declarations-by-styling-id-attributes",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd8aedf06756",
+ "title": "Override Class Declarations by Styling ID Attributes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/override-class-declarations-with-inline-styles",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9aedf06756",
+ "title": "Override Class Declarations with Inline Styles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/override-styles-in-subsequent-css",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9aedf04756",
+ "title": "Override Styles in Subsequent CSS"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/prioritize-one-style-over-another",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9aedf08756",
+ "title": "Prioritize One Style Over Another"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/set-the-font-family-of-an-element",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9aede08807",
+ "title": "Set the Font Family of an Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/set-the-id-of-an-element",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87eee1348bd9aede07836",
+ "title": "Set the id of an Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/size-your-images",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9acdf08812",
+ "title": "Size Your Images"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/specify-how-fonts-should-degrade",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9aedf08808",
+ "title": "Specify How Fonts Should Degrade"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/style-multiple-elements-with-a-css-class",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9aefe08806",
+ "title": "Style Multiple Elements with a CSS Class"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/style-the-html-body-element",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9aedf08736",
+ "title": "Style the HTML Body Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/understand-absolute-versus-relative-units",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad82fee1322bd9aedf08721",
+ "title": "Understand Absolute versus Relative Units"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/use-a-css-class-to-style-an-element",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9aecf08806",
+ "title": "Use a CSS Class to Style an Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/use-a-custom-css-variable",
+ "blockName": "Basic CSS"
+ },
+ "id": "5a9d727a424fe3d0e10cad12",
+ "title": "Use a custom CSS Variable"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/use-a-media-query-to-change-a-variable",
+ "blockName": "Basic CSS"
+ },
+ "id": "5a9d72ad424fe3d0e10cad16",
+ "title": "Use a media query to change a variable"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/use-abbreviated-hex-code",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9aedf08719",
+ "title": "Use Abbreviated Hex Code"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/use-an-id-attribute-to-style-an-element",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87dee1348bd9aede07836",
+ "title": "Use an id Attribute to Style an Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/use-attribute-selectors-to-style-elements",
+ "blockName": "Basic CSS"
+ },
+ "id": "58c383d33e2e3259241f3076",
+ "title": "Use Attribute Selectors to Style Elements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/use-clockwise-notation-to-specify-the-margin-of-an-element",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9afdf08726",
+ "title": "Use Clockwise Notation to Specify the Margin of an Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/use-clockwise-notation-to-specify-the-padding-of-an-element",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9aedf08826",
+ "title": "Use Clockwise Notation to Specify the Padding of an Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/use-css-selectors-to-style-elements",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9aedf08805",
+ "title": "Use CSS Selectors to Style Elements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/use-css-variables-to-change-several-elements-at-once",
+ "blockName": "Basic CSS"
+ },
+ "id": "5a9d725e424fe3d0e10cad10",
+ "title": "Use CSS Variables to change several elements at once"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/use-hex-code-for-specific-colors",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9aedf08726",
+ "title": "Use Hex Code for Specific Colors"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/use-hex-code-to-mix-colors",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9aedf08721",
+ "title": "Use Hex Code to Mix Colors"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/use-rgb-to-mix-colors",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad82fee1348bd9aedf08721",
+ "title": "Use RGB to Mix Colors"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-css/use-rgb-values-to-color-elements",
+ "blockName": "Basic CSS"
+ },
+ "id": "bad87fee1348bd9aede08718",
+ "title": "Use RGB values to Color Elements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/add-a-submit-button-to-a-form",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "bad87fee1348bd9aedd08830",
+ "title": "Add a Submit Button to a Form"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/add-images-to-your-website",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "bad87fee1348bd9aedf08812",
+ "title": "Add Images to Your Website"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/add-placeholder-text-to-a-text-field",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "bad87fee1348bd9aedf08830",
+ "title": "Add Placeholder Text to a Text Field"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/check-radio-buttons-and-checkboxes-by-default",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "bad87fee1348bd9aedd08835",
+ "title": "Check Radio Buttons and Checkboxes by Default"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/comment-out-html",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "bad87fee1348bd9aedf08804",
+ "title": "Comment out HTML"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/create-a-bulleted-unordered-list",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "bad87fee1348bd9aedf08827",
+ "title": "Create a Bulleted Unordered List"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/create-a-form-element",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "bad87fee1348bd9aede08830",
+ "title": "Create a Form Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/create-a-set-of-checkboxes",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "bad87fee1348bd9aedf08835",
+ "title": "Create a Set of Checkboxes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/create-a-set-of-radio-buttons",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "bad87fee1348bd9aedf08834",
+ "title": "Create a Set of Radio Buttons"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/create-a-text-field",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "bad87fee1348bd9aedf08829",
+ "title": "Create a Text Field"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/create-an-ordered-list",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "bad87fee1348bd9aedf08828",
+ "title": "Create an Ordered List"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/declare-the-doctype-of-an-html-document",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "587d78aa367417b2b2512aed",
+ "title": "Declare the Doctype of an HTML Document"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/define-the-head-and-body-of-an-html-document",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "587d78aa367417b2b2512aec",
+ "title": "Define the Head and Body of an HTML Document"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/delete-html-elements",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "bad87fed1348bd9aedf08833",
+ "title": "Delete HTML Elements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/fill-in-the-blank-with-placeholder-text",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "bad87fee1348bd9aedf08833",
+ "title": "Fill in the Blank with Placeholder Text"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/headline-with-the-h2-element",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "bad87fee1348bd9aedf0887a",
+ "title": "Headline with the h2 Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/inform-with-the-paragraph-element",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "bad87fee1348bd9aedf08801",
+ "title": "Inform with the Paragraph Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/introduction-to-html5-elements",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "bad87fee1348bd9aecf08801",
+ "title": "Introduction to HTML5 Elements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/link-to-external-pages-with-anchor-elements",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "bad87fee1348bd9aedf08816",
+ "title": "Link to External Pages with Anchor Elements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/link-to-internal-sections-of-a-page-with-anchor-elements",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "bad88fee1348bd9aedf08816",
+ "title": "Link to Internal Sections of a Page with Anchor Elements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/make-dead-links-using-the-hash-symbol",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "bad87fee1348bd9aedf08817",
+ "title": "Make Dead Links Using the Hash Symbol"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/nest-an-anchor-element-within-a-paragraph",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "bad87fee1348bd9aede08817",
+ "title": "Nest an Anchor Element within a Paragraph"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/nest-many-elements-within-a-single-div-element",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "bad87fee1348bd9aede08835",
+ "title": "Nest Many Elements within a Single div Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/say-hello-to-html-elements",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "bd7123c8c441eddfaeb5bdef",
+ "title": "Say Hello to HTML Elements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/turn-an-image-into-a-link",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "bad87fee1348bd9aedf08820",
+ "title": "Turn an Image into a Link"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/uncomment-html",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "bad87fee1348bd9aedf08802",
+ "title": "Uncomment HTML"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/use-html5-to-require-a-field",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "bad87fee1348bd9aedc08830",
+ "title": "Use HTML5 to Require a Field"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/basic-html-and-html5/use-the-value-attribute-with-radio-buttons-and-checkboxes",
+ "blockName": "Basic HTML and HTML5"
+ },
+ "id": "5c6c06847491271903d37cfd",
+ "title": "Use the value attribute with Radio Buttons and Checkboxes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-flexbox/add-flex-superpowers-to-the-tweet-embed",
+ "blockName": "CSS Flexbox"
+ },
+ "id": "587d78ab367417b2b2512af1",
+ "title": "Add Flex Superpowers to the Tweet Embed"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-flexbox/align-elements-using-the-align-items-property",
+ "blockName": "CSS Flexbox"
+ },
+ "id": "587d78ad367417b2b2512af8",
+ "title": "Align Elements Using the align-items Property"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-flexbox/align-elements-using-the-justify-content-property",
+ "blockName": "CSS Flexbox"
+ },
+ "id": "587d78ac367417b2b2512af6",
+ "title": "Align Elements Using the justify-content Property"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-flexbox/apply-the-flex-direction-property-to-create-a-column-in-the-tweet-embed",
+ "blockName": "CSS Flexbox"
+ },
+ "id": "587d78ac367417b2b2512af5",
+ "title": "Apply the flex-direction Property to Create a Column in the Tweet Embed"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-flexbox/apply-the-flex-direction-property-to-create-rows-in-the-tweet-embed",
+ "blockName": "CSS Flexbox"
+ },
+ "id": "587d78ab367417b2b2512af3",
+ "title": "Apply the flex-direction Property to Create Rows in the Tweet Embed"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-flexbox/use-display-flex-to-position-two-boxes",
+ "blockName": "CSS Flexbox"
+ },
+ "id": "587d78ab367417b2b2512af0",
+ "title": "Use display: flex to Position Two Boxes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-flexbox/use-the-align-items-property-in-the-tweet-embed",
+ "blockName": "CSS Flexbox"
+ },
+ "id": "587d78ad367417b2b2512af9",
+ "title": "Use the align-items Property in the Tweet Embed"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-flexbox/use-the-align-self-property",
+ "blockName": "CSS Flexbox"
+ },
+ "id": "587d78af367417b2b2512b00",
+ "title": "Use the align-self Property"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-flexbox/use-the-flex-basis-property-to-set-the-initial-size-of-an-item",
+ "blockName": "CSS Flexbox"
+ },
+ "id": "587d78ae367417b2b2512afd",
+ "title": "Use the flex-basis Property to Set the Initial Size of an Item"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-flexbox/use-the-flex-direction-property-to-make-a-column",
+ "blockName": "CSS Flexbox"
+ },
+ "id": "587d78ac367417b2b2512af4",
+ "title": "Use the flex-direction Property to Make a Column"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-flexbox/use-the-flex-direction-property-to-make-a-row",
+ "blockName": "CSS Flexbox"
+ },
+ "id": "587d78ab367417b2b2512af2",
+ "title": "Use the flex-direction Property to Make a Row"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-flexbox/use-the-flex-grow-property-to-expand-items",
+ "blockName": "CSS Flexbox"
+ },
+ "id": "587d78ae367417b2b2512afc",
+ "title": "Use the flex-grow Property to Expand Items"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-flexbox/use-the-flex-shorthand-property",
+ "blockName": "CSS Flexbox"
+ },
+ "id": "587d78ae367417b2b2512afe",
+ "title": "Use the flex Shorthand Property"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-flexbox/use-the-flex-shrink-property-to-shrink-items",
+ "blockName": "CSS Flexbox"
+ },
+ "id": "587d78ad367417b2b2512afb",
+ "title": "Use the flex-shrink Property to Shrink Items"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-flexbox/use-the-flex-wrap-property-to-wrap-a-row-or-column",
+ "blockName": "CSS Flexbox"
+ },
+ "id": "587d78ad367417b2b2512afa",
+ "title": "Use the flex-wrap Property to Wrap a Row or Column"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-flexbox/use-the-justify-content-property-in-the-tweet-embed",
+ "blockName": "CSS Flexbox"
+ },
+ "id": "587d78ac367417b2b2512af7",
+ "title": "Use the justify-content Property in the Tweet Embed"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-flexbox/use-the-order-property-to-rearrange-items",
+ "blockName": "CSS Flexbox"
+ },
+ "id": "587d78ae367417b2b2512aff",
+ "title": "Use the order Property to Rearrange Items"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-grid/add-columns-with-grid-template-columns",
+ "blockName": "CSS Grid"
+ },
+ "id": "5a9036d038fddaf9a66b5d32",
+ "title": "Add Columns with grid-template-columns"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-grid/add-gaps-faster-with-grid-gap",
+ "blockName": "CSS Grid"
+ },
+ "id": "5a9036ee38fddaf9a66b5d37",
+ "title": "Add Gaps Faster with grid-gap"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-grid/add-rows-with-grid-template-rows",
+ "blockName": "CSS Grid"
+ },
+ "id": "5a9036e138fddaf9a66b5d33",
+ "title": "Add Rows with grid-template-rows"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-grid/align-all-items-horizontally-using-justify-items",
+ "blockName": "CSS Grid"
+ },
+ "id": "5a90376038fddaf9a66b5d3c",
+ "title": "Align All Items Horizontally using justify-items"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-grid/align-all-items-vertically-using-align-items",
+ "blockName": "CSS Grid"
+ },
+ "id": "5a94fdf869fb03452672e45b",
+ "title": "Align All Items Vertically using align-items"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-grid/align-an-item-horizontally-using-justify-self",
+ "blockName": "CSS Grid"
+ },
+ "id": "5a90374338fddaf9a66b5d3a",
+ "title": "Align an Item Horizontally using justify-self"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-grid/align-an-item-vertically-using-align-self",
+ "blockName": "CSS Grid"
+ },
+ "id": "5a90375238fddaf9a66b5d3b",
+ "title": "Align an Item Vertically using align-self"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-grid/create-a-column-gap-using-grid-column-gap",
+ "blockName": "CSS Grid"
+ },
+ "id": "5a9036ee38fddaf9a66b5d35",
+ "title": "Create a Column Gap Using grid-column-gap"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-grid/create-a-row-gap-using-grid-row-gap",
+ "blockName": "CSS Grid"
+ },
+ "id": "5a9036ee38fddaf9a66b5d36",
+ "title": "Create a Row Gap using grid-row-gap"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-grid/create-flexible-layouts-using-auto-fill",
+ "blockName": "CSS Grid"
+ },
+ "id": "5a94fe5469fb03452672e461",
+ "title": "Create Flexible Layouts Using auto-fill"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-grid/create-flexible-layouts-using-auto-fit",
+ "blockName": "CSS Grid"
+ },
+ "id": "5a94fe6269fb03452672e462",
+ "title": "Create Flexible Layouts Using auto-fit"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-grid/create-grids-within-grids",
+ "blockName": "CSS Grid"
+ },
+ "id": "5a94fe8569fb03452672e464",
+ "title": "Create Grids within Grids"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-grid/create-your-first-css-grid",
+ "blockName": "CSS Grid"
+ },
+ "id": "5a858944d96184f06fd60d61",
+ "title": "Create Your First CSS Grid"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-grid/divide-the-grid-into-an-area-template",
+ "blockName": "CSS Grid"
+ },
+ "id": "5a94fe0569fb03452672e45c",
+ "title": "Divide the Grid Into an Area Template"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-grid/limit-item-size-using-the-minmax-function",
+ "blockName": "CSS Grid"
+ },
+ "id": "5a94fe4469fb03452672e460",
+ "title": "Limit Item Size Using the minmax Function"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-grid/place-items-in-grid-areas-using-the-grid-area-property",
+ "blockName": "CSS Grid"
+ },
+ "id": "5a94fe1369fb03452672e45d",
+ "title": "Place Items in Grid Areas Using the grid-area Property"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-grid/reduce-repetition-using-the-repeat-function",
+ "blockName": "CSS Grid"
+ },
+ "id": "5a94fe3669fb03452672e45f",
+ "title": "Reduce Repetition Using the repeat Function"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-grid/use-css-grid-units-to-change-the-size-of-columns-and-rows",
+ "blockName": "CSS Grid"
+ },
+ "id": "5a9036ee38fddaf9a66b5d34",
+ "title": "Use CSS Grid units to Change the Size of Columns and Rows"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-grid/use-grid-area-without-creating-an-areas-template",
+ "blockName": "CSS Grid"
+ },
+ "id": "5a94fe2669fb03452672e45e",
+ "title": "Use grid-area Without Creating an Areas Template"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-grid/use-grid-column-to-control-spacing",
+ "blockName": "CSS Grid"
+ },
+ "id": "5a90372638fddaf9a66b5d38",
+ "title": "Use grid-column to Control Spacing"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-grid/use-grid-row-to-control-spacing",
+ "blockName": "CSS Grid"
+ },
+ "id": "5a90373638fddaf9a66b5d39",
+ "title": "Use grid-row to Control Spacing"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/css-grid/use-media-queries-to-create-responsive-layouts",
+ "blockName": "CSS Grid"
+ },
+ "id": "5a94fe7769fb03452672e463",
+ "title": "Use Media Queries to Create Responsive Layouts"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/responsive-web-design-principles/create-a-media-query",
+ "blockName": "Responsive Web Design Principles"
+ },
+ "id": "587d78b0367417b2b2512b08",
+ "title": "Create a Media Query"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/responsive-web-design-principles/make-an-image-responsive",
+ "blockName": "Responsive Web Design Principles"
+ },
+ "id": "587d78b1367417b2b2512b09",
+ "title": "Make an Image Responsive"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/responsive-web-design-principles/make-typography-responsive",
+ "blockName": "Responsive Web Design Principles"
+ },
+ "id": "587d78b1367417b2b2512b0c",
+ "title": "Make Typography Responsive"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/responsive-web-design-principles/use-a-retina-image-for-higher-resolution-displays",
+ "blockName": "Responsive Web Design Principles"
+ },
+ "id": "587d78b1367417b2b2512b0a",
+ "title": "Use a Retina Image for Higher Resolution Displays"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/responsive-web-design-projects/build-a-personal-portfolio-webpage",
+ "blockName": "Responsive Web Design Projects"
+ },
+ "id": "bd7158d8c242eddfaeb5bd13",
+ "title": "Build a Personal Portfolio Webpage"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/responsive-web-design-projects/build-a-product-landing-page",
+ "blockName": "Responsive Web Design Projects"
+ },
+ "id": "587d78af367417b2b2512b04",
+ "title": "Build a Product Landing Page"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/responsive-web-design-projects/build-a-survey-form",
+ "blockName": "Responsive Web Design Projects"
+ },
+ "id": "587d78af367417b2b2512b03",
+ "title": "Build a Survey Form"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/responsive-web-design-projects/build-a-technical-documentation-page",
+ "blockName": "Responsive Web Design Projects"
+ },
+ "id": "587d78b0367417b2b2512b05",
+ "title": "Build a Technical Documentation Page"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/responsive-web-design/responsive-web-design-projects/build-a-tribute-page",
+ "blockName": "Responsive Web Design Projects"
+ },
+ "id": "bd7158d8c442eddfaeb5bd18",
+ "title": "Build a Tribute Page"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-algorithm-scripting/boo-who",
+ "blockName": "Basic Algorithm Scripting"
+ },
+ "id": "a77dbc43c33f39daa4429b4f",
+ "title": "Boo who"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-algorithm-scripting/chunky-monkey",
+ "blockName": "Basic Algorithm Scripting"
+ },
+ "id": "a9bd25c716030ec90084d8a1",
+ "title": "Chunky Monkey"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-algorithm-scripting/confirm-the-ending",
+ "blockName": "Basic Algorithm Scripting"
+ },
+ "id": "acda2fb1324d9b0fa741e6b5",
+ "title": "Confirm the Ending"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-algorithm-scripting/convert-celsius-to-fahrenheit",
+ "blockName": "Basic Algorithm Scripting"
+ },
+ "id": "56533eb9ac21ba0edf2244b3",
+ "title": "Convert Celsius to Fahrenheit"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-algorithm-scripting/factorialize-a-number",
+ "blockName": "Basic Algorithm Scripting"
+ },
+ "id": "a302f7aae1aa3152a5b413bc",
+ "title": "Factorialize a Number"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-algorithm-scripting/falsy-bouncer",
+ "blockName": "Basic Algorithm Scripting"
+ },
+ "id": "adf08ec01beb4f99fc7a68f2",
+ "title": "Falsy Bouncer"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-algorithm-scripting/find-the-longest-word-in-a-string",
+ "blockName": "Basic Algorithm Scripting"
+ },
+ "id": "a26cbbe9ad8655a977e1ceb5",
+ "title": "Find the Longest Word in a String"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-algorithm-scripting/finders-keepers",
+ "blockName": "Basic Algorithm Scripting"
+ },
+ "id": "a6e40f1041b06c996f7b2406",
+ "title": "Finders Keepers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-algorithm-scripting/mutations",
+ "blockName": "Basic Algorithm Scripting"
+ },
+ "id": "af2170cad53daa0770fabdea",
+ "title": "Mutations"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-algorithm-scripting/repeat-a-string-repeat-a-string",
+ "blockName": "Basic Algorithm Scripting"
+ },
+ "id": "afcc8d540bea9ea2669306b6",
+ "title": "Repeat a String Repeat a String"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-algorithm-scripting/return-largest-numbers-in-arrays",
+ "blockName": "Basic Algorithm Scripting"
+ },
+ "id": "a789b3483989747d63b0e427",
+ "title": "Return Largest Numbers in Arrays"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-algorithm-scripting/reverse-a-string",
+ "blockName": "Basic Algorithm Scripting"
+ },
+ "id": "a202eed8fc186c8434cb6d61",
+ "title": "Reverse a String"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-algorithm-scripting/slice-and-splice",
+ "blockName": "Basic Algorithm Scripting"
+ },
+ "id": "579e2a2c335b9d72dd32e05c",
+ "title": "Slice and Splice"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-algorithm-scripting/title-case-a-sentence",
+ "blockName": "Basic Algorithm Scripting"
+ },
+ "id": "ab6137d4e35944e21037b769",
+ "title": "Title Case a Sentence"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-algorithm-scripting/truncate-a-string",
+ "blockName": "Basic Algorithm Scripting"
+ },
+ "id": "ac6993d51946422351508a41",
+ "title": "Truncate a String"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-algorithm-scripting/where-do-i-belong",
+ "blockName": "Basic Algorithm Scripting"
+ },
+ "id": "a24c1a4622e3c05097f71d67",
+ "title": "Where do I Belong"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-data-structures/access-an-arrays-contents-using-bracket-notation",
+ "blockName": "Basic Data Structures"
+ },
+ "id": "5a661e0f1068aca922b3ef17",
+ "title": "Access an Array's Contents Using Bracket Notation"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-data-structures/access-property-names-with-bracket-notation",
+ "blockName": "Basic Data Structures"
+ },
+ "id": "587d7b7c367417b2b2512b1a",
+ "title": "Access Property Names with Bracket Notation"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-data-structures/add-items-to-an-array-with-push-and-unshift",
+ "blockName": "Basic Data Structures"
+ },
+ "id": "587d78b2367417b2b2512b0e",
+ "title": "Add Items to an Array with push() and unshift()"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-data-structures/add-items-using-splice",
+ "blockName": "Basic Data Structures"
+ },
+ "id": "587d78b3367417b2b2512b11",
+ "title": "Add Items Using splice()"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-data-structures/add-key-value-pairs-to-javascript-objects",
+ "blockName": "Basic Data Structures"
+ },
+ "id": "587d7b7c367417b2b2512b18",
+ "title": "Add Key-Value Pairs to JavaScript Objects"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-data-structures/check-for-the-presence-of-an-element-with-indexof",
+ "blockName": "Basic Data Structures"
+ },
+ "id": "587d7b7b367417b2b2512b14",
+ "title": "Check For The Presence of an Element With indexOf()"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-data-structures/check-if-an-object-has-a-property",
+ "blockName": "Basic Data Structures"
+ },
+ "id": "587d7b7d367417b2b2512b1c",
+ "title": "Check if an Object has a Property"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-data-structures/combine-arrays-with-the-spread-operator",
+ "blockName": "Basic Data Structures"
+ },
+ "id": "587d7b7b367417b2b2512b17",
+ "title": "Combine Arrays with the Spread Operator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-data-structures/copy-an-array-with-the-spread-operator",
+ "blockName": "Basic Data Structures"
+ },
+ "id": "587d7b7b367417b2b2512b13",
+ "title": "Copy an Array with the Spread Operator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-data-structures/copy-array-items-using-slice",
+ "blockName": "Basic Data Structures"
+ },
+ "id": "587d7b7a367417b2b2512b12",
+ "title": "Copy Array Items Using slice()"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-data-structures/create-complex-multi-dimensional-arrays",
+ "blockName": "Basic Data Structures"
+ },
+ "id": "587d7b7b367417b2b2512b16",
+ "title": "Create complex multi-dimensional arrays"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-data-structures/generate-an-array-of-all-object-keys-with-object-keys",
+ "blockName": "Basic Data Structures"
+ },
+ "id": "587d7b7d367417b2b2512b1e",
+ "title": "Generate an Array of All Object Keys with Object.keys()"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-data-structures/iterate-through-all-an-arrays-items-using-for-loops",
+ "blockName": "Basic Data Structures"
+ },
+ "id": "587d7b7b367417b2b2512b15",
+ "title": "Iterate Through All an Array's Items Using For Loops"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-data-structures/iterate-through-the-keys-of-an-object-with-a-for---in-statement",
+ "blockName": "Basic Data Structures"
+ },
+ "id": "587d7b7d367417b2b2512b1d",
+ "title": "Iterate Through the Keys of an Object with a for...in Statement"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-data-structures/modify-an-array-stored-in-an-object",
+ "blockName": "Basic Data Structures"
+ },
+ "id": "587d7b7d367417b2b2512b1f",
+ "title": "Modify an Array Stored in an Object"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-data-structures/modify-an-object-nested-within-an-object",
+ "blockName": "Basic Data Structures"
+ },
+ "id": "587d7b7c367417b2b2512b19",
+ "title": "Modify an Object Nested Within an Object"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-data-structures/remove-items-from-an-array-with-pop-and-shift",
+ "blockName": "Basic Data Structures"
+ },
+ "id": "587d78b2367417b2b2512b0f",
+ "title": "Remove Items from an Array with pop() and shift()"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-data-structures/remove-items-using-splice",
+ "blockName": "Basic Data Structures"
+ },
+ "id": "587d78b2367417b2b2512b10",
+ "title": "Remove Items Using splice()"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-data-structures/use-an-array-to-store-a-collection-of-data",
+ "blockName": "Basic Data Structures"
+ },
+ "id": "587d7b7e367417b2b2512b20",
+ "title": "Use an Array to Store a Collection of Data"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-data-structures/use-the-delete-keyword-to-remove-object-properties",
+ "blockName": "Basic Data Structures"
+ },
+ "id": "587d7b7c367417b2b2512b1b",
+ "title": "Use the delete Keyword to Remove Object Properties"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/access-array-data-with-indexes",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56bbb991ad1ed5201cd392ca",
+ "title": "Access Array Data with Indexes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/access-multi-dimensional-arrays-with-indexes",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56592a60ddddeae28f7aa8e1",
+ "title": "Access Multi-Dimensional Arrays With Indexes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/accessing-nested-arrays",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244cd",
+ "title": "Accessing Nested Arrays"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/accessing-nested-objects",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244cc",
+ "title": "Accessing Nested Objects"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/accessing-object-properties-with-bracket-notation",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244c8",
+ "title": "Accessing Object Properties with Bracket Notation"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/accessing-object-properties-with-dot-notation",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244c7",
+ "title": "Accessing Object Properties with Dot Notation"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/accessing-object-properties-with-variables",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244c9",
+ "title": "Accessing Object Properties with Variables"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/add-new-properties-to-a-javascript-object",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56bbb991ad1ed5201cd392d2",
+ "title": "Add New Properties to a JavaScript Object"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/add-two-numbers-with-javascript",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "cf1111c1c11feddfaeb3bdef",
+ "title": "Add Two Numbers with JavaScript"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/adding-a-default-option-in-switch-statements",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244de",
+ "title": "Adding a Default Option in Switch Statements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/appending-variables-to-strings",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244ed",
+ "title": "Appending Variables to Strings"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/assigning-the-value-of-one-variable-to-another",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "5ee127a03c3b35dd45426493",
+ "title": "Assigning the Value of One Variable to Another"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/assignment-with-a-returned-value",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244c3",
+ "title": "Assignment with a Returned Value"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/build-javascript-objects",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56bbb991ad1ed5201cd392d0",
+ "title": "Build JavaScript Objects"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/chaining-if-else-statements",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244dc",
+ "title": "Chaining If Else Statements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/comment-your-javascript-code",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "bd7123c9c441eddfaeb4bdef",
+ "title": "Comment Your JavaScript Code"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/comparison-with-the-equality-operator",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244d0",
+ "title": "Comparison with the Equality Operator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/comparison-with-the-greater-than-operator",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244d4",
+ "title": "Comparison with the Greater Than Operator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/comparison-with-the-greater-than-or-equal-to-operator",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244d5",
+ "title": "Comparison with the Greater Than Or Equal To Operator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/comparison-with-the-inequality-operator",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244d2",
+ "title": "Comparison with the Inequality Operator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/comparison-with-the-less-than-operator",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244d6",
+ "title": "Comparison with the Less Than Operator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/comparison-with-the-less-than-or-equal-to-operator",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244d7",
+ "title": "Comparison with the Less Than Or Equal To Operator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/comparison-with-the-strict-equality-operator",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244d1",
+ "title": "Comparison with the Strict Equality Operator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/comparison-with-the-strict-inequality-operator",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244d3",
+ "title": "Comparison with the Strict Inequality Operator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/comparisons-with-the-logical-and-operator",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244d8",
+ "title": "Comparisons with the Logical And Operator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/comparisons-with-the-logical-or-operator",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244d9",
+ "title": "Comparisons with the Logical Or Operator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/compound-assignment-with-augmented-addition",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244af",
+ "title": "Compound Assignment With Augmented Addition"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/compound-assignment-with-augmented-division",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244b2",
+ "title": "Compound Assignment With Augmented Division"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/compound-assignment-with-augmented-multiplication",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244b1",
+ "title": "Compound Assignment With Augmented Multiplication"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/compound-assignment-with-augmented-subtraction",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244b0",
+ "title": "Compound Assignment With Augmented Subtraction"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/concatenating-strings-with-plus-operator",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244b7",
+ "title": "Concatenating Strings with Plus Operator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/concatenating-strings-with-the-plus-equals-operator",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244b8",
+ "title": "Concatenating Strings with the Plus Equals Operator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/constructing-strings-with-variables",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244b9",
+ "title": "Constructing Strings with Variables"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/count-backwards-with-a-for-loop",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56105e7b514f539506016a5e",
+ "title": "Count Backwards With a For Loop"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/counting-cards",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "565bbe00e9cc8ac0725390f4",
+ "title": "Counting Cards"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/create-decimal-numbers-with-javascript",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "cf1391c1c11feddfaeb4bdef",
+ "title": "Create Decimal Numbers with JavaScript"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/declare-a-read-only-variable-with-the-const-keyword",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "587d7b87367417b2b2512b41",
+ "title": "Declare a Read-Only Variable with the const Keyword"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/declare-javascript-variables",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "bd7123c9c443eddfaeb5bdef",
+ "title": "Declare JavaScript Variables"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/declare-string-variables",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "bd7123c9c444eddfaeb5bdef",
+ "title": "Declare String Variables"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/decrement-a-number-with-javascript",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244ad",
+ "title": "Decrement a Number with JavaScript"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/delete-properties-from-a-javascript-object",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56bbb991ad1ed5201cd392d3",
+ "title": "Delete Properties from a JavaScript Object"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/divide-one-decimal-by-another-with-javascript",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "bd7993c9ca9feddfaeb7bdef",
+ "title": "Divide One Decimal by Another with JavaScript"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/divide-one-number-by-another-with-javascript",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "cf1111c1c11feddfaeb6bdef",
+ "title": "Divide One Number by Another with JavaScript"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/escape-sequences-in-strings",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244b6",
+ "title": "Escape Sequences in Strings"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/escaping-literal-quotes-in-strings",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244b5",
+ "title": "Escaping Literal Quotes in Strings"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/explore-differences-between-the-var-and-let-keywords",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "587d7b87367417b2b2512b3f",
+ "title": "Explore Differences Between the var and let Keywords"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/find-the-length-of-a-string",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "bd7123c9c448eddfaeb5bdef",
+ "title": "Find the Length of a String"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/finding-a-remainder-in-javascript",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244ae",
+ "title": "Finding a Remainder in JavaScript"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/generate-random-fractions-with-javascript",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "cf1111c1c11feddfaeb9bdef",
+ "title": "Generate Random Fractions with JavaScript"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/generate-random-whole-numbers-with-javascript",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "cf1111c1c12feddfaeb1bdef",
+ "title": "Generate Random Whole Numbers with JavaScript"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/generate-random-whole-numbers-within-a-range",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "cf1111c1c12feddfaeb2bdef",
+ "title": "Generate Random Whole Numbers within a Range"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/global-scope-and-functions",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244be",
+ "title": "Global Scope and Functions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/global-vs--local-scope-in-functions",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244c0",
+ "title": "Global vs. Local Scope in Functions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/golf-code",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "5664820f61c48e80c9fa476c",
+ "title": "Golf Code"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/increment-a-number-with-javascript",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244ac",
+ "title": "Increment a Number with JavaScript"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/initializing-variables-with-the-assignment-operator",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244a9",
+ "title": "Initializing Variables with the Assignment Operator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/introducing-else-if-statements",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244db",
+ "title": "Introducing Else If Statements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/introducing-else-statements",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244da",
+ "title": "Introducing Else Statements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/iterate-odd-numbers-with-a-for-loop",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56104e9e514f539506016a5c",
+ "title": "Iterate Odd Numbers With a For Loop"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/iterate-through-an-array-with-a-for-loop",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "5675e877dbd60be8ad28edc6",
+ "title": "Iterate Through an Array with a For Loop"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/iterate-with-javascript-do---while-loops",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "5a2efd662fb457916e1fe604",
+ "title": "Iterate with JavaScript Do...While Loops"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/iterate-with-javascript-for-loops",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "cf1111c1c11feddfaeb5bdef",
+ "title": "Iterate with JavaScript For Loops"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/iterate-with-javascript-while-loops",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "cf1111c1c11feddfaeb1bdef",
+ "title": "Iterate with JavaScript While Loops"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/local-scope-and-functions",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244bf",
+ "title": "Local Scope and Functions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/logical-order-in-if-else-statements",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "5690307fddb111c6084545d7",
+ "title": "Logical Order in If Else Statements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/manipulate-arrays-with-pop",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56bbb991ad1ed5201cd392cc",
+ "title": "Manipulate Arrays With pop()"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/manipulate-arrays-with-push",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56bbb991ad1ed5201cd392cb",
+ "title": "Manipulate Arrays With push()"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/manipulate-arrays-with-shift",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56bbb991ad1ed5201cd392cd",
+ "title": "Manipulate Arrays With shift()"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/manipulate-arrays-with-unshift",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56bbb991ad1ed5201cd392ce",
+ "title": "Manipulate Arrays With unshift()"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/manipulating-complex-objects",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244cb",
+ "title": "Manipulating Complex Objects"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/modify-array-data-with-indexes",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "cf1111c1c11feddfaeb8bdef",
+ "title": "Modify Array Data With Indexes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/multiple-identical-options-in-switch-statements",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244df",
+ "title": "Multiple Identical Options in Switch Statements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/multiply-two-decimals-with-javascript",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "bd7993c9c69feddfaeb7bdef",
+ "title": "Multiply Two Decimals with JavaScript"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/multiply-two-numbers-with-javascript",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "cf1231c1c11feddfaeb5bdef",
+ "title": "Multiply Two Numbers with JavaScript"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/nest-one-array-within-another-array",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "cf1111c1c11feddfaeb7bdef",
+ "title": "Nest one Array within Another Array"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/nesting-for-loops",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244e1",
+ "title": "Nesting For Loops"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/passing-values-to-functions-with-arguments",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244bd",
+ "title": "Passing Values to Functions with Arguments"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/practice-comparing-different-values",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "599a789b454f2bbd91a3ff4d",
+ "title": "Practice comparing different values"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/profile-lookup",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "5688e62ea601b2482ff8422b",
+ "title": "Profile Lookup"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/quoting-strings-with-single-quotes",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244b4",
+ "title": "Quoting Strings with Single Quotes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/record-collection",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244cf",
+ "title": "Record Collection"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/replace-loops-using-recursion",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "5cfa3679138e7d9595b9d9d4",
+ "title": "Replace Loops using Recursion"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/replacing-if-else-chains-with-switch",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244e0",
+ "title": "Replacing If Else Chains with Switch"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/return-a-value-from-a-function-with-return",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244c2",
+ "title": "Return a Value from a Function with Return"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/return-early-pattern-for-functions",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244c4",
+ "title": "Return Early Pattern for Functions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/returning-boolean-values-from-functions",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "5679ceb97cbaa8c51670a16b",
+ "title": "Returning Boolean Values from Functions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/selecting-from-many-options-with-switch-statements",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244dd",
+ "title": "Selecting from Many Options with Switch Statements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/shopping-list",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244bc",
+ "title": "Shopping List"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/stand-in-line",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244c6",
+ "title": "Stand in Line"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/store-multiple-values-in-one-variable-using-javascript-arrays",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "bd7993c9c69feddfaeb8bdef",
+ "title": "Store Multiple Values in one Variable using JavaScript Arrays"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/storing-values-with-the-assignment-operator",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244a8",
+ "title": "Storing Values with the Assignment Operator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/subtract-one-number-from-another-with-javascript",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "cf1111c1c11feddfaeb4bdef",
+ "title": "Subtract One Number from Another with JavaScript"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/testing-objects-for-properties",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "567af2437cbaa8c51670a16c",
+ "title": "Testing Objects for Properties"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/understand-string-immutability",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244ba",
+ "title": "Understand String Immutability"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/understanding-boolean-values",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "bd7123c9c441eddfaeb5bdef",
+ "title": "Understanding Boolean Values"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/understanding-case-sensitivity-in-variables",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244ab",
+ "title": "Understanding Case Sensitivity in Variables"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/understanding-undefined-value-returned-from-a-function",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "598e8944f009e646fc236146",
+ "title": "Understanding Undefined Value returned from a Function"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/understanding-uninitialized-variables",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244aa",
+ "title": "Understanding Uninitialized Variables"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/updating-object-properties",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56bbb991ad1ed5201cd392d1",
+ "title": "Updating Object Properties"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/use-bracket-notation-to-find-the-first-character-in-a-string",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "bd7123c9c549eddfaeb5bdef",
+ "title": "Use Bracket Notation to Find the First Character in a String"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/use-bracket-notation-to-find-the-last-character-in-a-string",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "bd7123c9c451eddfaeb5bdef",
+ "title": "Use Bracket Notation to Find the Last Character in a String"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/use-bracket-notation-to-find-the-nth-character-in-a-string",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "bd7123c9c450eddfaeb5bdef",
+ "title": "Use Bracket Notation to Find the Nth Character in a String"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/use-bracket-notation-to-find-the-nth-to-last-character-in-a-string",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "bd7123c9c452eddfaeb5bdef",
+ "title": "Use Bracket Notation to Find the Nth-to-Last Character in a String"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/use-conditional-logic-with-if-statements",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "cf1111c1c12feddfaeb3bdef",
+ "title": "Use Conditional Logic with If Statements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/use-multiple-conditional-ternary-operators",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "587d7b7e367417b2b2512b21",
+ "title": "Use Multiple Conditional (Ternary) Operators"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/use-recursion-to-create-a-countdown",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "5cd9a70215d3c4e65518328f",
+ "title": "Use Recursion to Create a Countdown"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/use-recursion-to-create-a-range-of-numbers",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "5cc0bd7a49b71cb96132e54c",
+ "title": "Use Recursion to Create a Range of Numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/use-the-conditional-ternary-operator",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "587d7b7e367417b2b2512b24",
+ "title": "Use the Conditional (Ternary) Operator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/use-the-parseint-function-with-a-radix",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "587d7b7e367417b2b2512b22",
+ "title": "Use the parseInt Function with a Radix"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/use-the-parseint-function",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "587d7b7e367417b2b2512b23",
+ "title": "Use the parseInt Function"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/using-objects-for-lookups",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244ca",
+ "title": "Using Objects for Lookups"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/word-blanks",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56533eb9ac21ba0edf2244bb",
+ "title": "Word Blanks"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/basic-javascript/write-reusable-javascript-with-functions",
+ "blockName": "Basic JavaScript"
+ },
+ "id": "56bbb991ad1ed5201cd392cf",
+ "title": "Write Reusable JavaScript with Functions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/debugging/catch-arguments-passed-in-the-wrong-order-when-calling-a-function",
+ "blockName": "Debugging"
+ },
+ "id": "587d7b85367417b2b2512b3a",
+ "title": "Catch Arguments Passed in the Wrong Order When Calling a Function"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/debugging/catch-missing-open-and-closing-parenthesis-after-a-function-call",
+ "blockName": "Debugging"
+ },
+ "id": "587d7b85367417b2b2512b39",
+ "title": "Catch Missing Open and Closing Parenthesis After a Function Call"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/debugging/catch-misspelled-variable-and-function-names",
+ "blockName": "Debugging"
+ },
+ "id": "587d7b84367417b2b2512b35",
+ "title": "Catch Misspelled Variable and Function Names"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/debugging/catch-mixed-usage-of-single-and-double-quotes",
+ "blockName": "Debugging"
+ },
+ "id": "587d7b84367417b2b2512b37",
+ "title": "Catch Mixed Usage of Single and Double Quotes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/debugging/catch-off-by-one-errors-when-using-indexing",
+ "blockName": "Debugging"
+ },
+ "id": "587d7b86367417b2b2512b3b",
+ "title": "Catch Off By One Errors When Using Indexing"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/debugging/catch-unclosed-parentheses-brackets-braces-and-quotes",
+ "blockName": "Debugging"
+ },
+ "id": "587d7b84367417b2b2512b36",
+ "title": "Catch Unclosed Parentheses, Brackets, Braces and Quotes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/debugging/catch-use-of-assignment-operator-instead-of-equality-operator",
+ "blockName": "Debugging"
+ },
+ "id": "587d7b85367417b2b2512b38",
+ "title": "Catch Use of Assignment Operator Instead of Equality Operator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/debugging/prevent-infinite-loops-with-a-valid-terminal-condition",
+ "blockName": "Debugging"
+ },
+ "id": "587d7b86367417b2b2512b3d",
+ "title": "Prevent Infinite Loops with a Valid Terminal Condition"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/debugging/understanding-the-differences-between-the-freecodecamp-and-browser-console",
+ "blockName": "Debugging"
+ },
+ "id": "587d7b83367417b2b2512b37",
+ "title": "Understanding the Differences between the freeCodeCamp and Browser Console"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/debugging/use-caution-when-reinitializing-variables-inside-a-loop",
+ "blockName": "Debugging"
+ },
+ "id": "587d7b86367417b2b2512b3c",
+ "title": "Use Caution When Reinitializing Variables Inside a Loop"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/debugging/use-the-javascript-console-to-check-the-value-of-a-variable",
+ "blockName": "Debugging"
+ },
+ "id": "587d7b83367417b2b2512b33",
+ "title": "Use the JavaScript Console to Check the Value of a Variable"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/debugging/use-typeof-to-check-the-type-of-a-variable",
+ "blockName": "Debugging"
+ },
+ "id": "587d7b84367417b2b2512b34",
+ "title": "Use typeof to Check the Type of a Variable"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/compare-scopes-of-the-var-and-let-keywords",
+ "blockName": "ES6"
+ },
+ "id": "587d7b87367417b2b2512b40",
+ "title": "Compare Scopes of the var and let Keywords"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/complete-a-promise-with-resolve-and-reject",
+ "blockName": "ES6"
+ },
+ "id": "5cdafbc32913098997531680",
+ "title": "Complete a Promise with resolve and reject"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/create-a-javascript-promise",
+ "blockName": "ES6"
+ },
+ "id": "5cdafbb0291309899753167f",
+ "title": "Create a JavaScript Promise"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/create-a-module-script",
+ "blockName": "ES6"
+ },
+ "id": "5cddbfd622f1a59093ec611d",
+ "title": "Create a Module Script"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/create-an-export-fallback-with-export-default",
+ "blockName": "ES6"
+ },
+ "id": "587d7b8c367417b2b2512b58",
+ "title": "Create an Export Fallback with export default"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/create-strings-using-template-literals",
+ "blockName": "ES6"
+ },
+ "id": "587d7b8a367417b2b2512b4e",
+ "title": "Create Strings using Template Literals"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/handle-a-fulfilled-promise-with-then",
+ "blockName": "ES6"
+ },
+ "id": "5cdafbd72913098997531681",
+ "title": "Handle a Fulfilled Promise with then"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/handle-a-rejected-promise-with-catch",
+ "blockName": "ES6"
+ },
+ "id": "5cdafbe72913098997531682",
+ "title": "Handle a Rejected Promise with catch"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/import-a-default-export",
+ "blockName": "ES6"
+ },
+ "id": "587d7b8d367417b2b2512b59",
+ "title": "Import a Default Export"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/mutate-an-array-declared-with-const",
+ "blockName": "ES6"
+ },
+ "id": "587d7b87367417b2b2512b42",
+ "title": "Mutate an Array Declared with const"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/prevent-object-mutation",
+ "blockName": "ES6"
+ },
+ "id": "598f48a36c8c40764b4e52b3",
+ "title": "Prevent Object Mutation"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/reuse-javascript-code-using-import",
+ "blockName": "ES6"
+ },
+ "id": "587d7b8c367417b2b2512b55",
+ "title": "Reuse JavaScript Code Using import"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/set-default-parameters-for-your-functions",
+ "blockName": "ES6"
+ },
+ "id": "587d7b88367417b2b2512b46",
+ "title": "Set Default Parameters for Your Functions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/use--to-import-everything-from-a-file",
+ "blockName": "ES6"
+ },
+ "id": "587d7b8c367417b2b2512b57",
+ "title": "Use * to Import Everything from a File"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/use-arrow-functions-to-write-concise-anonymous-functions",
+ "blockName": "ES6"
+ },
+ "id": "587d7b87367417b2b2512b43",
+ "title": "Use Arrow Functions to Write Concise Anonymous Functions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/use-class-syntax-to-define-a-constructor-function",
+ "blockName": "ES6"
+ },
+ "id": "587d7b8b367417b2b2512b53",
+ "title": "Use class Syntax to Define a Constructor Function"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/use-destructuring-assignment-to-assign-variables-from-arrays",
+ "blockName": "ES6"
+ },
+ "id": "587d7b89367417b2b2512b4b",
+ "title": "Use Destructuring Assignment to Assign Variables from Arrays"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/use-destructuring-assignment-to-assign-variables-from-nested-objects",
+ "blockName": "ES6"
+ },
+ "id": "587d7b89367417b2b2512b4a",
+ "title": "Use Destructuring Assignment to Assign Variables from Nested Objects"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/use-destructuring-assignment-to-assign-variables-from-objects",
+ "blockName": "ES6"
+ },
+ "id": "587d7b89367417b2b2512b49",
+ "title": "Use Destructuring Assignment to Assign Variables from Objects"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/use-destructuring-assignment-to-extract-values-from-objects",
+ "blockName": "ES6"
+ },
+ "id": "5cfa550e84205a357704ccb6",
+ "title": "Use Destructuring Assignment to Extract Values from Objects"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/use-destructuring-assignment-to-pass-an-object-as-a-functions-parameters",
+ "blockName": "ES6"
+ },
+ "id": "587d7b8a367417b2b2512b4d",
+ "title": "Use Destructuring Assignment to Pass an Object as a Function's Parameters"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/use-destructuring-assignment-with-the-rest-parameter-to-reassign-array-elements",
+ "blockName": "ES6"
+ },
+ "id": "587d7b8a367417b2b2512b4c",
+ "title": "Use Destructuring Assignment with the Rest Parameter to Reassign Array Elements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/use-export-to-share-a-code-block",
+ "blockName": "ES6"
+ },
+ "id": "587d7b8c367417b2b2512b56",
+ "title": "Use export to Share a Code Block"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/use-getters-and-setters-to-control-access-to-an-object",
+ "blockName": "ES6"
+ },
+ "id": "587d7b8c367417b2b2512b54",
+ "title": "Use getters and setters to Control Access to an Object"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/use-the-rest-parameter-with-function-parameters",
+ "blockName": "ES6"
+ },
+ "id": "587d7b88367417b2b2512b47",
+ "title": "Use the Rest Parameter with Function Parameters"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/use-the-spread-operator-to-evaluate-arrays-in-place",
+ "blockName": "ES6"
+ },
+ "id": "587d7b89367417b2b2512b48",
+ "title": "Use the Spread Operator to Evaluate Arrays In-Place"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/write-arrow-functions-with-parameters",
+ "blockName": "ES6"
+ },
+ "id": "587d7b88367417b2b2512b44",
+ "title": "Write Arrow Functions with Parameters"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/write-concise-declarative-functions-with-es6",
+ "blockName": "ES6"
+ },
+ "id": "587d7b8b367417b2b2512b50",
+ "title": "Write Concise Declarative Functions with ES6"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/es6/write-concise-object-literal-declarations-using-object-property-shorthand",
+ "blockName": "ES6"
+ },
+ "id": "587d7b8a367417b2b2512b4f",
+ "title": "Write Concise Object Literal Declarations Using Object Property Shorthand"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/functional-programming/add-elements-to-the-end-of-an-array-using-concat-instead-of-push",
+ "blockName": "Functional Programming"
+ },
+ "id": "587d7da9367417b2b2512b67",
+ "title": "Add Elements to the End of an Array Using concat Instead of push"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/functional-programming/apply-functional-programming-to-convert-strings-to-url-slugs",
+ "blockName": "Functional Programming"
+ },
+ "id": "587d7dab367417b2b2512b6d",
+ "title": "Apply Functional Programming to Convert Strings to URL Slugs"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/functional-programming/avoid-mutations-and-side-effects-using-functional-programming",
+ "blockName": "Functional Programming"
+ },
+ "id": "587d7b8e367417b2b2512b5e",
+ "title": "Avoid Mutations and Side Effects Using Functional Programming"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/functional-programming/combine-an-array-into-a-string-using-the-join-method",
+ "blockName": "Functional Programming"
+ },
+ "id": "587d7daa367417b2b2512b6c",
+ "title": "Combine an Array into a String Using the join Method"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/functional-programming/combine-two-arrays-using-the-concat-method",
+ "blockName": "Functional Programming"
+ },
+ "id": "587d7da9367417b2b2512b66",
+ "title": "Combine Two Arrays Using the concat Method"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/functional-programming/implement-map-on-a-prototype",
+ "blockName": "Functional Programming"
+ },
+ "id": "587d7b8f367417b2b2512b62",
+ "title": "Implement map on a Prototype"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/functional-programming/implement-the-filter-method-on-a-prototype",
+ "blockName": "Functional Programming"
+ },
+ "id": "587d7b8f367417b2b2512b64",
+ "title": "Implement the filter Method on a Prototype"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/functional-programming/introduction-to-currying-and-partial-application",
+ "blockName": "Functional Programming"
+ },
+ "id": "587d7dab367417b2b2512b70",
+ "title": "Introduction to Currying and Partial Application"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/functional-programming/learn-about-functional-programming",
+ "blockName": "Functional Programming"
+ },
+ "id": "587d7b8d367417b2b2512b5b",
+ "title": "Learn About Functional Programming"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/functional-programming/pass-arguments-to-avoid-external-dependence-in-a-function",
+ "blockName": "Functional Programming"
+ },
+ "id": "587d7b8e367417b2b2512b5f",
+ "title": "Pass Arguments to Avoid External Dependence in a Function"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/functional-programming/refactor-global-variables-out-of-functions",
+ "blockName": "Functional Programming"
+ },
+ "id": "587d7b8f367417b2b2512b60",
+ "title": "Refactor Global Variables Out of Functions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/functional-programming/remove-elements-from-an-array-using-slice-instead-of-splice",
+ "blockName": "Functional Programming"
+ },
+ "id": "9d7123c8c441eeafaeb5bdef",
+ "title": "Remove Elements from an Array Using slice Instead of splice"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/functional-programming/return-a-sorted-array-without-changing-the-original-array",
+ "blockName": "Functional Programming"
+ },
+ "id": "587d7da9367417b2b2512b6a",
+ "title": "Return a Sorted Array Without Changing the Original Array"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/functional-programming/return-part-of-an-array-using-the-slice-method",
+ "blockName": "Functional Programming"
+ },
+ "id": "587d7b90367417b2b2512b65",
+ "title": "Return Part of an Array Using the slice Method"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/functional-programming/sort-an-array-alphabetically-using-the-sort-method",
+ "blockName": "Functional Programming"
+ },
+ "id": "587d7da9367417b2b2512b69",
+ "title": "Sort an Array Alphabetically using the sort Method"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/functional-programming/split-a-string-into-an-array-using-the-split-method",
+ "blockName": "Functional Programming"
+ },
+ "id": "587d7daa367417b2b2512b6b",
+ "title": "Split a String into an Array Using the split Method"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/functional-programming/understand-functional-programming-terminology",
+ "blockName": "Functional Programming"
+ },
+ "id": "587d7b8e367417b2b2512b5c",
+ "title": "Understand Functional Programming Terminology"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/functional-programming/understand-the-hazards-of-using-imperative-code",
+ "blockName": "Functional Programming"
+ },
+ "id": "587d7b8e367417b2b2512b5d",
+ "title": "Understand the Hazards of Using Imperative Code"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/functional-programming/use-higher-order-functions-map-filter-or-reduce-to-solve-a-complex-problem",
+ "blockName": "Functional Programming"
+ },
+ "id": "587d7b88367417b2b2512b45",
+ "title": "Use Higher-Order Functions map, filter, or reduce to Solve a Complex Problem"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/functional-programming/use-the-every-method-to-check-that-every-element-in-an-array-meets-a-criteria",
+ "blockName": "Functional Programming"
+ },
+ "id": "587d7dab367417b2b2512b6e",
+ "title": "Use the every Method to Check that Every Element in an Array Meets a Criteria"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/functional-programming/use-the-filter-method-to-extract-data-from-an-array",
+ "blockName": "Functional Programming"
+ },
+ "id": "587d7b8f367417b2b2512b63",
+ "title": "Use the filter Method to Extract Data from an Array"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/functional-programming/use-the-map-method-to-extract-data-from-an-array",
+ "blockName": "Functional Programming"
+ },
+ "id": "587d7b8f367417b2b2512b61",
+ "title": "Use the map Method to Extract Data from an Array"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/functional-programming/use-the-reduce-method-to-analyze-data",
+ "blockName": "Functional Programming"
+ },
+ "id": "587d7da9367417b2b2512b68",
+ "title": "Use the reduce Method to Analyze Data"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/functional-programming/use-the-some-method-to-check-that-any-elements-in-an-array-meet-a-criteria",
+ "blockName": "Functional Programming"
+ },
+ "id": "587d7dab367417b2b2512b6f",
+ "title": "Use the some Method to Check that Any Elements in an Array Meet a Criteria"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/arguments-optional",
+ "blockName": "Intermediate Algorithm Scripting"
+ },
+ "id": "a97fd23d9b809dac9921074f",
+ "title": "Arguments Optional"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/binary-agents",
+ "blockName": "Intermediate Algorithm Scripting"
+ },
+ "id": "a8d97bd4c764e91f9d2bda01",
+ "title": "Binary Agents"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/convert-html-entities",
+ "blockName": "Intermediate Algorithm Scripting"
+ },
+ "id": "a6b0bb188d873cb2c8729495",
+ "title": "Convert HTML Entities"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/diff-two-arrays",
+ "blockName": "Intermediate Algorithm Scripting"
+ },
+ "id": "a5de63ebea8dbee56860f4f2",
+ "title": "Diff Two Arrays"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/dna-pairing",
+ "blockName": "Intermediate Algorithm Scripting"
+ },
+ "id": "afd15382cdfb22c9efe8b7de",
+ "title": "DNA Pairing"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/drop-it",
+ "blockName": "Intermediate Algorithm Scripting"
+ },
+ "id": "a5deed1811a43193f9f1c841",
+ "title": "Drop it"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/everything-be-true",
+ "blockName": "Intermediate Algorithm Scripting"
+ },
+ "id": "a10d2431ad0c6a099a4b8b52",
+ "title": "Everything Be True"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/make-a-person",
+ "blockName": "Intermediate Algorithm Scripting"
+ },
+ "id": "a2f1d72d9b908d0bd72bb9f6",
+ "title": "Make a Person"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/map-the-debris",
+ "blockName": "Intermediate Algorithm Scripting"
+ },
+ "id": "af4afb223120f7348cdfc9fd",
+ "title": "Map the Debris"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/missing-letters",
+ "blockName": "Intermediate Algorithm Scripting"
+ },
+ "id": "af7588ade1100bde429baf20",
+ "title": "Missing letters"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/pig-latin",
+ "blockName": "Intermediate Algorithm Scripting"
+ },
+ "id": "aa7697ea2477d1316795783b",
+ "title": "Pig Latin"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/search-and-replace",
+ "blockName": "Intermediate Algorithm Scripting"
+ },
+ "id": "a0b5010f579e69b815e7c5d6",
+ "title": "Search and Replace"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/seek-and-destroy",
+ "blockName": "Intermediate Algorithm Scripting"
+ },
+ "id": "a39963a4c10bc8b4d4f06d7e",
+ "title": "Seek and Destroy"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/smallest-common-multiple",
+ "blockName": "Intermediate Algorithm Scripting"
+ },
+ "id": "ae9defd7acaf69703ab432ea",
+ "title": "Smallest Common Multiple"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/sorted-union",
+ "blockName": "Intermediate Algorithm Scripting"
+ },
+ "id": "a105e963526e7de52b219be9",
+ "title": "Sorted Union"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/spinal-tap-case",
+ "blockName": "Intermediate Algorithm Scripting"
+ },
+ "id": "a103376db3ba46b2d50db289",
+ "title": "Spinal Tap Case"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/steamroller",
+ "blockName": "Intermediate Algorithm Scripting"
+ },
+ "id": "ab306dbdcc907c7ddfc30830",
+ "title": "Steamroller"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/sum-all-numbers-in-a-range",
+ "blockName": "Intermediate Algorithm Scripting"
+ },
+ "id": "a3566b1109230028080c9345",
+ "title": "Sum All Numbers in a Range"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/sum-all-odd-fibonacci-numbers",
+ "blockName": "Intermediate Algorithm Scripting"
+ },
+ "id": "a5229172f011153519423690",
+ "title": "Sum All Odd Fibonacci Numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/sum-all-primes",
+ "blockName": "Intermediate Algorithm Scripting"
+ },
+ "id": "a3bfc1673c0526e06d3ac698",
+ "title": "Sum All Primes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/wherefore-art-thou",
+ "blockName": "Intermediate Algorithm Scripting"
+ },
+ "id": "a8e512fbe388ac2f9198f0fa",
+ "title": "Wherefore art thou"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/caesars-cipher",
+ "blockName": "JavaScript Algorithms and Data Structures Projects"
+ },
+ "id": "56533eb9ac21ba0edf2244e2",
+ "title": "Caesars Cipher"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/cash-register",
+ "blockName": "JavaScript Algorithms and Data Structures Projects"
+ },
+ "id": "aa2e6f85cab2ab736c9a9b24",
+ "title": "Cash Register"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/palindrome-checker",
+ "blockName": "JavaScript Algorithms and Data Structures Projects"
+ },
+ "id": "aaa48de84e1ecc7c742e1124",
+ "title": "Palindrome Checker"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/roman-numeral-converter",
+ "blockName": "JavaScript Algorithms and Data Structures Projects"
+ },
+ "id": "a7f4d8f2483413a6ce226cac",
+ "title": "Roman Numeral Converter"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/telephone-number-validator",
+ "blockName": "JavaScript Algorithms and Data Structures Projects"
+ },
+ "id": "aff0395860f5d3034dc0bfc9",
+ "title": "Telephone Number Validator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/add-methods-after-inheritance",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7db1367417b2b2512b87",
+ "title": "Add Methods After Inheritance"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/change-the-prototype-to-a-new-object",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7daf367417b2b2512b7f",
+ "title": "Change the Prototype to a New Object"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/create-a-basic-javascript-object",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7dac367417b2b2512b73",
+ "title": "Create a Basic JavaScript Object"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/create-a-method-on-an-object",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7dad367417b2b2512b75",
+ "title": "Create a Method on an Object"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/define-a-constructor-function",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7dad367417b2b2512b77",
+ "title": "Define a Constructor Function"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/extend-constructors-to-receive-arguments",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7dae367417b2b2512b79",
+ "title": "Extend Constructors to Receive Arguments"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/inherit-behaviors-from-a-supertype",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7db0367417b2b2512b84",
+ "title": "Inherit Behaviors from a Supertype"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/iterate-over-all-properties",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7daf367417b2b2512b7d",
+ "title": "Iterate Over All Properties"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/make-code-more-reusable-with-the-this-keyword",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7dad367417b2b2512b76",
+ "title": "Make Code More Reusable with the this Keyword"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/override-inherited-methods",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7db1367417b2b2512b88",
+ "title": "Override Inherited Methods"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/remember-to-set-the-constructor-property-when-changing-the-prototype",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7daf367417b2b2512b80",
+ "title": "Remember to Set the Constructor Property when Changing the Prototype"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/reset-an-inherited-constructor-property",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7db1367417b2b2512b86",
+ "title": "Reset an Inherited Constructor Property"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/set-the-childs-prototype-to-an-instance-of-the-parent",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7db1367417b2b2512b85",
+ "title": "Set the Child's Prototype to an Instance of the Parent"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/understand-own-properties",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7dae367417b2b2512b7b",
+ "title": "Understand Own Properties"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/understand-the-constructor-property",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7daf367417b2b2512b7e",
+ "title": "Understand the Constructor Property"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/understand-the-immediately-invoked-function-expression-iife",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7db2367417b2b2512b8b",
+ "title": "Understand the Immediately Invoked Function Expression (IIFE)"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/understand-the-prototype-chain",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7db0367417b2b2512b82",
+ "title": "Understand the Prototype Chain"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/understand-where-an-objects-prototype-comes-from",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7db0367417b2b2512b81",
+ "title": "Understand Where an Object’s Prototype Comes From"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/use-a-constructor-to-create-objects",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7dad367417b2b2512b78",
+ "title": "Use a Constructor to Create Objects"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/use-a-mixin-to-add-common-behavior-between-unrelated-objects",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7db2367417b2b2512b89",
+ "title": "Use a Mixin to Add Common Behavior Between Unrelated Objects"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/use-an-iife-to-create-a-module",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7db2367417b2b2512b8c",
+ "title": "Use an IIFE to Create a Module"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/use-closure-to-protect-properties-within-an-object-from-being-modified-externally",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7db2367417b2b2512b8a",
+ "title": "Use Closure to Protect Properties Within an Object from Being Modified Externally"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/use-dot-notation-to-access-the-properties-of-an-object",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7dac367417b2b2512b74",
+ "title": "Use Dot Notation to Access the Properties of an Object"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/use-inheritance-so-you-dont-repeat-yourself",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7db0367417b2b2512b83",
+ "title": "Use Inheritance So You Don't Repeat Yourself"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/use-prototype-properties-to-reduce-duplicate-code",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7dae367417b2b2512b7c",
+ "title": "Use Prototype Properties to Reduce Duplicate Code"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/object-oriented-programming/verify-an-objects-constructor-with-instanceof",
+ "blockName": "Object Oriented Programming"
+ },
+ "id": "587d7dae367417b2b2512b7a",
+ "title": "Verify an Object's Constructor with instanceof"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/check-for-all-or-none",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7dba367417b2b2512ba8",
+ "title": "Check for All or None"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/check-for-mixed-grouping-of-characters",
+ "blockName": "Regular Expressions"
+ },
+ "id": "5c3dda8b4d8df89bea71600f",
+ "title": "Check For Mixed Grouping of Characters"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/extract-matches",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db4367417b2b2512b92",
+ "title": "Extract Matches"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/find-characters-with-lazy-matching",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db6367417b2b2512b9b",
+ "title": "Find Characters with Lazy Matching"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/find-more-than-the-first-match",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db4367417b2b2512b93",
+ "title": "Find More Than the First Match"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/find-one-or-more-criminals-in-a-hunt",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db7367417b2b2512b9c",
+ "title": "Find One or More Criminals in a Hunt"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/ignore-case-while-matching",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db4367417b2b2512b91",
+ "title": "Ignore Case While Matching"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/match-a-literal-string-with-different-possibilities",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db4367417b2b2512b90",
+ "title": "Match a Literal String with Different Possibilities"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/match-all-letters-and-numbers",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db7367417b2b2512b9f",
+ "title": "Match All Letters and Numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/match-all-non-numbers",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db8367417b2b2512ba1",
+ "title": "Match All Non-Numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/match-all-numbers",
+ "blockName": "Regular Expressions"
+ },
+ "id": "5d712346c441eddfaeb5bdef",
+ "title": "Match All Numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/match-anything-with-wildcard-period",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db5367417b2b2512b94",
+ "title": "Match Anything with Wildcard Period"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/match-beginning-string-patterns",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db7367417b2b2512b9d",
+ "title": "Match Beginning String Patterns"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/match-characters-that-occur-one-or-more-times",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db6367417b2b2512b99",
+ "title": "Match Characters that Occur One or More Times"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/match-characters-that-occur-zero-or-more-times",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db6367417b2b2512b9a",
+ "title": "Match Characters that Occur Zero or More Times"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/match-ending-string-patterns",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db7367417b2b2512b9e",
+ "title": "Match Ending String Patterns"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/match-everything-but-letters-and-numbers",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db8367417b2b2512ba0",
+ "title": "Match Everything But Letters and Numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/match-letters-of-the-alphabet",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db5367417b2b2512b96",
+ "title": "Match Letters of the Alphabet"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/match-literal-strings",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db3367417b2b2512b8f",
+ "title": "Match Literal Strings"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/match-non-whitespace-characters",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db9367417b2b2512ba4",
+ "title": "Match Non-Whitespace Characters"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/match-numbers-and-letters-of-the-alphabet",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db5367417b2b2512b97",
+ "title": "Match Numbers and Letters of the Alphabet"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/match-single-character-with-multiple-possibilities",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db5367417b2b2512b95",
+ "title": "Match Single Character with Multiple Possibilities"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/match-single-characters-not-specified",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db6367417b2b2512b98",
+ "title": "Match Single Characters Not Specified"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/match-whitespace",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db8367417b2b2512ba3",
+ "title": "Match Whitespace"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/positive-and-negative-lookahead",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7dba367417b2b2512ba9",
+ "title": "Positive and Negative Lookahead"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/remove-whitespace-from-start-and-end",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7dbb367417b2b2512bac",
+ "title": "Remove Whitespace from Start and End"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/restrict-possible-usernames",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db8367417b2b2512ba2",
+ "title": "Restrict Possible Usernames"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/reuse-patterns-using-capture-groups",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7dbb367417b2b2512baa",
+ "title": "Reuse Patterns Using Capture Groups"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/specify-exact-number-of-matches",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db9367417b2b2512ba7",
+ "title": "Specify Exact Number of Matches"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/specify-only-the-lower-number-of-matches",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db9367417b2b2512ba6",
+ "title": "Specify Only the Lower Number of Matches"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/specify-upper-and-lower-number-of-matches",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db9367417b2b2512ba5",
+ "title": "Specify Upper and Lower Number of Matches"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/use-capture-groups-to-search-and-replace",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7dbb367417b2b2512bab",
+ "title": "Use Capture Groups to Search and Replace"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/javascript-algorithms-and-data-structures/regular-expressions/using-the-test-method",
+ "blockName": "Regular Expressions"
+ },
+ "id": "587d7db3367417b2b2512b8e",
+ "title": "Using the Test Method"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/add-elements-within-your-bootstrap-wells",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348bd9aec908849",
+ "title": "Add Elements within Your Bootstrap Wells"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/add-font-awesome-icons-to-all-of-our-buttons",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348bd9aedc08845",
+ "title": "Add Font Awesome Icons to all of our Buttons"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/add-font-awesome-icons-to-our-buttons",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348bd9aedd08845",
+ "title": "Add Font Awesome Icons to our Buttons"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/add-id-attributes-to-bootstrap-elements",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348bd9aec908853",
+ "title": "Add id Attributes to Bootstrap Elements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/apply-the-default-bootstrap-button-style",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348bd9aec908850",
+ "title": "Apply the Default Bootstrap Button Style"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/call-out-optional-actions-with-btn-info",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348cd8acef08813",
+ "title": "Call out Optional Actions with btn-info"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/center-text-with-bootstrap",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348bd8acde08812",
+ "title": "Center Text with Bootstrap"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/create-a-block-element-bootstrap-button",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348cd8acef08812",
+ "title": "Create a Block Element Bootstrap Button"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/create-a-bootstrap-button",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348cd8acdf08812",
+ "title": "Create a Bootstrap Button"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/create-a-bootstrap-headline",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348bd9aec908846",
+ "title": "Create a Bootstrap Headline"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/create-a-bootstrap-row",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348bd9bec908846",
+ "title": "Create a Bootstrap Row"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/create-a-class-to-target-with-jquery-selectors",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348bd9aec908852",
+ "title": "Create a Class to Target with jQuery Selectors"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/create-a-custom-heading",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348bd9aede08845",
+ "title": "Create a Custom Heading"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/create-bootstrap-wells",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348bd9aec908848",
+ "title": "Create Bootstrap Wells"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/ditch-custom-css-for-bootstrap",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1347bd9aedf08845",
+ "title": "Ditch Custom CSS for Bootstrap"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/give-each-element-a-unique-id",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348bd9aec908855",
+ "title": "Give Each Element a Unique id"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/house-our-page-within-a-bootstrap-container-fluid-div",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348bd9aec908746",
+ "title": "House our page within a Bootstrap container-fluid div"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/label-bootstrap-buttons",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348bd9aec908856",
+ "title": "Label Bootstrap Buttons"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/label-bootstrap-wells",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348bd9aec908854",
+ "title": "Label Bootstrap Wells"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/line-up-form-elements-responsively-with-bootstrap",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348bd9aec908845",
+ "title": "Line up Form Elements Responsively with Bootstrap"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/make-images-mobile-responsive",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348bd9acde08812",
+ "title": "Make Images Mobile Responsive"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/responsively-style-checkboxes",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348bd9aeda08845",
+ "title": "Responsively Style Checkboxes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/responsively-style-radio-buttons",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348bd9aedb08845",
+ "title": "Responsively Style Radio Buttons"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/split-your-bootstrap-row",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348bd9aec908847",
+ "title": "Split Your Bootstrap Row"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/style-text-inputs-as-form-controls",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348bd9aed908845",
+ "title": "Style Text Inputs as Form Controls"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/taste-the-bootstrap-button-color-rainbow",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348cd8acef08811",
+ "title": "Taste the Bootstrap Button Color Rainbow"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/use-a-span-to-target-inline-elements",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348bd9aedf08845",
+ "title": "Use a span to Target Inline Elements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/use-comments-to-clarify-code",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348bd9aec908857",
+ "title": "Use Comments to Clarify Code"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/use-responsive-design-with-bootstrap-fluid-containers",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348bd9acde08712",
+ "title": "Use Responsive Design with Bootstrap Fluid Containers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/use-the-bootstrap-grid-to-put-elements-side-by-side",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad88fee1348ce8acef08815",
+ "title": "Use the Bootstrap Grid to Put Elements Side By Side"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/bootstrap/warn-your-users-of-a-dangerous-action-with-btn-danger",
+ "blockName": "Bootstrap"
+ },
+ "id": "bad87fee1348ce8acef08814",
+ "title": "Warn Your Users of a Dangerous Action with btn-danger"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/front-end-development-libraries-projects/build-a-25--5-clock",
+ "blockName": "Front End Development Libraries Projects"
+ },
+ "id": "bd7158d8c442eddfaeb5bd0f",
+ "title": "Build a 25 + 5 Clock"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/front-end-development-libraries-projects/build-a-drum-machine",
+ "blockName": "Front End Development Libraries Projects"
+ },
+ "id": "587d7dbc367417b2b2512bae",
+ "title": "Build a Drum Machine"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/front-end-development-libraries-projects/build-a-javascript-calculator",
+ "blockName": "Front End Development Libraries Projects"
+ },
+ "id": "bd7158d8c442eddfaeb5bd17",
+ "title": "Build a JavaScript Calculator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/front-end-development-libraries-projects/build-a-markdown-previewer",
+ "blockName": "Front End Development Libraries Projects"
+ },
+ "id": "bd7157d8c242eddfaeb5bd13",
+ "title": "Build a Markdown Previewer"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/front-end-development-libraries-projects/build-a-random-quote-machine",
+ "blockName": "Front End Development Libraries Projects"
+ },
+ "id": "bd7158d8c442eddfaeb5bd13",
+ "title": "Build a Random Quote Machine"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/jquery/change-text-inside-an-element-using-jquery",
+ "blockName": "jQuery"
+ },
+ "id": "564944c91be2204b269d51e3",
+ "title": "Change Text Inside an Element Using jQuery"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/jquery/change-the-css-of-an-element-using-jquery",
+ "blockName": "jQuery"
+ },
+ "id": "bad87fee1348bd9aed908826",
+ "title": "Change the CSS of an Element Using jQuery"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/jquery/clone-an-element-using-jquery",
+ "blockName": "jQuery"
+ },
+ "id": "bad87fee1348bd9aed508826",
+ "title": "Clone an Element Using jQuery"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/jquery/delete-your-jquery-functions",
+ "blockName": "jQuery"
+ },
+ "id": "bad87fee1348bd9aeda08726",
+ "title": "Delete Your jQuery Functions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/jquery/disable-an-element-using-jquery",
+ "blockName": "jQuery"
+ },
+ "id": "bad87fee1348bd9aed808826",
+ "title": "Disable an Element Using jQuery"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/jquery/learn-how-script-tags-and-document-ready-work",
+ "blockName": "jQuery"
+ },
+ "id": "bad87fee1348bd9acdd08826",
+ "title": "Learn How Script Tags and Document Ready Work"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/jquery/remove-an-element-using-jquery",
+ "blockName": "jQuery"
+ },
+ "id": "bad87fee1348bd9aed708826",
+ "title": "Remove an Element Using jQuery"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/jquery/remove-classes-from-an-element-with-jquery",
+ "blockName": "jQuery"
+ },
+ "id": "bad87fee1348bd9aed918626",
+ "title": "Remove Classes from an Element with jQuery"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/jquery/target-a-specific-child-of-an-element-using-jquery",
+ "blockName": "jQuery"
+ },
+ "id": "bad87fee1348bd9aed108826",
+ "title": "Target a Specific Child of an Element Using jQuery"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/jquery/target-elements-by-class-using-jquery",
+ "blockName": "jQuery"
+ },
+ "id": "bad87fee1348bd9aedc08826",
+ "title": "Target Elements by Class Using jQuery"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/jquery/target-elements-by-id-using-jquery",
+ "blockName": "jQuery"
+ },
+ "id": "bad87fee1348bd9aeda08826",
+ "title": "Target Elements by id Using jQuery"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/jquery/target-even-elements-using-jquery",
+ "blockName": "jQuery"
+ },
+ "id": "bad87fee1348bd9aed008826",
+ "title": "Target Even Elements Using jQuery"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/jquery/target-html-elements-with-selectors-using-jquery",
+ "blockName": "jQuery"
+ },
+ "id": "bad87fee1348bd9bedc08826",
+ "title": "Target HTML Elements with Selectors Using jQuery"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/jquery/target-the-children-of-an-element-using-jquery",
+ "blockName": "jQuery"
+ },
+ "id": "bad87fee1348bd9aed208826",
+ "title": "Target the Children of an Element Using jQuery"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/jquery/target-the-parent-of-an-element-using-jquery",
+ "blockName": "jQuery"
+ },
+ "id": "bad87fee1348bd9aed308826",
+ "title": "Target the Parent of an Element Using jQuery"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/jquery/target-the-same-element-with-multiple-jquery-selectors",
+ "blockName": "jQuery"
+ },
+ "id": "bad87fee1348bd9aed908626",
+ "title": "Target the Same Element with Multiple jQuery Selectors"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/jquery/use-appendto-to-move-elements-with-jquery",
+ "blockName": "jQuery"
+ },
+ "id": "bad87fee1348bd9aed608826",
+ "title": "Use appendTo to Move Elements with jQuery"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/jquery/use-jquery-to-modify-the-entire-page",
+ "blockName": "jQuery"
+ },
+ "id": "bad87fee1348bd9aecb08826",
+ "title": "Use jQuery to Modify the Entire Page"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/access-props-using-this-props",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d403616e",
+ "title": "Access Props Using this.props"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/add-comments-in-jsx",
+ "blockName": "React"
+ },
+ "id": "5a24bbe0dba28a8d3cbd4c5e",
+ "title": "Add Comments in JSX"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/add-event-listeners",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d403617e",
+ "title": "Add Event Listeners"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/add-inline-styles-in-react",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036182",
+ "title": "Add Inline Styles in React"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/bind-this-to-a-class-method",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036174",
+ "title": "Bind 'this' to a Class Method"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/change-inline-css-conditionally-based-on-component-state",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036189",
+ "title": "Change Inline CSS Conditionally Based on Component State"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/compose-react-components",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036166",
+ "title": "Compose React Components"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/create-a-complex-jsx-element",
+ "blockName": "React"
+ },
+ "id": "5a24bbe0dba28a8d3cbd4c5d",
+ "title": "Create a Complex JSX Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/create-a-component-with-composition",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036164",
+ "title": "Create a Component with Composition"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/create-a-controlled-form",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036179",
+ "title": "Create a Controlled Form"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/create-a-controlled-input",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036178",
+ "title": "Create a Controlled Input"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/create-a-react-component",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036163",
+ "title": "Create a React Component"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/create-a-simple-jsx-element",
+ "blockName": "React"
+ },
+ "id": "587d7dbc367417b2b2512bb1",
+ "title": "Create a Simple JSX Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/create-a-stateful-component",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036170",
+ "title": "Create a Stateful Component"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/create-a-stateless-functional-component",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036162",
+ "title": "Create a Stateless Functional Component"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/define-an-html-class-in-jsx",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036160",
+ "title": "Define an HTML Class in JSX"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/give-sibling-elements-a-unique-key-attribute",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d403618b",
+ "title": "Give Sibling Elements a Unique Key Attribute"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/introducing-inline-styles",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036181",
+ "title": "Introducing Inline Styles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/learn-about-self-closing-jsx-tags",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036161",
+ "title": "Learn About Self-Closing JSX Tags"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/optimize-re-renders-with-shouldcomponentupdate",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036180",
+ "title": "Optimize Re-Renders with shouldComponentUpdate"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/override-default-props",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d403616c",
+ "title": "Override Default Props"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/pass-a-callback-as-props",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d403617b",
+ "title": "Pass a Callback as Props"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/pass-an-array-as-props",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d403616a",
+ "title": "Pass an Array as Props"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/pass-props-to-a-stateless-functional-component",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036169",
+ "title": "Pass Props to a Stateless Functional Component"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/pass-state-as-props-to-child-components",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d403617a",
+ "title": "Pass State as Props to Child Components"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/render-a-class-component-to-the-dom",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036167",
+ "title": "Render a Class Component to the DOM"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/render-conditionally-from-props",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036188",
+ "title": "Render Conditionally from Props"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/render-html-elements-to-the-dom",
+ "blockName": "React"
+ },
+ "id": "5a24bbe0dba28a8d3cbd4c5f",
+ "title": "Render HTML Elements to the DOM"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/render-react-on-the-server-with-rendertostring",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d403618d",
+ "title": "Render React on the Server with renderToString"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/render-state-in-the-user-interface-another-way",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036172",
+ "title": "Render State in the User Interface Another Way"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/render-state-in-the-user-interface",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036171",
+ "title": "Render State in the User Interface"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/render-with-an-if-else-condition",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036184",
+ "title": "Render with an If-Else Condition"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/review-using-props-with-stateless-functional-components",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d403616f",
+ "title": "Review Using Props with Stateless Functional Components"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/set-state-with-this-setstate",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036173",
+ "title": "Set State with this.setState"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/use--for-a-more-concise-conditional",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036185",
+ "title": "Use && for a More Concise Conditional"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/use-a-ternary-expression-for-conditional-rendering",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036187",
+ "title": "Use a Ternary Expression for Conditional Rendering"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/use-advanced-javascript-in-react-render-method",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036183",
+ "title": "Use Advanced JavaScript in React Render Method"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/use-array-filter-to-dynamically-filter-an-array",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d403618c",
+ "title": "Use Array.filter() to Dynamically Filter an Array"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/use-array-map-to-dynamically-render-elements",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d403618a",
+ "title": "Use Array.map() to Dynamically Render Elements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/use-default-props",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d403616b",
+ "title": "Use Default Props"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/use-proptypes-to-define-the-props-you-expect",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d403616d",
+ "title": "Use PropTypes to Define the Props You Expect"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/use-react-to-render-nested-components",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036165",
+ "title": "Use React to Render Nested Components"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/use-state-to-toggle-an-element",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036176",
+ "title": "Use State to Toggle an Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/use-the-lifecycle-method-componentdidmount",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d403617d",
+ "title": "Use the Lifecycle Method componentDidMount"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/use-the-lifecycle-method-componentwillmount",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d403617c",
+ "title": "Use the Lifecycle Method componentWillMount"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/write-a-react-component-from-scratch",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036168",
+ "title": "Write a React Component from Scratch"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react/write-a-simple-counter",
+ "blockName": "React"
+ },
+ "id": "5a24c314108439a4d4036177",
+ "title": "Write a Simple Counter"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react-and-redux/connect-redux-to-react",
+ "blockName": "React and Redux"
+ },
+ "id": "5a24c314108439a4d4036147",
+ "title": "Connect Redux to React"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react-and-redux/connect-redux-to-the-messages-app",
+ "blockName": "React and Redux"
+ },
+ "id": "5a24c314108439a4d4036148",
+ "title": "Connect Redux to the Messages App"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react-and-redux/extract-local-state-into-redux",
+ "blockName": "React and Redux"
+ },
+ "id": "5a24c314108439a4d4036149",
+ "title": "Extract Local State into Redux"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react-and-redux/extract-state-logic-to-redux",
+ "blockName": "React and Redux"
+ },
+ "id": "5a24c314108439a4d4036143",
+ "title": "Extract State Logic to Redux"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react-and-redux/getting-started-with-react-redux",
+ "blockName": "React and Redux"
+ },
+ "id": "5a24c314108439a4d4036141",
+ "title": "Getting Started with React Redux"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react-and-redux/manage-state-locally-first",
+ "blockName": "React and Redux"
+ },
+ "id": "5a24c314108439a4d4036142",
+ "title": "Manage State Locally First"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react-and-redux/map-dispatch-to-props",
+ "blockName": "React and Redux"
+ },
+ "id": "5a24c314108439a4d4036146",
+ "title": "Map Dispatch to Props"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react-and-redux/map-state-to-props",
+ "blockName": "React and Redux"
+ },
+ "id": "5a24c314108439a4d4036145",
+ "title": "Map State to Props"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react-and-redux/moving-forward-from-here",
+ "blockName": "React and Redux"
+ },
+ "id": "5a24c314108439a4d403614a",
+ "title": "Moving Forward From Here"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/react-and-redux/use-provider-to-connect-redux-to-react",
+ "blockName": "React and Redux"
+ },
+ "id": "5a24c314108439a4d4036144",
+ "title": "Use Provider to Connect Redux to React"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/redux/combine-multiple-reducers",
+ "blockName": "Redux"
+ },
+ "id": "5a24c314108439a4d4036154",
+ "title": "Combine Multiple Reducers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/redux/copy-an-object-with-object-assign",
+ "blockName": "Redux"
+ },
+ "id": "5a24c314108439a4d403615b",
+ "title": "Copy an Object with Object.assign"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/redux/create-a-redux-store",
+ "blockName": "Redux"
+ },
+ "id": "5a24c314108439a4d403614b",
+ "title": "Create a Redux Store"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/redux/define-a-redux-action",
+ "blockName": "Redux"
+ },
+ "id": "5a24c314108439a4d403614d",
+ "title": "Define a Redux Action"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/redux/define-an-action-creator",
+ "blockName": "Redux"
+ },
+ "id": "5a24c314108439a4d403614e",
+ "title": "Define an Action Creator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/redux/dispatch-an-action-event",
+ "blockName": "Redux"
+ },
+ "id": "5a24c314108439a4d403614f",
+ "title": "Dispatch an Action Event"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/redux/get-state-from-the-redux-store",
+ "blockName": "Redux"
+ },
+ "id": "5a24c314108439a4d403614c",
+ "title": "Get State from the Redux Store"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/redux/handle-an-action-in-the-store",
+ "blockName": "Redux"
+ },
+ "id": "5a24c314108439a4d4036150",
+ "title": "Handle an Action in the Store"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/redux/never-mutate-state",
+ "blockName": "Redux"
+ },
+ "id": "5a24c314108439a4d4036158",
+ "title": "Never Mutate State"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/redux/register-a-store-listener",
+ "blockName": "Redux"
+ },
+ "id": "5a24c314108439a4d4036153",
+ "title": "Register a Store Listener"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/redux/remove-an-item-from-an-array",
+ "blockName": "Redux"
+ },
+ "id": "5a24c314108439a4d403615a",
+ "title": "Remove an Item from an Array"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/redux/send-action-data-to-the-store",
+ "blockName": "Redux"
+ },
+ "id": "5a24c314108439a4d4036155",
+ "title": "Send Action Data to the Store"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/redux/use-a-switch-statement-to-handle-multiple-actions",
+ "blockName": "Redux"
+ },
+ "id": "5a24c314108439a4d4036151",
+ "title": "Use a Switch Statement to Handle Multiple Actions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/redux/use-const-for-action-types",
+ "blockName": "Redux"
+ },
+ "id": "5a24c314108439a4d4036152",
+ "title": "Use const for Action Types"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/redux/use-middleware-to-handle-asynchronous-actions",
+ "blockName": "Redux"
+ },
+ "id": "5a24c314108439a4d4036156",
+ "title": "Use Middleware to Handle Asynchronous Actions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/redux/use-the-spread-operator-on-arrays",
+ "blockName": "Redux"
+ },
+ "id": "5a24c314108439a4d4036159",
+ "title": "Use the Spread Operator on Arrays"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/redux/write-a-counter-with-redux",
+ "blockName": "Redux"
+ },
+ "id": "5a24c314108439a4d4036157",
+ "title": "Write a Counter with Redux"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/sass/apply-a-style-until-a-condition-is-met-with-while",
+ "blockName": "Sass"
+ },
+ "id": "587d7dbf367417b2b2512bbb",
+ "title": "Apply a Style Until a Condition is Met with @while"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/sass/create-reusable-css-with-mixins",
+ "blockName": "Sass"
+ },
+ "id": "587d7dbd367417b2b2512bb6",
+ "title": "Create Reusable CSS with Mixins"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/sass/extend-one-set-of-css-styles-to-another-element",
+ "blockName": "Sass"
+ },
+ "id": "587d7fa5367417b2b2512bbd",
+ "title": "Extend One Set of CSS Styles to Another Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/sass/nest-css-with-sass",
+ "blockName": "Sass"
+ },
+ "id": "587d7dbd367417b2b2512bb5",
+ "title": "Nest CSS with Sass"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/sass/split-your-styles-into-smaller-chunks-with-partials",
+ "blockName": "Sass"
+ },
+ "id": "587d7dbf367417b2b2512bbc",
+ "title": "Split Your Styles into Smaller Chunks with Partials"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/sass/store-data-with-sass-variables",
+ "blockName": "Sass"
+ },
+ "id": "587d7dbd367417b2b2512bb4",
+ "title": "Store Data with Sass Variables"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/sass/use-each-to-map-over-items-in-a-list",
+ "blockName": "Sass"
+ },
+ "id": "587d7dbf367417b2b2512bba",
+ "title": "Use @each to Map Over Items in a List"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/sass/use-for-to-create-a-sass-loop",
+ "blockName": "Sass"
+ },
+ "id": "587d7dbe367417b2b2512bb9",
+ "title": "Use @for to Create a Sass Loop"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/front-end-development-libraries/sass/use-if-and-else-to-add-logic-to-your-styles",
+ "blockName": "Sass"
+ },
+ "id": "587d7dbe367417b2b2512bb8",
+ "title": "Use @if and @else to Add Logic To Your Styles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-projects/visualize-data-with-a-bar-chart",
+ "blockName": "Data Visualization Projects"
+ },
+ "id": "bd7168d8c242eddfaeb5bd13",
+ "title": "Visualize Data with a Bar Chart"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-projects/visualize-data-with-a-choropleth-map",
+ "blockName": "Data Visualization Projects"
+ },
+ "id": "587d7fa6367417b2b2512bbf",
+ "title": "Visualize Data with a Choropleth Map"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-projects/visualize-data-with-a-heat-map",
+ "blockName": "Data Visualization Projects"
+ },
+ "id": "bd7188d8c242eddfaeb5bd13",
+ "title": "Visualize Data with a Heat Map"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-projects/visualize-data-with-a-scatterplot-graph",
+ "blockName": "Data Visualization Projects"
+ },
+ "id": "bd7178d8c242eddfaeb5bd13",
+ "title": "Visualize Data with a Scatterplot Graph"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-projects/visualize-data-with-a-treemap-diagram",
+ "blockName": "Data Visualization Projects"
+ },
+ "id": "587d7fa6367417b2b2512bc0",
+ "title": "Visualize Data with a Treemap Diagram"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/add-a-hover-effect-to-a-d3-element",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7faa367417b2b2512bd4",
+ "title": "Add a Hover Effect to a D3 Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/add-a-tooltip-to-a-d3-element",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7faa367417b2b2512bd6",
+ "title": "Add a Tooltip to a D3 Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/add-attributes-to-the-circle-elements",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7fab367417b2b2512bd8",
+ "title": "Add Attributes to the Circle Elements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/add-axes-to-a-visualization",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7fad367417b2b2512bdf",
+ "title": "Add Axes to a Visualization"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/add-classes-with-d3",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7fa7367417b2b2512bc8",
+ "title": "Add Classes with D3"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/add-document-elements-with-d3",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7fa6367417b2b2512bc2",
+ "title": "Add Document Elements with D3"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/add-inline-styling-to-elements",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7fa7367417b2b2512bc6",
+ "title": "Add Inline Styling to Elements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/add-labels-to-d3-elements",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7faa367417b2b2512bd2",
+ "title": "Add Labels to D3 Elements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/add-labels-to-scatter-plot-circles",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7fab367417b2b2512bd9",
+ "title": "Add Labels to Scatter Plot Circles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/change-styles-based-on-data",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7fa7367417b2b2512bc7",
+ "title": "Change Styles Based on Data"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/change-the-color-of-an-svg-element",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7fa9367417b2b2512bd1",
+ "title": "Change the Color of an SVG Element"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/change-the-presentation-of-a-bar-chart",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7fa8367417b2b2512bca",
+ "title": "Change the Presentation of a Bar Chart"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/create-a-bar-for-each-data-point-in-the-set",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7fa8367417b2b2512bcd",
+ "title": "Create a Bar for Each Data Point in the Set"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/create-a-linear-scale-with-d3",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7fab367417b2b2512bda",
+ "title": "Create a Linear Scale with D3"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/create-a-scatterplot-with-svg-circles",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7fab367417b2b2512bd7",
+ "title": "Create a Scatterplot with SVG Circles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/display-shapes-with-svg",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7fa8367417b2b2512bcc",
+ "title": "Display Shapes with SVG"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/dynamically-change-the-height-of-each-bar",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7fa9367417b2b2512bcf",
+ "title": "Dynamically Change the Height of Each Bar"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/dynamically-set-the-coordinates-for-each-bar",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7fa9367417b2b2512bce",
+ "title": "Dynamically Set the Coordinates for Each Bar"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/invert-svg-elements",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7fa9367417b2b2512bd0",
+ "title": "Invert SVG Elements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/learn-about-svg-in-d3",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7fa8367417b2b2512bcb",
+ "title": "Learn About SVG in D3"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/select-a-group-of-elements-with-d3",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7fa6367417b2b2512bc3",
+ "title": "Select a Group of Elements with D3"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/set-a-domain-and-a-range-on-a-scale",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7fac367417b2b2512bdb",
+ "title": "Set a Domain and a Range on a Scale"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/style-d3-labels",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7faa367417b2b2512bd3",
+ "title": "Style D3 Labels"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/update-the-height-of-an-element-dynamically",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7fa8367417b2b2512bc9",
+ "title": "Update the Height of an Element Dynamically"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/use-a-pre-defined-scale-to-place-elements",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7fac367417b2b2512bde",
+ "title": "Use a Pre-Defined Scale to Place Elements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/use-dynamic-scales",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7fac367417b2b2512bdd",
+ "title": "Use Dynamic Scales"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/use-the-d3-max-and-d3-min-functions-to-find-minimum-and-maximum-values-in-a-dataset",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7fac367417b2b2512bdc",
+ "title": "Use the d3.max and d3.min Functions to Find Minimum and Maximum Values in a Dataset"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/work-with-data-in-d3",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7fa7367417b2b2512bc4",
+ "title": "Work with Data in D3"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/data-visualization-with-d3/work-with-dynamic-data-in-d3",
+ "blockName": "Data Visualization with D3"
+ },
+ "id": "587d7fa7367417b2b2512bc5",
+ "title": "Work with Dynamic Data in D3"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/json-apis-and-ajax/access-the-json-data-from-an-api",
+ "blockName": "JSON APIs and Ajax"
+ },
+ "id": "587d7fae367417b2b2512be4",
+ "title": "Access the JSON Data from an API"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/json-apis-and-ajax/change-text-with-click-events",
+ "blockName": "JSON APIs and Ajax"
+ },
+ "id": "587d7fad367417b2b2512be2",
+ "title": "Change Text with click Events"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/json-apis-and-ajax/convert-json-data-to-html",
+ "blockName": "JSON APIs and Ajax"
+ },
+ "id": "587d7fae367417b2b2512be5",
+ "title": "Convert JSON Data to HTML"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/json-apis-and-ajax/get-geolocation-data-to-find-a-users-gps-coordinates",
+ "blockName": "JSON APIs and Ajax"
+ },
+ "id": "587d7faf367417b2b2512be8",
+ "title": "Get Geolocation Data to Find A User's GPS Coordinates"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/json-apis-and-ajax/get-json-with-the-javascript-fetch-method",
+ "blockName": "JSON APIs and Ajax"
+ },
+ "id": "5ccfad82bb2dc6c965a848e5",
+ "title": "Get JSON with the JavaScript fetch method"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/json-apis-and-ajax/get-json-with-the-javascript-xmlhttprequest-method",
+ "blockName": "JSON APIs and Ajax"
+ },
+ "id": "587d7fae367417b2b2512be3",
+ "title": "Get JSON with the JavaScript XMLHttpRequest Method"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/json-apis-and-ajax/handle-click-events-with-javascript-using-the-onclick-property",
+ "blockName": "JSON APIs and Ajax"
+ },
+ "id": "587d7fad367417b2b2512be1",
+ "title": "Handle Click Events with JavaScript using the onclick property"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/json-apis-and-ajax/post-data-with-the-javascript-xmlhttprequest-method",
+ "blockName": "JSON APIs and Ajax"
+ },
+ "id": "587d7faf367417b2b2512be9",
+ "title": "Post Data with the JavaScript XMLHttpRequest Method"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/json-apis-and-ajax/pre-filter-json-to-get-the-data-you-need",
+ "blockName": "JSON APIs and Ajax"
+ },
+ "id": "587d7fae367417b2b2512be7",
+ "title": "Pre-filter JSON to Get the Data You Need"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-visualization/json-apis-and-ajax/render-images-from-data-sources",
+ "blockName": "JSON APIs and Ajax"
+ },
+ "id": "587d7fae367417b2b2512be6",
+ "title": "Render Images from Data Sources"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/back-end-development-and-apis-projects/exercise-tracker",
+ "blockName": "Back End Development and APIs Projects"
+ },
+ "id": "5a8b073d06fa14fcfde687aa",
+ "title": "Exercise Tracker"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/back-end-development-and-apis-projects/file-metadata-microservice",
+ "blockName": "Back End Development and APIs Projects"
+ },
+ "id": "bd7158d8c443edefaeb5bd0f",
+ "title": "File Metadata Microservice"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/back-end-development-and-apis-projects/request-header-parser-microservice",
+ "blockName": "Back End Development and APIs Projects"
+ },
+ "id": "bd7158d8c443edefaeb5bdff",
+ "title": "Request Header Parser Microservice"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/back-end-development-and-apis-projects/timestamp-microservice",
+ "blockName": "Back End Development and APIs Projects"
+ },
+ "id": "bd7158d8c443edefaeb5bdef",
+ "title": "Timestamp Microservice"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/back-end-development-and-apis-projects/url-shortener-microservice",
+ "blockName": "Back End Development and APIs Projects"
+ },
+ "id": "bd7158d8c443edefaeb5bd0e",
+ "title": "URL Shortener Microservice"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/basic-node-and-express/chain-middleware-to-create-a-time-server",
+ "blockName": "Basic Node and Express"
+ },
+ "id": "587d7fb1367417b2b2512bf4",
+ "title": "Chain Middleware to Create a Time Server"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/basic-node-and-express/get-data-from-post-requests",
+ "blockName": "Basic Node and Express"
+ },
+ "id": "587d7fb2367417b2b2512bf8",
+ "title": "Get Data from POST Requests"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/basic-node-and-express/get-query-parameter-input-from-the-client",
+ "blockName": "Basic Node and Express"
+ },
+ "id": "587d7fb2367417b2b2512bf6",
+ "title": "Get Query Parameter Input from the Client"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/basic-node-and-express/get-route-parameter-input-from-the-client",
+ "blockName": "Basic Node and Express"
+ },
+ "id": "587d7fb2367417b2b2512bf5",
+ "title": "Get Route Parameter Input from the Client"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/basic-node-and-express/implement-a-root-level-request-logger-middleware",
+ "blockName": "Basic Node and Express"
+ },
+ "id": "587d7fb1367417b2b2512bf3",
+ "title": "Implement a Root-Level Request Logger Middleware"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/basic-node-and-express/meet-the-node-console",
+ "blockName": "Basic Node and Express"
+ },
+ "id": "587d7fb0367417b2b2512bed",
+ "title": "Meet the Node console"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/basic-node-and-express/serve-an-html-file",
+ "blockName": "Basic Node and Express"
+ },
+ "id": "587d7fb0367417b2b2512bef",
+ "title": "Serve an HTML File"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/basic-node-and-express/serve-json-on-a-specific-route",
+ "blockName": "Basic Node and Express"
+ },
+ "id": "587d7fb1367417b2b2512bf1",
+ "title": "Serve JSON on a Specific Route"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/basic-node-and-express/serve-static-assets",
+ "blockName": "Basic Node and Express"
+ },
+ "id": "587d7fb0367417b2b2512bf0",
+ "title": "Serve Static Assets"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/basic-node-and-express/start-a-working-express-server",
+ "blockName": "Basic Node and Express"
+ },
+ "id": "587d7fb0367417b2b2512bee",
+ "title": "Start a Working Express Server"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/basic-node-and-express/use-body-parser-to-parse-post-requests",
+ "blockName": "Basic Node and Express"
+ },
+ "id": "587d7fb2367417b2b2512bf7",
+ "title": "Use body-parser to Parse POST Requests"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/basic-node-and-express/use-the--env-file",
+ "blockName": "Basic Node and Express"
+ },
+ "id": "587d7fb1367417b2b2512bf2",
+ "title": "Use the .env File"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/managing-packages-with-npm/add-a-description-to-your-package-json",
+ "blockName": "Managing Packages with Npm"
+ },
+ "id": "587d7fb3367417b2b2512bfc",
+ "title": "Add a Description to Your package.json"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/managing-packages-with-npm/add-a-license-to-your-package-json",
+ "blockName": "Managing Packages with Npm"
+ },
+ "id": "587d7fb4367417b2b2512bfe",
+ "title": "Add a License to Your package.json"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/managing-packages-with-npm/add-a-version-to-your-package-json",
+ "blockName": "Managing Packages with Npm"
+ },
+ "id": "587d7fb4367417b2b2512bff",
+ "title": "Add a Version to Your package.json"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/managing-packages-with-npm/add-keywords-to-your-package-json",
+ "blockName": "Managing Packages with Npm"
+ },
+ "id": "587d7fb4367417b2b2512bfd",
+ "title": "Add Keywords to Your package.json"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/managing-packages-with-npm/expand-your-project-with-external-packages-from-npm",
+ "blockName": "Managing Packages with Npm"
+ },
+ "id": "587d7fb4367417b2b2512c00",
+ "title": "Expand Your Project with External Packages from npm"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/managing-packages-with-npm/how-to-use-package-json-the-core-of-any-node-js-project-or-npm-package",
+ "blockName": "Managing Packages with Npm"
+ },
+ "id": "587d7fb3367417b2b2512bfb",
+ "title": "How to Use package.json, the Core of Any Node.js Project or npm Package"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/managing-packages-with-npm/manage-npm-dependencies-by-understanding-semantic-versioning",
+ "blockName": "Managing Packages with Npm"
+ },
+ "id": "587d7fb5367417b2b2512c01",
+ "title": "Manage npm Dependencies By Understanding Semantic Versioning"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/managing-packages-with-npm/remove-a-package-from-your-dependencies",
+ "blockName": "Managing Packages with Npm"
+ },
+ "id": "587d7fb5367417b2b2512c04",
+ "title": "Remove a Package from Your Dependencies"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/managing-packages-with-npm/use-the-caret-character-to-use-the-latest-minor-version-of-a-dependency",
+ "blockName": "Managing Packages with Npm"
+ },
+ "id": "587d7fb5367417b2b2512c03",
+ "title": "Use the Caret-Character to Use the Latest Minor Version of a Dependency"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/managing-packages-with-npm/use-the-tilde-character-to-always-use-the-latest-patch-version-of-a-dependency",
+ "blockName": "Managing Packages with Npm"
+ },
+ "id": "587d7fb5367417b2b2512c02",
+ "title": "Use the Tilde-Character to Always Use the Latest Patch Version of a Dependency"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/mongodb-and-mongoose/chain-search-query-helpers-to-narrow-search-results",
+ "blockName": "MongoDB and Mongoose"
+ },
+ "id": "587d7fb9367417b2b2512c12",
+ "title": "Chain Search Query Helpers to Narrow Search Results"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/mongodb-and-mongoose/create-a-model",
+ "blockName": "MongoDB and Mongoose"
+ },
+ "id": "587d7fb6367417b2b2512c07",
+ "title": "Create a Model"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/mongodb-and-mongoose/create-and-save-a-record-of-a-model",
+ "blockName": "MongoDB and Mongoose"
+ },
+ "id": "587d7fb6367417b2b2512c09",
+ "title": "Create and Save a Record of a Model"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/mongodb-and-mongoose/create-many-records-with-model-create",
+ "blockName": "MongoDB and Mongoose"
+ },
+ "id": "587d7fb7367417b2b2512c0a",
+ "title": "Create Many Records with model.create()"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/mongodb-and-mongoose/delete-many-documents-with-model-remove",
+ "blockName": "MongoDB and Mongoose"
+ },
+ "id": "587d7fb8367417b2b2512c11",
+ "title": "Delete Many Documents with model.remove()"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/mongodb-and-mongoose/delete-one-document-using-model-findbyidandremove",
+ "blockName": "MongoDB and Mongoose"
+ },
+ "id": "587d7fb8367417b2b2512c10",
+ "title": "Delete One Document Using model.findByIdAndRemove"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/mongodb-and-mongoose/install-and-set-up-mongoose",
+ "blockName": "MongoDB and Mongoose"
+ },
+ "id": "587d7fb6367417b2b2512c06",
+ "title": "Install and Set Up Mongoose"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/mongodb-and-mongoose/perform-classic-updates-by-running-find-edit-then-save",
+ "blockName": "MongoDB and Mongoose"
+ },
+ "id": "587d7fb8367417b2b2512c0e",
+ "title": "Perform Classic Updates by Running Find, Edit, then Save"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/mongodb-and-mongoose/perform-new-updates-on-a-document-using-model-findoneandupdate",
+ "blockName": "MongoDB and Mongoose"
+ },
+ "id": "587d7fb8367417b2b2512c0f",
+ "title": "Perform New Updates on a Document Using model.findOneAndUpdate()"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/mongodb-and-mongoose/use-model-find-to-search-your-database",
+ "blockName": "MongoDB and Mongoose"
+ },
+ "id": "587d7fb7367417b2b2512c0b",
+ "title": "Use model.find() to Search Your Database"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/mongodb-and-mongoose/use-model-findbyid-to-search-your-database-by-id",
+ "blockName": "MongoDB and Mongoose"
+ },
+ "id": "587d7fb7367417b2b2512c0d",
+ "title": "Use model.findById() to Search Your Database By _id"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/back-end-development-and-apis/mongodb-and-mongoose/use-model-findone-to-return-a-single-matching-document-from-your-database",
+ "blockName": "MongoDB and Mongoose"
+ },
+ "id": "587d7fb7367417b2b2512c0c",
+ "title": "Use model.findOne() to Return a Single Matching Document from Your Database"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/advanced-node-and-express/announce-new-users",
+ "blockName": "Advanced Node and Express"
+ },
+ "id": "589fc832f9fc0f352b528e78",
+ "title": "Announce New Users"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/advanced-node-and-express/authentication-strategies",
+ "blockName": "Advanced Node and Express"
+ },
+ "id": "5895f70df9fc0f352b528e68",
+ "title": "Authentication Strategies"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/advanced-node-and-express/authentication-with-socket-io",
+ "blockName": "Advanced Node and Express"
+ },
+ "id": "589fc831f9fc0f352b528e77",
+ "title": "Authentication with Socket.IO"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/advanced-node-and-express/clean-up-your-project-with-modules",
+ "blockName": "Advanced Node and Express"
+ },
+ "id": "589690e6f9fc0f352b528e6e",
+ "title": "Clean Up Your Project with Modules"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/advanced-node-and-express/communicate-by-emitting",
+ "blockName": "Advanced Node and Express"
+ },
+ "id": "589fc831f9fc0f352b528e75",
+ "title": "Communicate by Emitting"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/advanced-node-and-express/create-new-middleware",
+ "blockName": "Advanced Node and Express"
+ },
+ "id": "5895f70df9fc0f352b528e6a",
+ "title": "Create New Middleware"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/advanced-node-and-express/handle-a-disconnect",
+ "blockName": "Advanced Node and Express"
+ },
+ "id": "589fc831f9fc0f352b528e76",
+ "title": "Handle a Disconnect"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/advanced-node-and-express/hashing-your-passwords",
+ "blockName": "Advanced Node and Express"
+ },
+ "id": "58a25c98f9fc0f352b528e7f",
+ "title": "Hashing Your Passwords"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/advanced-node-and-express/how-to-put-a-profile-together",
+ "blockName": "Advanced Node and Express"
+ },
+ "id": "5895f70ef9fc0f352b528e6b",
+ "title": "How to Put a Profile Together"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/advanced-node-and-express/how-to-use-passport-strategies",
+ "blockName": "Advanced Node and Express"
+ },
+ "id": "5895f70df9fc0f352b528e69",
+ "title": "How to Use Passport Strategies"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/advanced-node-and-express/implement-the-serialization-of-a-passport-user",
+ "blockName": "Advanced Node and Express"
+ },
+ "id": "5895f70cf9fc0f352b528e67",
+ "title": "Implement the Serialization of a Passport User"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/advanced-node-and-express/implementation-of-social-authentication-ii",
+ "blockName": "Advanced Node and Express"
+ },
+ "id": "589a69f5f9fc0f352b528e71",
+ "title": "Implementation of Social Authentication II"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/advanced-node-and-express/implementation-of-social-authentication-iii",
+ "blockName": "Advanced Node and Express"
+ },
+ "id": "589a8eb3f9fc0f352b528e72",
+ "title": "Implementation of Social Authentication III"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/advanced-node-and-express/implementation-of-social-authentication",
+ "blockName": "Advanced Node and Express"
+ },
+ "id": "589a69f5f9fc0f352b528e70",
+ "title": "Implementation of Social Authentication"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/advanced-node-and-express/logging-a-user-out",
+ "blockName": "Advanced Node and Express"
+ },
+ "id": "58965611f9fc0f352b528e6c",
+ "title": "Logging a User Out"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/advanced-node-and-express/registration-of-new-users",
+ "blockName": "Advanced Node and Express"
+ },
+ "id": "58966a17f9fc0f352b528e6d",
+ "title": "Registration of New Users"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/advanced-node-and-express/send-and-display-chat-messages",
+ "blockName": "Advanced Node and Express"
+ },
+ "id": "589fc832f9fc0f352b528e79",
+ "title": "Send and Display Chat Messages"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/advanced-node-and-express/serialization-of-a-user-object",
+ "blockName": "Advanced Node and Express"
+ },
+ "id": "5895f70cf9fc0f352b528e66",
+ "title": "Serialization of a User Object"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/advanced-node-and-express/set-up-a-template-engine",
+ "blockName": "Advanced Node and Express"
+ },
+ "id": "5895f700f9fc0f352b528e63",
+ "title": "Set up a Template Engine"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/advanced-node-and-express/set-up-passport",
+ "blockName": "Advanced Node and Express"
+ },
+ "id": "5895f70cf9fc0f352b528e65",
+ "title": "Set up Passport"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/advanced-node-and-express/set-up-the-environment",
+ "blockName": "Advanced Node and Express"
+ },
+ "id": "589fc830f9fc0f352b528e74",
+ "title": "Set up the Environment"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/advanced-node-and-express/use-a-template-engines-powers",
+ "blockName": "Advanced Node and Express"
+ },
+ "id": "5895f70bf9fc0f352b528e64",
+ "title": "Use a Template Engine's Powers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-and-testing-with-chai/assert-deep-equality-with--deepequal-and--notdeepequal",
+ "blockName": "Quality Assurance and Testing with Chai"
+ },
+ "id": "587d824c367417b2b2512c4c",
+ "title": "Assert Deep Equality with .deepEqual and .notDeepEqual"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-and-testing-with-chai/compare-the-properties-of-two-elements",
+ "blockName": "Quality Assurance and Testing with Chai"
+ },
+ "id": "587d824c367417b2b2512c4d",
+ "title": "Compare the Properties of Two Elements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-and-testing-with-chai/learn-how-javascript-assertions-work",
+ "blockName": "Quality Assurance and Testing with Chai"
+ },
+ "id": "587d824a367417b2b2512c46",
+ "title": "Learn How JavaScript Assertions Work"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-and-testing-with-chai/run-functional-tests-on-an-api-response-using-chai-http-iii---put-method",
+ "blockName": "Quality Assurance and Testing with Chai"
+ },
+ "id": "587d824f367417b2b2512c5a",
+ "title": "Run Functional Tests on an API Response using Chai-HTTP III - PUT method"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-and-testing-with-chai/run-functional-tests-on-an-api-response-using-chai-http-iv---put-method",
+ "blockName": "Quality Assurance and Testing with Chai"
+ },
+ "id": "587d824f367417b2b2512c5b",
+ "title": "Run Functional Tests on an API Response using Chai-HTTP IV - PUT method"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-and-testing-with-chai/run-functional-tests-on-api-endpoints-using-chai-http-ii",
+ "blockName": "Quality Assurance and Testing with Chai"
+ },
+ "id": "587d824f367417b2b2512c59",
+ "title": "Run Functional Tests on API Endpoints using Chai-HTTP II"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-and-testing-with-chai/run-functional-tests-on-api-endpoints-using-chai-http",
+ "blockName": "Quality Assurance and Testing with Chai"
+ },
+ "id": "587d824e367417b2b2512c58",
+ "title": "Run Functional Tests on API Endpoints using Chai-HTTP"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-and-testing-with-chai/run-functional-tests-using-a-headless-browser-ii",
+ "blockName": "Quality Assurance and Testing with Chai"
+ },
+ "id": "5f8884f4c46685731aabfc41",
+ "title": "Run Functional Tests Using a Headless Browser II"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-and-testing-with-chai/run-functional-tests-using-a-headless-browser",
+ "blockName": "Quality Assurance and Testing with Chai"
+ },
+ "id": "587d8250367417b2b2512c5d",
+ "title": "Run Functional Tests Using a Headless Browser"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-and-testing-with-chai/simulate-actions-using-a-headless-browser",
+ "blockName": "Quality Assurance and Testing with Chai"
+ },
+ "id": "587d824f367417b2b2512c5c",
+ "title": "Simulate Actions Using a Headless Browser"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-and-testing-with-chai/test-for-truthiness",
+ "blockName": "Quality Assurance and Testing with Chai"
+ },
+ "id": "587d824b367417b2b2512c49",
+ "title": "Test for Truthiness"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-and-testing-with-chai/test-if-a-string-contains-a-substring",
+ "blockName": "Quality Assurance and Testing with Chai"
+ },
+ "id": "587d824d367417b2b2512c53",
+ "title": "Test if a String Contains a Substring"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-and-testing-with-chai/test-if-a-value-falls-within-a-specific-range",
+ "blockName": "Quality Assurance and Testing with Chai"
+ },
+ "id": "587d824c367417b2b2512c4f",
+ "title": "Test if a Value Falls within a Specific Range"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-and-testing-with-chai/test-if-a-value-is-a-string",
+ "blockName": "Quality Assurance and Testing with Chai"
+ },
+ "id": "587d824d367417b2b2512c52",
+ "title": "Test if a Value is a String"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-and-testing-with-chai/test-if-a-value-is-an-array",
+ "blockName": "Quality Assurance and Testing with Chai"
+ },
+ "id": "587d824d367417b2b2512c50",
+ "title": "Test if a Value is an Array"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-and-testing-with-chai/test-if-a-value-is-of-a-specific-data-structure-type",
+ "blockName": "Quality Assurance and Testing with Chai"
+ },
+ "id": "587d824e367417b2b2512c56",
+ "title": "Test if a Value is of a Specific Data Structure Type"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-and-testing-with-chai/test-if-a-variable-or-function-is-defined",
+ "blockName": "Quality Assurance and Testing with Chai"
+ },
+ "id": "587d824b367417b2b2512c47",
+ "title": "Test if a Variable or Function is Defined"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-and-testing-with-chai/test-if-an-array-contains-an-item",
+ "blockName": "Quality Assurance and Testing with Chai"
+ },
+ "id": "587d824d367417b2b2512c51",
+ "title": "Test if an Array Contains an Item"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-and-testing-with-chai/test-if-an-object-has-a-property",
+ "blockName": "Quality Assurance and Testing with Chai"
+ },
+ "id": "587d824e367417b2b2512c55",
+ "title": "Test if an Object has a Property"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-and-testing-with-chai/test-if-an-object-is-an-instance-of-a-constructor",
+ "blockName": "Quality Assurance and Testing with Chai"
+ },
+ "id": "587d824e367417b2b2512c57",
+ "title": "Test if an Object is an Instance of a Constructor"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-and-testing-with-chai/test-if-one-value-is-below-or-at-least-as-large-as-another",
+ "blockName": "Quality Assurance and Testing with Chai"
+ },
+ "id": "587d824c367417b2b2512c4e",
+ "title": "Test if One Value is Below or At Least as Large as Another"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-and-testing-with-chai/use-assert-isok-and-assert-isnotok",
+ "blockName": "Quality Assurance and Testing with Chai"
+ },
+ "id": "587d824b367417b2b2512c48",
+ "title": "Use Assert.isOK and Assert.isNotOK"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-and-testing-with-chai/use-regular-expressions-to-test-a-string",
+ "blockName": "Quality Assurance and Testing with Chai"
+ },
+ "id": "587d824d367417b2b2512c54",
+ "title": "Use Regular Expressions to Test a String"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-and-testing-with-chai/use-the-double-equals-to-assert-equality",
+ "blockName": "Quality Assurance and Testing with Chai"
+ },
+ "id": "587d824b367417b2b2512c4a",
+ "title": "Use the Double Equals to Assert Equality"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-and-testing-with-chai/use-the-triple-equals-to-assert-strict-equality",
+ "blockName": "Quality Assurance and Testing with Chai"
+ },
+ "id": "587d824b367417b2b2512c4b",
+ "title": "Use the Triple Equals to Assert Strict Equality"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-projects/american-british-translator",
+ "blockName": "Quality Assurance Projects"
+ },
+ "id": "5e601c0d5ac9d0ecd8b94afe",
+ "title": "American British Translator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-projects/issue-tracker",
+ "blockName": "Quality Assurance Projects"
+ },
+ "id": "587d8249367417b2b2512c42",
+ "title": "Issue Tracker"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-projects/metric-imperial-converter",
+ "blockName": "Quality Assurance Projects"
+ },
+ "id": "587d8249367417b2b2512c41",
+ "title": "Metric-Imperial Converter"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-projects/personal-library",
+ "blockName": "Quality Assurance Projects"
+ },
+ "id": "587d824a367417b2b2512c43",
+ "title": "Personal Library"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/quality-assurance/quality-assurance-projects/sudoku-solver",
+ "blockName": "Quality Assurance Projects"
+ },
+ "id": "5e601bf95ac9d0ecd8b94afd",
+ "title": "Sudoku Solver"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/build-your-own-functions",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f060b6c005b0e76f05b",
+ "title": "Build your own Functions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/comparing-and-sorting-tuples",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f0b0b6c005b0e76f06d",
+ "title": "Comparing and Sorting Tuples"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/conditional-execution",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f050b6c005b0e76f058",
+ "title": "Conditional Execution"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/data-visualization-mailing-lists",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f6a0b6c005b0e76f097",
+ "title": "Data Visualization: Mailing Lists"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/data-visualization-page-rank",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f6a0b6c005b0e76f096",
+ "title": "Data Visualization: Page Rank"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/dictionaries-and-loops",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f0a0b6c005b0e76f069",
+ "title": "Dictionaries and Loops"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/dictionaries-common-applications",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f090b6c005b0e76f068",
+ "title": "Dictionaries: Common Applications"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/files-as-a-sequence",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f080b6c005b0e76f063",
+ "title": "Files as a Sequence"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/intermediate-expressions",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f050b6c005b0e76f057",
+ "title": "Intermediate Expressions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/intermediate-strings",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f070b6c005b0e76f061",
+ "title": "Intermediate Strings"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/introduction-elements-of-python",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e6a54c358d3af90110a60a3",
+ "title": "Introduction: Elements of Python"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/introduction-hardware-architecture",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e6a54af58d3af90110a60a1",
+ "title": "Introduction: Hardware Architecture"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/introduction-python-as-a-language",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e6a54ba58d3af90110a60a2",
+ "title": "Introduction: Python as a Language"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/introduction-why-program",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e6a54a558d3af90110a60a0",
+ "title": "Introduction: Why Program?"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/iterations-definite-loops",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f070b6c005b0e76f05d",
+ "title": "Iterations: Definite Loops"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/iterations-loop-idioms",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f070b6c005b0e76f05e",
+ "title": "Iterations: Loop Idioms"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/iterations-more-patterns",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f070b6c005b0e76f05f",
+ "title": "Iterations: More Patterns"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/loops-and-iterations",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f060b6c005b0e76f05c",
+ "title": "Loops and Iterations"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/make-a-relational-database",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f170b6c005b0e76f08b",
+ "title": "Make a Relational Database"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/more-conditional-structures",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f060b6c005b0e76f059",
+ "title": "More Conditional Structures"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/networking-protocol",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f0c0b6c005b0e76f072",
+ "title": "Networking Protocol"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/networking-text-processing",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f0c0b6c005b0e76f074",
+ "title": "Networking: Text Processing"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/networking-using-urllib-in-python",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f0d0b6c005b0e76f075",
+ "title": "Networking: Using urllib in Python"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/networking-web-scraping-with-python",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f0d0b6c005b0e76f076",
+ "title": "Networking: Web Scraping with Python"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/networking-with-python",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f0c0b6c005b0e76f071",
+ "title": "Networking with Python"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/networking-write-a-web-browser",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f0c0b6c005b0e76f073",
+ "title": "Networking: Write a Web Browser"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/object-lifecycle",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f170b6c005b0e76f087",
+ "title": "Object Lifecycle"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/objects-a-sample-class",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f160b6c005b0e76f086",
+ "title": "Objects: A Sample Class"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/objects-inheritance",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f170b6c005b0e76f088",
+ "title": "Objects: Inheritance"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/python-dictionaries",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f090b6c005b0e76f067",
+ "title": "Python Dictionaries"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/python-functions",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f060b6c005b0e76f05a",
+ "title": "Python Functions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/python-lists",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f080b6c005b0e76f064",
+ "title": "Python Lists"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/python-objects",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f160b6c005b0e76f085",
+ "title": "Python Objects"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/reading-files",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f080b6c005b0e76f062",
+ "title": "Reading Files"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/regular-expressions-matching-and-extracting-data",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f0b0b6c005b0e76f06f",
+ "title": "Regular Expressions: Matching and Extracting Data"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/regular-expressions-practical-applications",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f0b0b6c005b0e76f070",
+ "title": "Regular Expressions: Practical Applications"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/regular-expressions",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f0b0b6c005b0e76f06e",
+ "title": "Regular Expressions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/relational-database-design",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f180b6c005b0e76f08c",
+ "title": "Relational Database Design"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/relational-databases-and-sqlite",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f170b6c005b0e76f08a",
+ "title": "Relational Databases and SQLite"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/relational-databases-join-operation",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f180b6c005b0e76f08f",
+ "title": "Relational Databases: Join Operation"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/relational-databases-many-to-many-relationships",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f190b6c005b0e76f090",
+ "title": "Relational Databases: Many-to-many Relationships"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/relational-databases-relationship-building",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f180b6c005b0e76f08e",
+ "title": "Relational Databases: Relationship Building"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/representing-relationships-in-a-relational-database",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f180b6c005b0e76f08d",
+ "title": "Representing Relationships in a Relational Database"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/strings-and-lists",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f090b6c005b0e76f066",
+ "title": "Strings and Lists"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/strings-in-python",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f070b6c005b0e76f060",
+ "title": "Strings in Python"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/the-tuples-collection",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f0a0b6c005b0e76f06c",
+ "title": "The Tuples Collection"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/using-web-services",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f0e0b6c005b0e76f07a",
+ "title": "Using Web Services"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/variables-expressions-and-statements",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f050b6c005b0e76f056",
+ "title": "Variables, Expressions, and Statements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/visualizing-data-with-python",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f690b6c005b0e76f095",
+ "title": "Visualizing Data with Python"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/web-services-api-rate-limiting-and-security",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f150b6c005b0e76f080",
+ "title": "Web Services: API Rate Limiting and Security"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/web-services-apis",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f150b6c005b0e76f07f",
+ "title": "Web Services: APIs"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/web-services-json",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f140b6c005b0e76f07d",
+ "title": "Web Services: JSON"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/web-services-service-oriented-approach",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f140b6c005b0e76f07e",
+ "title": "Web Services: Service Oriented Approach"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/web-services-xml-schema",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f0e0b6c005b0e76f07c",
+ "title": "Web Services: XML Schema"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/web-services-xml",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f0e0b6c005b0e76f07b",
+ "title": "Web Services: XML"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/python-for-everybody/working-with-lists",
+ "blockName": "Python for Everybody"
+ },
+ "id": "5e7b9f090b6c005b0e76f065",
+ "title": "Working with Lists"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/scientific-computing-with-python-projects/arithmetic-formatter",
+ "blockName": "Scientific Computing with Python Projects"
+ },
+ "id": "5e44412c903586ffb414c94c",
+ "title": "Arithmetic Formatter"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/scientific-computing-with-python-projects/budget-app",
+ "blockName": "Scientific Computing with Python Projects"
+ },
+ "id": "5e44413e903586ffb414c94e",
+ "title": "Budget App"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/scientific-computing-with-python-projects/polygon-area-calculator",
+ "blockName": "Scientific Computing with Python Projects"
+ },
+ "id": "5e444147903586ffb414c94f",
+ "title": "Polygon Area Calculator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/scientific-computing-with-python-projects/probability-calculator",
+ "blockName": "Scientific Computing with Python Projects"
+ },
+ "id": "5e44414f903586ffb414c950",
+ "title": "Probability Calculator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/scientific-computing-with-python/scientific-computing-with-python-projects/time-calculator",
+ "blockName": "Scientific Computing with Python Projects"
+ },
+ "id": "5e444136903586ffb414c94d",
+ "title": "Time Calculator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/data-analysis-example-a",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c14d",
+ "title": "Data Analysis Example A"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/data-analysis-example-b",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c14e",
+ "title": "Data Analysis Example B"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/data-cleaning-and-visualizations",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c160",
+ "title": "Data Cleaning and Visualizations"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/data-cleaning-duplicates",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c15f",
+ "title": "Data Cleaning Duplicates"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/data-cleaning-introduction",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c15d",
+ "title": "Data Cleaning Introduction"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/data-cleaning-with-dataframes",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c15e",
+ "title": "Data Cleaning with DataFrames"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/how-to-use-jupyter-notebooks-intro",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c14f",
+ "title": "How to use Jupyter Notebooks Intro"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/introduction-to-data-analysis",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c14c",
+ "title": "Introduction to Data Analysis"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/jupyter-notebooks-cells",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c150",
+ "title": "Jupyter Notebooks Cells"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/jupyter-notebooks-importing-and-exporting-data",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c151",
+ "title": "Jupyter Notebooks Importing and Exporting Data"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/numpy-algebra-and-size",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c157",
+ "title": "Numpy Algebra and Size"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/numpy-arrays",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c154",
+ "title": "Numpy Arrays"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/numpy-boolean-arrays",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c156",
+ "title": "Numpy Boolean Arrays"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/numpy-introduction-a",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c152",
+ "title": "Numpy Introduction A"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/numpy-introduction-b",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c153",
+ "title": "Numpy Introduction B"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/numpy-operations",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c155",
+ "title": "Numpy Operations"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/pandas-conditional-selection-and-modifying-dataframes",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c15b",
+ "title": "Pandas Conditional Selection and Modifying DataFrames"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/pandas-creating-columns",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c15c",
+ "title": "Pandas Creating Columns"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/pandas-dataframes",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c15a",
+ "title": "Pandas DataFrames"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/pandas-indexing-and-conditional-selection",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c159",
+ "title": "Pandas Indexing and Conditional Selection"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/pandas-introduction",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c158",
+ "title": "Pandas Introduction"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/parsing-html-and-saving-data",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c164",
+ "title": "Parsing HTML and Saving Data"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/python-functions-and-collections",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c166",
+ "title": "Python Functions and Collections"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/python-introduction",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c165",
+ "title": "Python Introduction"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/python-iteration-and-modules",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c167",
+ "title": "Python Iteration and Modules"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/reading-data-csv-and-txt",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c162",
+ "title": "Reading Data CSV and TXT"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/reading-data-from-databases",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c163",
+ "title": "Reading Data from Databases"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-course/reading-data-introduction",
+ "blockName": "Data Analysis with Python Course"
+ },
+ "id": "5e9a093a74c4063ca6f7c161",
+ "title": "Reading Data Introduction"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-projects/demographic-data-analyzer",
+ "blockName": "Data Analysis with Python Projects"
+ },
+ "id": "5e46f7e5ac417301a38fb929",
+ "title": "Demographic Data Analyzer"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-projects/mean-variance-standard-deviation-calculator",
+ "blockName": "Data Analysis with Python Projects"
+ },
+ "id": "5e46f7e5ac417301a38fb928",
+ "title": "Mean-Variance-Standard Deviation Calculator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-projects/medical-data-visualizer",
+ "blockName": "Data Analysis with Python Projects"
+ },
+ "id": "5e46f7f8ac417301a38fb92a",
+ "title": "Medical Data Visualizer"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-projects/page-view-time-series-visualizer",
+ "blockName": "Data Analysis with Python Projects"
+ },
+ "id": "5e46f802ac417301a38fb92b",
+ "title": "Page View Time Series Visualizer"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/data-analysis-with-python-projects/sea-level-predictor",
+ "blockName": "Data Analysis with Python Projects"
+ },
+ "id": "5e4f5c4b570f7e3a4949899f",
+ "title": "Sea Level Predictor"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/numpy/accessing-and-changing-elements-rows-columns",
+ "blockName": "Numpy"
+ },
+ "id": "5e9a0a8e09c5df3cc3600ed4",
+ "title": "Accessing and Changing Elements, Rows, Columns"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/numpy/basics-of-numpy",
+ "blockName": "Numpy"
+ },
+ "id": "5e9a0a8e09c5df3cc3600ed3",
+ "title": "Basics of Numpy"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/numpy/copying-arrays-warning",
+ "blockName": "Numpy"
+ },
+ "id": "5e9a0a8e09c5df3cc3600ed7",
+ "title": "Copying Arrays Warning"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/numpy/initialize-array-problem",
+ "blockName": "Numpy"
+ },
+ "id": "5e9a0a8e09c5df3cc3600ed6",
+ "title": "Initialize Array Problem"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/numpy/initializing-different-arrays",
+ "blockName": "Numpy"
+ },
+ "id": "5e9a0a8e09c5df3cc3600ed5",
+ "title": "Initializing Different Arrays"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/numpy/loading-data-and-advanced-indexing",
+ "blockName": "Numpy"
+ },
+ "id": "5e9a0a8e09c5df3cc3600eda",
+ "title": "Loading Data and Advanced Indexing"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/numpy/mathematics",
+ "blockName": "Numpy"
+ },
+ "id": "5e9a0a8e09c5df3cc3600ed8",
+ "title": "Mathematics"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/numpy/reorganizing-arrays",
+ "blockName": "Numpy"
+ },
+ "id": "5e9a0a8e09c5df3cc3600ed9",
+ "title": "Reorganizing Arrays"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/data-analysis-with-python/numpy/what-is-numpy",
+ "blockName": "Numpy"
+ },
+ "id": "5e9a0a8e09c5df3cc3600ed2",
+ "title": "What is NumPy"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/information-security-projects/anonymous-message-board",
+ "blockName": "Information Security Projects"
+ },
+ "id": "587d824a367417b2b2512c45",
+ "title": "Anonymous Message Board"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/information-security-projects/port-scanner",
+ "blockName": "Information Security Projects"
+ },
+ "id": "5e46f979ac417301a38fb932",
+ "title": "Port Scanner"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/information-security-projects/secure-real-time-multiplayer-game",
+ "blockName": "Information Security Projects"
+ },
+ "id": "5e601c775ac9d0ecd8b94aff",
+ "title": "Secure Real Time Multiplayer Game"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/information-security-projects/sha-1-password-cracker",
+ "blockName": "Information Security Projects"
+ },
+ "id": "5e46f983ac417301a38fb933",
+ "title": "SHA-1 Password Cracker"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/information-security-projects/stock-price-checker",
+ "blockName": "Information Security Projects"
+ },
+ "id": "587d824a367417b2b2512c44",
+ "title": "Stock Price Checker"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/information-security-with-helmetjs/ask-browsers-to-access-your-site-via-https-only-with-helmet-hsts",
+ "blockName": "Information Security with HelmetJS"
+ },
+ "id": "587d8248367417b2b2512c3c",
+ "title": "Ask Browsers to Access Your Site via HTTPS Only with helmet.hsts()"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/information-security-with-helmetjs/avoid-inferring-the-response-mime-type-with-helmet-nosniff",
+ "blockName": "Information Security with HelmetJS"
+ },
+ "id": "587d8248367417b2b2512c3a",
+ "title": "Avoid Inferring the Response MIME Type with helmet.noSniff()"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/information-security-with-helmetjs/configure-helmet-using-the-parent-helmet-middleware",
+ "blockName": "Information Security with HelmetJS"
+ },
+ "id": "587d8249367417b2b2512c40",
+ "title": "Configure Helmet Using the ‘parent’ helmet() Middleware"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/information-security-with-helmetjs/disable-client-side-caching-with-helmet-nocache",
+ "blockName": "Information Security with HelmetJS"
+ },
+ "id": "587d8249367417b2b2512c3e",
+ "title": "Disable Client-Side Caching with helmet.noCache()"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/information-security-with-helmetjs/disable-dns-prefetching-with-helmet-dnsprefetchcontrol",
+ "blockName": "Information Security with HelmetJS"
+ },
+ "id": "587d8248367417b2b2512c3d",
+ "title": "Disable DNS Prefetching with helmet.dnsPrefetchControl()"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/information-security-with-helmetjs/hash-and-compare-passwords-asynchronously",
+ "blockName": "Information Security with HelmetJS"
+ },
+ "id": "58a25bcff9fc0f352b528e7d",
+ "title": "Hash and Compare Passwords Asynchronously"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/information-security-with-helmetjs/hash-and-compare-passwords-synchronously",
+ "blockName": "Information Security with HelmetJS"
+ },
+ "id": "58a25bcff9fc0f352b528e7e",
+ "title": "Hash and Compare Passwords Synchronously"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/information-security-with-helmetjs/hide-potentially-dangerous-information-using-helmet-hidepoweredby",
+ "blockName": "Information Security with HelmetJS"
+ },
+ "id": "587d8247367417b2b2512c37",
+ "title": "Hide Potentially Dangerous Information Using helmet.hidePoweredBy()"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/information-security-with-helmetjs/install-and-require-helmet",
+ "blockName": "Information Security with HelmetJS"
+ },
+ "id": "587d8247367417b2b2512c36",
+ "title": "Install and Require Helmet"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/information-security-with-helmetjs/mitigate-the-risk-of-clickjacking-with-helmet-frameguard",
+ "blockName": "Information Security with HelmetJS"
+ },
+ "id": "587d8247367417b2b2512c38",
+ "title": "Mitigate the Risk of Clickjacking with helmet.frameguard()"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/information-security-with-helmetjs/mitigate-the-risk-of-cross-site-scripting-xss-attacks-with-helmet-xssfilter",
+ "blockName": "Information Security with HelmetJS"
+ },
+ "id": "587d8247367417b2b2512c39",
+ "title": "Mitigate the Risk of Cross Site Scripting (XSS) Attacks with helmet.xssFilter()"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/information-security-with-helmetjs/prevent-ie-from-opening-untrusted-html-with-helmet-ienoopen",
+ "blockName": "Information Security with HelmetJS"
+ },
+ "id": "587d8248367417b2b2512c3b",
+ "title": "Prevent IE from Opening Untrusted HTML with helmet.ieNoOpen()"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/information-security-with-helmetjs/set-a-content-security-policy-with-helmet-contentsecuritypolicy",
+ "blockName": "Information Security with HelmetJS"
+ },
+ "id": "587d8249367417b2b2512c3f",
+ "title": "Set a Content Security Policy with helmet.contentSecurityPolicy()"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/information-security-with-helmetjs/understand-bcrypt-hashes",
+ "blockName": "Information Security with HelmetJS"
+ },
+ "id": "58a25bcef9fc0f352b528e7c",
+ "title": "Understand BCrypt Hashes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/python-for-penetration-testing/creating-a-tcp-client",
+ "blockName": "Python for Penetration Testing"
+ },
+ "id": "5ea9997bbec2e9bc47e94db0",
+ "title": "Creating a TCP Client"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/python-for-penetration-testing/developing-a-banner-grabber",
+ "blockName": "Python for Penetration Testing"
+ },
+ "id": "5ea9997bbec2e9bc47e94db3",
+ "title": "Developing a Banner Grabber"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/python-for-penetration-testing/developing-a-port-scanner",
+ "blockName": "Python for Penetration Testing"
+ },
+ "id": "5ea9997bbec2e9bc47e94db4",
+ "title": "Developing a Port Scanner"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/python-for-penetration-testing/developing-an-nmap-scanner-part-1",
+ "blockName": "Python for Penetration Testing"
+ },
+ "id": "5ea9997bbec2e9bc47e94db1",
+ "title": "Developing an Nmap Scanner part 1"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/python-for-penetration-testing/developing-an-nmap-scanner-part-2",
+ "blockName": "Python for Penetration Testing"
+ },
+ "id": "5ea9997bbec2e9bc47e94db2",
+ "title": "Developing an Nmap Scanner part 2"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/python-for-penetration-testing/introduction-and-setup",
+ "blockName": "Python for Penetration Testing"
+ },
+ "id": "5ea9997bbec2e9bc47e94dae",
+ "title": "Introduction and Setup"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/information-security/python-for-penetration-testing/understanding-sockets-and-creating-a-tcp-server",
+ "blockName": "Python for Penetration Testing"
+ },
+ "id": "5ea9997bbec2e9bc47e94daf",
+ "title": "Understanding Sockets and Creating a TCP Server"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/algorithms/find-the-symmetric-difference",
+ "blockName": "Algorithms"
+ },
+ "id": "a3f503de51cf954ede28891d",
+ "title": "Find the Symmetric Difference"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/algorithms/implement-binary-search",
+ "blockName": "Algorithms"
+ },
+ "id": "61abc7ebf3029b56226de5b6",
+ "title": "Implement Binary Search"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/algorithms/implement-bubble-sort",
+ "blockName": "Algorithms"
+ },
+ "id": "8d5123c8c441eddfaeb5bdef",
+ "title": "Implement Bubble Sort"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/algorithms/implement-insertion-sort",
+ "blockName": "Algorithms"
+ },
+ "id": "587d8259367417b2b2512c86",
+ "title": "Implement Insertion Sort"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/algorithms/implement-merge-sort",
+ "blockName": "Algorithms"
+ },
+ "id": "587d825c367417b2b2512c8f",
+ "title": "Implement Merge Sort"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/algorithms/implement-quick-sort",
+ "blockName": "Algorithms"
+ },
+ "id": "587d825a367417b2b2512c89",
+ "title": "Implement Quick Sort"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/algorithms/implement-selection-sort",
+ "blockName": "Algorithms"
+ },
+ "id": "587d8259367417b2b2512c85",
+ "title": "Implement Selection Sort"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/algorithms/inventory-update",
+ "blockName": "Algorithms"
+ },
+ "id": "a56138aff60341a09ed6c480",
+ "title": "Inventory Update"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/algorithms/no-repeats-please",
+ "blockName": "Algorithms"
+ },
+ "id": "a7bf700cd123b9a54eef01d5",
+ "title": "No Repeats Please"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/algorithms/pairwise",
+ "blockName": "Algorithms"
+ },
+ "id": "a3f503de51cfab748ff001aa",
+ "title": "Pairwise"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/add-a-new-element-to-a-binary-search-tree",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8257367417b2b2512c7b",
+ "title": "Add a New Element to a Binary Search Tree"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/add-elements-at-a-specific-index-in-a-linked-list",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8252367417b2b2512c67",
+ "title": "Add Elements at a Specific Index in a Linked List"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/adjacency-list",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8256367417b2b2512c77",
+ "title": "Adjacency List"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/adjacency-matrix",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8256367417b2b2512c78",
+ "title": "Adjacency Matrix"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/breadth-first-search",
+ "blockName": "Data Structures"
+ },
+ "id": "587d825c367417b2b2512c90",
+ "title": "Breadth-First Search"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/check-if-an-element-is-present-in-a-binary-search-tree",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8257367417b2b2512c7c",
+ "title": "Check if an Element is Present in a Binary Search Tree"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/check-if-tree-is-binary-search-tree",
+ "blockName": "Data Structures"
+ },
+ "id": "5cc0c1b32479e176caf3b422",
+ "title": "Check if Tree is Binary Search Tree"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/create-a-circular-queue",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8255367417b2b2512c75",
+ "title": "Create a Circular Queue"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/create-a-doubly-linked-list",
+ "blockName": "Data Structures"
+ },
+ "id": "587d825a367417b2b2512c87",
+ "title": "Create a Doubly Linked List"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/create-a-hash-table",
+ "blockName": "Data Structures"
+ },
+ "id": "587d825b367417b2b2512c8e",
+ "title": "Create a Hash Table"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/create-a-linked-list-class",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8251367417b2b2512c62",
+ "title": "Create a Linked List Class"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/create-a-map-data-structure",
+ "blockName": "Data Structures"
+ },
+ "id": "8d5823c8c441eddfaeb5bdef",
+ "title": "Create a Map Data Structure"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/create-a-priority-queue-class",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8255367417b2b2512c74",
+ "title": "Create a Priority Queue Class"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/create-a-queue-class",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8250367417b2b2512c60",
+ "title": "Create a Queue Class"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/create-a-set-class",
+ "blockName": "Data Structures"
+ },
+ "id": "8d1323c8c441eddfaeb5bdef",
+ "title": "Create a Set Class"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/create-a-stack-class",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8250367417b2b2512c5f",
+ "title": "Create a Stack Class"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/create-a-trie-search-tree",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8259367417b2b2512c84",
+ "title": "Create a Trie Search Tree"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/create-an-es6-javascript-map",
+ "blockName": "Data Structures"
+ },
+ "id": "587d825b367417b2b2512c8d",
+ "title": "Create an ES6 JavaScript Map"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/create-and-add-to-sets-in-es6",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8254367417b2b2512c70",
+ "title": "Create and Add to Sets in ES6"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/delete-a-leaf-node-in-a-binary-search-tree",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8258367417b2b2512c80",
+ "title": "Delete a Leaf Node in a Binary Search Tree"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/delete-a-node-with-one-child-in-a-binary-search-tree",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8258367417b2b2512c81",
+ "title": "Delete a Node with One Child in a Binary Search Tree"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/delete-a-node-with-two-children-in-a-binary-search-tree",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8258367417b2b2512c82",
+ "title": "Delete a Node with Two Children in a Binary Search Tree"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/depth-first-search",
+ "blockName": "Data Structures"
+ },
+ "id": "587d825d367417b2b2512c96",
+ "title": "Depth-First Search"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/find-the-minimum-and-maximum-height-of-a-binary-search-tree",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8257367417b2b2512c7d",
+ "title": "Find the Minimum and Maximum Height of a Binary Search Tree"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/find-the-minimum-and-maximum-value-in-a-binary-search-tree",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8256367417b2b2512c7a",
+ "title": "Find the Minimum and Maximum Value in a Binary Search Tree"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/implement-heap-sort-with-a-min-heap",
+ "blockName": "Data Structures"
+ },
+ "id": "587d825b367417b2b2512c8c",
+ "title": "Implement Heap Sort with a Min Heap"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/incidence-matrix",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8256367417b2b2512c79",
+ "title": "Incidence Matrix"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/insert-an-element-into-a-max-heap",
+ "blockName": "Data Structures"
+ },
+ "id": "587d825a367417b2b2512c8a",
+ "title": "Insert an Element into a Max Heap"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/invert-a-binary-tree",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8259367417b2b2512c83",
+ "title": "Invert a Binary Tree"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/learn-how-a-stack-works",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8250367417b2b2512c5e",
+ "title": "Learn how a Stack Works"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/perform-a-difference-on-two-sets-of-data",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8254367417b2b2512c6e",
+ "title": "Perform a Difference on Two Sets of Data"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/perform-a-subset-check-on-two-sets-of-data",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8254367417b2b2512c6f",
+ "title": "Perform a Subset Check on Two Sets of Data"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/perform-a-union-on-two-sets",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8253367417b2b2512c6c",
+ "title": "Perform a Union on Two Sets"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/perform-an-intersection-on-two-sets-of-data",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8253367417b2b2512c6d",
+ "title": "Perform an Intersection on Two Sets of Data"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/remove-an-element-from-a-max-heap",
+ "blockName": "Data Structures"
+ },
+ "id": "587d825b367417b2b2512c8b",
+ "title": "Remove an Element from a Max Heap"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/remove-elements-from-a-linked-list-by-index",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8251367417b2b2512c65",
+ "title": "Remove Elements from a Linked List by Index"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/remove-elements-from-a-linked-list",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8251367417b2b2512c63",
+ "title": "Remove Elements from a Linked List"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/remove-items-from-a-set-in-es6",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8254367417b2b2512c71",
+ "title": "Remove items from a set in ES6"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/reverse-a-doubly-linked-list",
+ "blockName": "Data Structures"
+ },
+ "id": "587d825a367417b2b2512c88",
+ "title": "Reverse a Doubly Linked List"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/search-within-a-linked-list",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8251367417b2b2512c64",
+ "title": "Search within a Linked List"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/typed-arrays",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8253367417b2b2512c6a",
+ "title": "Typed Arrays"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/use--has-and--size-on-an-es6-set",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8255367417b2b2512c72",
+ "title": "Use .has and .size on an ES6 Set"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/use-breadth-first-search-in-a-binary-search-tree",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8258367417b2b2512c7f",
+ "title": "Use Breadth First Search in a Binary Search Tree"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/use-depth-first-search-in-a-binary-search-tree",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8257367417b2b2512c7e",
+ "title": "Use Depth First Search in a Binary Search Tree"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/use-spread-and-notes-for-es5-set-integration",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8255367417b2b2512c73",
+ "title": "Use Spread and Notes for ES5 Set() Integration"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/data-structures/work-with-nodes-in-a-linked-list",
+ "blockName": "Data Structures"
+ },
+ "id": "587d8251367417b2b2512c61",
+ "title": "Work with Nodes in a Linked List"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-1-multiples-of-3-and-5",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f36e1000cf542c50fe80",
+ "title": "Problem 1: Multiples of 3 and 5"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-10-summation-of-primes",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3761000cf542c50fe89",
+ "title": "Problem 10: Summation of primes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-100-arranged-probability",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3d01000cf542c50fee3",
+ "title": "Problem 100: Arranged probability"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-101-optimum-polynomial",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3d21000cf542c50fee4",
+ "title": "Problem 101: Optimum polynomial"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-102-triangle-containment",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3d21000cf542c50fee5",
+ "title": "Problem 102: Triangle containment"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-103-special-subset-sums-optimum",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3d61000cf542c50fee7",
+ "title": "Problem 103: Special subset sums: optimum"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-104-pandigital-fibonacci-ends",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3d51000cf542c50fee6",
+ "title": "Problem 104: Pandigital Fibonacci ends"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-105-special-subset-sums-testing",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3d61000cf542c50fee8",
+ "title": "Problem 105: Special subset sums: testing"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-106-special-subset-sums-meta-testing",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3d71000cf542c50fee9",
+ "title": "Problem 106: Special subset sums: meta-testing"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-107-minimal-network",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3d91000cf542c50feea",
+ "title": "Problem 107: Minimal network"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-108-diophantine-reciprocals-i",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3d91000cf542c50feeb",
+ "title": "Problem 108: Diophantine Reciprocals I"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-109-darts",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3db1000cf542c50feec",
+ "title": "Problem 109: Darts"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-11-largest-product-in-a-grid",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3781000cf542c50fe8a",
+ "title": "Problem 11: Largest product in a grid"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-110-diophantine-reciprocals-ii",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3db1000cf542c50feed",
+ "title": "Problem 110: Diophantine Reciprocals II"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-111-primes-with-runs",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3db1000cf542c50feee",
+ "title": "Problem 111: Primes with runs"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-112-bouncy-numbers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3dd1000cf542c50feef",
+ "title": "Problem 112: Bouncy numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-113-non-bouncy-numbers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3dd1000cf542c50fef0",
+ "title": "Problem 113: Non-bouncy numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-114-counting-block-combinations-i",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3e01000cf542c50fef2",
+ "title": "Problem 114: Counting block combinations I"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-115-counting-block-combinations-ii",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3df1000cf542c50fef1",
+ "title": "Problem 115: Counting block combinations II"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-116-red-green-or-blue-tiles",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3e01000cf542c50fef3",
+ "title": "Problem 116: Red, green or blue tiles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-117-red-green-and-blue-tiles",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3e21000cf542c50fef4",
+ "title": "Problem 117: Red, green, and blue tiles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-118-pandigital-prime-sets",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3e21000cf542c50fef5",
+ "title": "Problem 118: Pandigital prime sets"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-119-digit-power-sum",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3e41000cf542c50fef6",
+ "title": "Problem 119: Digit power sum"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-12-highly-divisible-triangular-number",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3781000cf542c50fe8b",
+ "title": "Problem 12: Highly divisible triangular number"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-120-square-remainders",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3e41000cf542c50fef7",
+ "title": "Problem 120: Square remainders"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-121-disc-game-prize-fund",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3e51000cf542c50fef8",
+ "title": "Problem 121: Disc game prize fund"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-122-efficient-exponentiation",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3e61000cf542c50fef9",
+ "title": "Problem 122: Efficient exponentiation"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-123-prime-square-remainders",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3e71000cf542c50fefa",
+ "title": "Problem 123: Prime square remainders"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-124-ordered-radicals",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3e81000cf542c50fefb",
+ "title": "Problem 124: Ordered radicals"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-125-palindromic-sums",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3e91000cf542c50fefc",
+ "title": "Problem 125: Palindromic sums"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-126-cuboid-layers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3ea1000cf542c50fefd",
+ "title": "Problem 126: Cuboid layers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-127-abc-hits",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3ec1000cf542c50fefe",
+ "title": "Problem 127: abc-hits"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-128-hexagonal-tile-differences",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3ec1000cf542c50feff",
+ "title": "Problem 128: Hexagonal tile differences"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-129-repunit-divisibility",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3ef1000cf542c50ff01",
+ "title": "Problem 129: Repunit divisibility"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-13-large-sum",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f37a1000cf542c50fe8c",
+ "title": "Problem 13: Large sum"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-130-composites-with-prime-repunit-property",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3ee1000cf542c50ff00",
+ "title": "Problem 130: Composites with prime repunit property"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-131-prime-cube-partnership",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3ef1000cf542c50ff02",
+ "title": "Problem 131: Prime cube partnership"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-132-large-repunit-factors",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3f11000cf542c50ff03",
+ "title": "Problem 132: Large repunit factors"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-133-repunit-nonfactors",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3f21000cf542c50ff04",
+ "title": "Problem 133: Repunit nonfactors"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-134-prime-pair-connection",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3f21000cf542c50ff05",
+ "title": "Problem 134: Prime pair connection"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-135-same-differences",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3f31000cf542c50ff06",
+ "title": "Problem 135: Same differences"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-136-singleton-difference",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3f51000cf542c50ff07",
+ "title": "Problem 136: Singleton difference"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-137-fibonacci-golden-nuggets",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3f51000cf542c50ff08",
+ "title": "Problem 137: Fibonacci golden nuggets"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-138-special-isosceles-triangles",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3f61000cf542c50ff09",
+ "title": "Problem 138: Special isosceles triangles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-139-pythagorean-tiles",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3f71000cf542c50ff0a",
+ "title": "Problem 139: Pythagorean tiles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-14-longest-collatz-sequence",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f37a1000cf542c50fe8d",
+ "title": "Problem 14: Longest Collatz sequence"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-140-modified-fibonacci-golden-nuggets",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3fa1000cf542c50ff0c",
+ "title": "Problem 140: Modified Fibonacci golden nuggets"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-141-investigating-progressive-numbers-n-which-are-also-square",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3f91000cf542c50ff0b",
+ "title": "Problem 141: Investigating progressive numbers, n, which are also square"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-142-perfect-square-collection",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3fa1000cf542c50ff0d",
+ "title": "Problem 142: Perfect Square Collection"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-143-investigating-the-torricelli-point-of-a-triangle",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3fc1000cf542c50ff0e",
+ "title": "Problem 143: Investigating the Torricelli point of a triangle"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-144-investigating-multiple-reflections-of-a-laser-beam",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3fc1000cf542c50ff0f",
+ "title": "Problem 144: Investigating multiple reflections of a laser beam"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-145-how-many-reversible-numbers-are-there-below-one-billion",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3fd1000cf542c50ff10",
+ "title": "Problem 145: How many reversible numbers are there below one-billion?"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-146-investigating-a-prime-pattern",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3fe1000cf542c50ff11",
+ "title": "Problem 146: Investigating a Prime Pattern"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-147-rectangles-in-cross-hatched-grids",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3ff1000cf542c50ff12",
+ "title": "Problem 147: Rectangles in cross-hatched grids"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-148-exploring-pascals-triangle",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4021000cf542c50ff14",
+ "title": "Problem 148: Exploring Pascal's triangle"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-149-searching-for-a-maximum-sum-subsequence",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4021000cf542c50ff13",
+ "title": "Problem 149: Searching for a maximum-sum subsequence"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-15-lattice-paths",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f37b1000cf542c50fe8e",
+ "title": "Problem 15: Lattice paths"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-150-searching-a-triangular-array-for-a-sub-triangle-having-minimum-sum",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4031000cf542c50ff15",
+ "title": "Problem 150: Searching a triangular array for a sub-triangle having minimum-sum"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-151-paper-sheets-of-standard-sizes-an-expected-value-problem",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4031000cf542c50ff16",
+ "title": "Problem 151: Paper sheets of standard sizes: an expected-value problem"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-152-writing-one-half-as-a-sum-of-inverse-squares",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4041000cf542c50ff17",
+ "title": "Problem 152: Writing one half as a sum of inverse squares"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-153-investigating-gaussian-integers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4051000cf542c50ff18",
+ "title": "Problem 153: Investigating Gaussian Integers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-154-exploring-pascals-pyramid",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4071000cf542c50ff19",
+ "title": "Problem 154: Exploring Pascal's pyramid"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-155-counting-capacitor-circuits",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4081000cf542c50ff1a",
+ "title": "Problem 155: Counting Capacitor Circuits"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-156-counting-digits",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4091000cf542c50ff1b",
+ "title": "Problem 156: Counting Digits"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-157-solving-the-diophantine-equation",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4091000cf542c50ff1c",
+ "title": "Problem 157: Solving the diophantine equation"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-158-exploring-strings-for-which-only-one-character-comes-lexicographically-after-its-neighbour-to-the-left",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f40a1000cf542c50ff1d",
+ "title": "Problem 158: Exploring strings for which only one character comes lexicographically after its neighbour to the left"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-159-digital-root-sums-of-factorisations",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f40c1000cf542c50ff1e",
+ "title": "Problem 159: Digital root sums of factorisations"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-16-power-digit-sum",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f37d1000cf542c50fe8f",
+ "title": "Problem 16: Power digit sum"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-160-factorial-trailing-digits",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f40d1000cf542c50ff1f",
+ "title": "Problem 160: Factorial trailing digits"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-161-triominoes",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f40d1000cf542c50ff20",
+ "title": "Problem 161: Triominoes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-162-hexadecimal-numbers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f40e1000cf542c50ff21",
+ "title": "Problem 162: Hexadecimal numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-163-cross-hatched-triangles",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f40f1000cf542c50ff22",
+ "title": "Problem 163: Cross-hatched triangles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-164-numbers-for-which-no-three-consecutive-digits-have-a-sum-greater-than-a-given-value",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4111000cf542c50ff23",
+ "title": "Problem 164: Numbers for which no three consecutive digits have a sum greater than a given value"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-165-intersections",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4111000cf542c50ff24",
+ "title": "Problem 165: Intersections"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-166-criss-cross",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4131000cf542c50ff25",
+ "title": "Problem 166: Criss Cross"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-167-investigating-ulam-sequences",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4141000cf542c50ff26",
+ "title": "Problem 167: Investigating Ulam sequences"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-168-number-rotations",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4151000cf542c50ff27",
+ "title": "Problem 168: Number Rotations"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-169-exploring-the-number-of-different-ways-a-number-can-be-expressed-as-a-sum-of-powers-of-2",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4151000cf542c50ff28",
+ "title": "Problem 169: Exploring the number of different ways a number can be expressed as a sum of powers of 2"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-17-number-letter-counts",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f37d1000cf542c50fe90",
+ "title": "Problem 17: Number letter counts"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-170-find-the-largest-0-to-9-pandigital-that-can-be-formed-by-concatenating-products",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4161000cf542c50ff29",
+ "title": "Problem 170: Find the largest 0 to 9 pandigital that can be formed by concatenating products"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-171-finding-numbers-for-which-the-sum-of-the-squares-of-the-digits-is-a-square",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4181000cf542c50ff2a",
+ "title": "Problem 171: Finding numbers for which the sum of the squares of the digits is a square"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-172-investigating-numbers-with-few-repeated-digits",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4181000cf542c50ff2b",
+ "title": "Problem 172: Investigating numbers with few repeated digits"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-173-using-up-to-one-million-tiles-how-many-different-hollow-square-laminae-can-be-formed",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f41a1000cf542c50ff2c",
+ "title": "Problem 173: Using up to one million tiles how many different \"hollow\" square laminae can be formed?"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-174-counting-the-number-of-hollow-square-laminae-that-can-form-one-two-three-----distinct-arrangements",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f41a1000cf542c50ff2d",
+ "title": "Problem 174: Counting the number of \"hollow\" square laminae that can form one, two, three, ... distinct arrangements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-175-fractions-involving-the-number-of-different-ways-a-number-can-be-expressed-as-a-sum-of-powers-of-2",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f41c1000cf542c50ff2e",
+ "title": "Problem 175: Fractions involving the number of different ways a number can be expressed as a sum of powers of 2"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-176-right-angled-triangles-that-share-a-cathetus",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f41c1000cf542c50ff2f",
+ "title": "Problem 176: Right-angled triangles that share a cathetus"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-177-integer-angled-quadrilaterals",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f41e1000cf542c50ff30",
+ "title": "Problem 177: Integer angled Quadrilaterals"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-178-step-numbers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f41e1000cf542c50ff31",
+ "title": "Problem 178: Step Numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-179-consecutive-positive-divisors",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f41f1000cf542c50ff32",
+ "title": "Problem 179: Consecutive positive divisors"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-18-maximum-path-sum-i",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f37e1000cf542c50fe91",
+ "title": "Problem 18: Maximum path sum I"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-180-rational-zeros-of-a-function-of-three-variables",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4201000cf542c50ff33",
+ "title": "Problem 180: Rational zeros of a function of three variables"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-181-investigating-in-how-many-ways-objects-of-two-different-colours-can-be-grouped",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4231000cf542c50ff34",
+ "title": "Problem 181: Investigating in how many ways objects of two different colours can be grouped"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-182-rsa-encryption",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4231000cf542c50ff35",
+ "title": "Problem 182: RSA encryption"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-183-maximum-product-of-parts",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4231000cf542c50ff36",
+ "title": "Problem 183: Maximum product of parts"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-184-triangles-containing-the-origin",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4241000cf542c50ff37",
+ "title": "Problem 184: Triangles containing the origin"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-185-number-mind",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4251000cf542c50ff38",
+ "title": "Problem 185: Number Mind"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-186-connectedness-of-a-network",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4281000cf542c50ff39",
+ "title": "Problem 186: Connectedness of a network"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-187-semiprimes",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4291000cf542c50ff3a",
+ "title": "Problem 187: Semiprimes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-188-the-hyperexponentiation-of-a-number",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4291000cf542c50ff3b",
+ "title": "Problem 188: The hyperexponentiation of a number"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-189-tri-colouring-a-triangular-grid",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4291000cf542c50ff3c",
+ "title": "Problem 189: Tri-colouring a triangular grid"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-19-counting-sundays",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f37f1000cf542c50fe92",
+ "title": "Problem 19: Counting Sundays"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-190-maximising-a-weighted-product",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f42b1000cf542c50ff3d",
+ "title": "Problem 190: Maximising a weighted product"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-191-prize-strings",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f42b1000cf542c50ff3e",
+ "title": "Problem 191: Prize Strings"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-192-best-approximations",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f42c1000cf542c50ff3f",
+ "title": "Problem 192: Best Approximations"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-193-squarefree-numbers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f42f1000cf542c50ff41",
+ "title": "Problem 193: Squarefree Numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-194-coloured-configurations",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f42f1000cf542c50ff40",
+ "title": "Problem 194: Coloured Configurations"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-195-inscribed-circles-of-triangles-with-one-angle-of-60-degrees",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4311000cf542c50ff43",
+ "title": "Problem 195: Inscribed circles of triangles with one angle of 60 degrees"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-196-prime-triplets",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4301000cf542c50ff42",
+ "title": "Problem 196: Prime triplets"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-197-investigating-the-behaviour-of-a-recursively-defined-sequence",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4311000cf542c50ff44",
+ "title": "Problem 197: Investigating the behaviour of a recursively defined sequence"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-198-ambiguous-numbers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4331000cf542c50ff45",
+ "title": "Problem 198: Ambiguous Numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-199-iterative-circle-packing",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4341000cf542c50ff46",
+ "title": "Problem 199: Iterative Circle Packing"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-2-even-fibonacci-numbers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f36e1000cf542c50fe81",
+ "title": "Problem 2: Even Fibonacci Numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-20-factorial-digit-sum",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3801000cf542c50fe93",
+ "title": "Problem 20: Factorial digit sum"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-200-find-the-200th-prime-proof-sqube-containing-the-contiguous-sub-string-200",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4351000cf542c50ff47",
+ "title": "Problem 200: Find the 200th prime-proof sqube containing the contiguous sub-string \"200\""
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-201-subsets-with-a-unique-sum",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4361000cf542c50ff48",
+ "title": "Problem 201: Subsets with a unique sum"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-202-laserbeam",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4371000cf542c50ff49",
+ "title": "Problem 202: Laserbeam"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-203-squarefree-binomial-coefficients",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4381000cf542c50ff4a",
+ "title": "Problem 203: Squarefree Binomial Coefficients"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-204-generalised-hamming-numbers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4381000cf542c50ff4b",
+ "title": "Problem 204: Generalised Hamming Numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-205-dice-game",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4391000cf542c50ff4c",
+ "title": "Problem 205: Dice Game"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-206-concealed-square",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f43a1000cf542c50ff4d",
+ "title": "Problem 206: Concealed Square"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-207-integer-partition-equations",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f43c1000cf542c50ff4e",
+ "title": "Problem 207: Integer partition equations"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-208-robot-walks",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f43f1000cf542c50ff51",
+ "title": "Problem 208: Robot Walks"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-209-circular-logic",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f43e1000cf542c50ff4f",
+ "title": "Problem 209: Circular Logic"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-21-amicable-numbers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3811000cf542c50fe94",
+ "title": "Problem 21: Amicable numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-210-obtuse-angled-triangles",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f43e1000cf542c50ff50",
+ "title": "Problem 210: Obtuse Angled Triangles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-211-divisor-square-sum",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f43f1000cf542c50ff52",
+ "title": "Problem 211: Divisor Square Sum"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-212-combined-volume-of-cuboids",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4411000cf542c50ff53",
+ "title": "Problem 212: Combined Volume of Cuboids"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-213-flea-circus",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4411000cf542c50ff54",
+ "title": "Problem 213: Flea Circus"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-214-totient-chains",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4421000cf542c50ff55",
+ "title": "Problem 214: Totient Chains"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-215-crack-free-walls",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4431000cf542c50ff56",
+ "title": "Problem 215: Crack-free Walls"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-216-investigating-the-primality-of-numbers-of-the-form-2n2-1",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4451000cf542c50ff57",
+ "title": "Problem 216: Investigating the primality of numbers of the form 2n2-1"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-217-balanced-numbers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4461000cf542c50ff58",
+ "title": "Problem 217: Balanced Numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-218-perfect-right-angled-triangles",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4461000cf542c50ff59",
+ "title": "Problem 218: Perfect right-angled triangles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-219-skew-cost-coding",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4481000cf542c50ff5a",
+ "title": "Problem 219: Skew-cost coding"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-22-names-scores",
+ "blockName": "Project Euler"
+ },
+ "id": "5a51eabcad78bf416f316e2a",
+ "title": "Problem 22: Names scores"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-220-heighway-dragon",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4481000cf542c50ff5b",
+ "title": "Problem 220: Heighway Dragon"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-221-alexandrian-integers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4491000cf542c50ff5c",
+ "title": "Problem 221: Alexandrian Integers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-222-sphere-packing",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f44b1000cf542c50ff5d",
+ "title": "Problem 222: Sphere Packing"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-223-almost-right-angled-triangles-i",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f44b1000cf542c50ff5e",
+ "title": "Problem 223: Almost right-angled triangles I"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-224-almost-right-angled-triangles-ii",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f44e1000cf542c50ff5f",
+ "title": "Problem 224: Almost right-angled triangles II"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-225-tribonacci-non-divisors",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f44e1000cf542c50ff60",
+ "title": "Problem 225: Tribonacci non-divisors"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-226-a-scoop-of-blancmange",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4511000cf542c50ff62",
+ "title": "Problem 226: A Scoop of Blancmange"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-227-the-chase",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f44f1000cf542c50ff61",
+ "title": "Problem 227: The Chase"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-228-minkowski-sums",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4511000cf542c50ff63",
+ "title": "Problem 228: Minkowski Sums"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-229-four-representations-using-squares",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4521000cf542c50ff64",
+ "title": "Problem 229: Four Representations using Squares"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-23-non-abundant-sums",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3831000cf542c50fe96",
+ "title": "Problem 23: Non-abundant sums"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-230-fibonacci-words",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4531000cf542c50ff65",
+ "title": "Problem 230: Fibonacci Words"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-231-the-prime-factorisation-of-binomial-coefficients",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4531000cf542c50ff66",
+ "title": "Problem 231: The prime factorisation of binomial coefficients"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-232-the-race",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4551000cf542c50ff67",
+ "title": "Problem 232: The Race"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-233-lattice-points-on-a-circle",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4551000cf542c50ff68",
+ "title": "Problem 233: Lattice points on a circle"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-234-semidivisible-numbers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4571000cf542c50ff69",
+ "title": "Problem 234: Semidivisible numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-235-an-arithmetic-geometric-sequence",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4571000cf542c50ff6a",
+ "title": "Problem 235: An Arithmetic Geometric sequence"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-236-luxury-hampers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4591000cf542c50ff6b",
+ "title": "Problem 236: Luxury Hampers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-237-tours-on-a-4-x-n-playing-board",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4591000cf542c50ff6c",
+ "title": "Problem 237: Tours on a 4 x n playing board"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-238-infinite-string-tour",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f45b1000cf542c50ff6d",
+ "title": "Problem 238: Infinite string tour"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-239-twenty-two-foolish-primes",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f45c1000cf542c50ff6e",
+ "title": "Problem 239: Twenty-two Foolish Primes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-24-lexicographic-permutations",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3841000cf542c50fe97",
+ "title": "Problem 24: Lexicographic permutations"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-240-top-dice",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f45d1000cf542c50ff6f",
+ "title": "Problem 240: Top Dice"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-241-perfection-quotients",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f45d1000cf542c50ff70",
+ "title": "Problem 241: Perfection Quotients"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-242-odd-triplets",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f45f1000cf542c50ff71",
+ "title": "Problem 242: Odd Triplets"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-243-resilience",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4601000cf542c50ff73",
+ "title": "Problem 243: Resilience"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-244-sliders",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4601000cf542c50ff72",
+ "title": "Problem 244: Sliders"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-245-coresilience",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4621000cf542c50ff74",
+ "title": "Problem 245: Coresilience"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-246-tangents-to-an-ellipse",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4621000cf542c50ff75",
+ "title": "Problem 246: Tangents to an ellipse"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-247-squares-under-a-hyperbola",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4641000cf542c50ff76",
+ "title": "Problem 247: Squares under a hyperbola"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-248-numbers-for-which-eulers-totient-function-equals-13",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4651000cf542c50ff77",
+ "title": "Problem 248: Numbers for which Euler’s totient function equals 13!"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-249-prime-subset-sums",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4671000cf542c50ff79",
+ "title": "Problem 249: Prime Subset Sums"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-25-1000-digit-fibonacci-number",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3851000cf542c50fe98",
+ "title": "Problem 25: 1000-digit Fibonacci number"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-250-250250",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4661000cf542c50ff78",
+ "title": "Problem 250: 250250"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-251-cardano-triplets",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4671000cf542c50ff7a",
+ "title": "Problem 251: Cardano Triplets"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-252-convex-holes",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4691000cf542c50ff7b",
+ "title": "Problem 252: Convex Holes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-253-tidying-up",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4691000cf542c50ff7c",
+ "title": "Problem 253: Tidying up"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-254-sums-of-digit-factorials",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f46b1000cf542c50ff7d",
+ "title": "Problem 254: Sums of Digit Factorials"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-255-rounded-square-roots",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f46d1000cf542c50ff7f",
+ "title": "Problem 255: Rounded Square Roots"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-256-tatami-free-rooms",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f46c1000cf542c50ff7e",
+ "title": "Problem 256: Tatami-Free Rooms"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-257-angular-bisectors",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f46e1000cf542c50ff80",
+ "title": "Problem 257: Angular Bisectors"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-258-a-lagged-fibonacci-sequence",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f46e1000cf542c50ff81",
+ "title": "Problem 258: A lagged Fibonacci sequence"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-259-reachable-numbers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4701000cf542c50ff82",
+ "title": "Problem 259: Reachable Numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-26-reciprocal-cycles",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3861000cf542c50fe99",
+ "title": "Problem 26: Reciprocal cycles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-260-stone-game",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4701000cf542c50ff83",
+ "title": "Problem 260: Stone Game"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-261-pivotal-square-sums",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4711000cf542c50ff84",
+ "title": "Problem 261: Pivotal Square Sums"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-262-mountain-range",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4731000cf542c50ff85",
+ "title": "Problem 262: Mountain Range"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-263-an-engineers-dream-come-true",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4741000cf542c50ff86",
+ "title": "Problem 263: An engineers' dream come true"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-264-triangle-centres",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4751000cf542c50ff87",
+ "title": "Problem 264: Triangle Centres"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-265-binary-circles",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4761000cf542c50ff88",
+ "title": "Problem 265: Binary Circles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-266-pseudo-square-root",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4771000cf542c50ff89",
+ "title": "Problem 266: Pseudo Square Root"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-267-billionaire",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4771000cf542c50ff8a",
+ "title": "Problem 267: Billionaire"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-268-counting-numbers-with-at-least-four-distinct-prime-factors-less-than-100",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4791000cf542c50ff8b",
+ "title": "Problem 268: Counting numbers with at least four distinct prime factors less than 100"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-269-polynomials-with-at-least-one-integer-root",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4791000cf542c50ff8c",
+ "title": "Problem 269: Polynomials with at least one integer root"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-27-quadratic-primes",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3871000cf542c50fe9a",
+ "title": "Problem 27: Quadratic primes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-270-cutting-squares",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f47c1000cf542c50ff8e",
+ "title": "Problem 270: Cutting Squares"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-271-modular-cubes-part-1",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f47b1000cf542c50ff8d",
+ "title": "Problem 271: Modular Cubes, part 1"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-272-modular-cubes-part-2",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f47d1000cf542c50ff8f",
+ "title": "Problem 272: Modular Cubes, part 2"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-273-sum-of-squares",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f47e1000cf542c50ff90",
+ "title": "Problem 273: Sum of Squares"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-274-divisibility-multipliers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f47f1000cf542c50ff91",
+ "title": "Problem 274: Divisibility Multipliers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-275-balanced-sculptures",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4801000cf542c50ff92",
+ "title": "Problem 275: Balanced Sculptures"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-276-primitive-triangles",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4801000cf542c50ff93",
+ "title": "Problem 276: Primitive Triangles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-277-a-modified-collatz-sequence",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4811000cf542c50ff94",
+ "title": "Problem 277: A Modified Collatz sequence"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-278-linear-combinations-of-semiprimes",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4831000cf542c50ff95",
+ "title": "Problem 278: Linear Combinations of Semiprimes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-279-triangles-with-integral-sides-and-an-integral-angle",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4841000cf542c50ff96",
+ "title": "Problem 279: Triangles with integral sides and an integral angle"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-28-number-spiral-diagonals",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3881000cf542c50fe9b",
+ "title": "Problem 28: Number spiral diagonals"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-280-ant-and-seeds",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4841000cf542c50ff97",
+ "title": "Problem 280: Ant and seeds"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-281-pizza-toppings",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4861000cf542c50ff98",
+ "title": "Problem 281: Pizza Toppings"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-282-the-ackermann-function",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4861000cf542c50ff99",
+ "title": "Problem 282: The Ackermann function"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-283-integer-sided-triangles-for-which-the-area--perimeter-ratio-is-integral",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4881000cf542c50ff9a",
+ "title": "Problem 283: Integer sided triangles for which the area / perimeter ratio is integral"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-284-steady-squares",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4891000cf542c50ff9b",
+ "title": "Problem 284: Steady Squares"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-285-pythagorean-odds",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f48a1000cf542c50ff9c",
+ "title": "Problem 285: Pythagorean odds"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-286-scoring-probabilities",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f48a1000cf542c50ff9d",
+ "title": "Problem 286: Scoring probabilities"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-287-quadtree-encoding-a-simple-compression-algorithm",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f48b1000cf542c50ff9e",
+ "title": "Problem 287: Quadtree encoding (a simple compression algorithm)"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-288-an-enormous-factorial",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f48d1000cf542c50ff9f",
+ "title": "Problem 288: An enormous factorial"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-289-eulerian-cycles",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f48d1000cf542c50ffa0",
+ "title": "Problem 289: Eulerian Cycles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-29-distinct-powers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3891000cf542c50fe9c",
+ "title": "Problem 29: Distinct powers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-290-digital-signature",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f48f1000cf542c50ffa1",
+ "title": "Problem 290: Digital Signature"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-291-panaitopol-primes",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f48f1000cf542c50ffa2",
+ "title": "Problem 291: Panaitopol Primes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-292-pythagorean-polygons",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4911000cf542c50ffa3",
+ "title": "Problem 292: Pythagorean Polygons"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-293-pseudo-fortunate-numbers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4931000cf542c50ffa4",
+ "title": "Problem 293: Pseudo-Fortunate Numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-294-sum-of-digits---experience-23",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4931000cf542c50ffa5",
+ "title": "Problem 294: Sum of digits - experience #23"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-295-lenticular-holes",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4931000cf542c50ffa6",
+ "title": "Problem 295: Lenticular holes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-296-angular-bisector-and-tangent",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4941000cf542c50ffa7",
+ "title": "Problem 296: Angular Bisector and Tangent"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-297-zeckendorf-representation",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4951000cf542c50ffa8",
+ "title": "Problem 297: Zeckendorf Representation"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-298-selective-amnesia",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4971000cf542c50ffa9",
+ "title": "Problem 298: Selective Amnesia"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-299-three-similar-triangles",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4971000cf542c50ffaa",
+ "title": "Problem 299: Three similar triangles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-3-largest-prime-factor",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f36f1000cf542c50fe82",
+ "title": "Problem 3: Largest prime factor"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-30-digit-n-powers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f38a1000cf542c50fe9d",
+ "title": "Problem 30: Digit n powers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-300-protein-folding",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f49a1000cf542c50ffac",
+ "title": "Problem 300: Protein folding"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-301-nim",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4991000cf542c50ffab",
+ "title": "Problem 301: Nim"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-302-strong-achilles-numbers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f49b1000cf542c50ffad",
+ "title": "Problem 302: Strong Achilles Numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-303-multiples-with-small-digits",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f49b1000cf542c50ffae",
+ "title": "Problem 303: Multiples with small digits"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-304-primonacci",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f49d1000cf542c50ffaf",
+ "title": "Problem 304: Primonacci"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-305-reflexive-position",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f49d1000cf542c50ffb0",
+ "title": "Problem 305: Reflexive Position"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-306-paper-strip-game",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f49f1000cf542c50ffb1",
+ "title": "Problem 306: Paper-strip Game"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-307-chip-defects",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4a01000cf542c50ffb2",
+ "title": "Problem 307: Chip Defects"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-308-an-amazing-prime-generating-automaton",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4a11000cf542c50ffb3",
+ "title": "Problem 308: An amazing Prime-generating Automaton"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-309-integer-ladders",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4a11000cf542c50ffb4",
+ "title": "Problem 309: Integer Ladders"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-31-coin-sums",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f38b1000cf542c50fe9e",
+ "title": "Problem 31: Coin sums"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-310-nim-square",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4a21000cf542c50ffb5",
+ "title": "Problem 310: Nim Square"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-311-biclinic-integral-quadrilaterals",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4a31000cf542c50ffb6",
+ "title": "Problem 311: Biclinic Integral Quadrilaterals"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-312-cyclic-paths-on-sierpiski-graphs",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4a51000cf542c50ffb7",
+ "title": "Problem 312: Cyclic paths on Sierpiński graphs"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-313-sliding-game",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4a61000cf542c50ffb8",
+ "title": "Problem 313: Sliding game"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-314-the-mouse-on-the-moon",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4a71000cf542c50ffb9",
+ "title": "Problem 314: The Mouse on the Moon"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-315-digital-root-clocks",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4a71000cf542c50ffba",
+ "title": "Problem 315: Digital root clocks"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-316-numbers-in-decimal-expansions",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4a81000cf542c50ffbb",
+ "title": "Problem 316: Numbers in decimal expansions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-317-firecracker",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4aa1000cf542c50ffbc",
+ "title": "Problem 317: Firecracker"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-318-2011-nines",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4ab1000cf542c50ffbd",
+ "title": "Problem 318: 2011 nines"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-319-bounded-sequences",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4ab1000cf542c50ffbe",
+ "title": "Problem 319: Bounded Sequences"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-32-pandigital-products",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f38c1000cf542c50fe9f",
+ "title": "Problem 32: Pandigital products"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-320-factorials-divisible-by-a-huge-integer",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4ae1000cf542c50ffbf",
+ "title": "Problem 320: Factorials divisible by a huge integer"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-321-swapping-counters",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4ae1000cf542c50ffc0",
+ "title": "Problem 321: Swapping Counters"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-322-binomial-coefficients-divisible-by-10",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4af1000cf542c50ffc1",
+ "title": "Problem 322: Binomial coefficients divisible by 10"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-323-bitwise-or-operations-on-random-integers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4b01000cf542c50ffc2",
+ "title": "Problem 323: Bitwise-OR operations on random integers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-324-building-a-tower",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4b11000cf542c50ffc3",
+ "title": "Problem 324: Building a tower"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-325-stone-game-ii",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4b11000cf542c50ffc4",
+ "title": "Problem 325: Stone Game II"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-326-modulo-summations",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4b21000cf542c50ffc5",
+ "title": "Problem 326: Modulo Summations"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-327-rooms-of-doom",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4b31000cf542c50ffc6",
+ "title": "Problem 327: Rooms of Doom"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-328-lowest-cost-search",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4b41000cf542c50ffc7",
+ "title": "Problem 328: Lowest-cost Search"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-329-prime-frog",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4b51000cf542c50ffc8",
+ "title": "Problem 329: Prime Frog"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-33-digit-cancelling-fractions",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f38d1000cf542c50fea0",
+ "title": "Problem 33: Digit cancelling fractions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-330-eulers-number",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4b71000cf542c50ffc9",
+ "title": "Problem 330: Euler's Number"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-331-cross-flips",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4b71000cf542c50ffca",
+ "title": "Problem 331: Cross flips"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-332-spherical-triangles",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4b91000cf542c50ffcb",
+ "title": "Problem 332: Spherical triangles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-333-special-partitions",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4b91000cf542c50ffcc",
+ "title": "Problem 333: Special partitions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-334-spilling-the-beans",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4ba1000cf542c50ffcd",
+ "title": "Problem 334: Spilling the beans"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-335-gathering-the-beans",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4bd1000cf542c50ffce",
+ "title": "Problem 335: Gathering the beans"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-336-maximix-arrangements",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4bd1000cf542c50ffcf",
+ "title": "Problem 336: Maximix Arrangements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-337-totient-stairstep-sequences",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4be1000cf542c50ffd0",
+ "title": "Problem 337: Totient Stairstep Sequences"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-338-cutting-rectangular-grid-paper",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4be1000cf542c50ffd1",
+ "title": "Problem 338: Cutting Rectangular Grid Paper"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-339-peredur-fab-efrawg",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4c01000cf542c50ffd2",
+ "title": "Problem 339: Peredur fab Efrawg"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-34-digit-factorials",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f38e1000cf542c50fea1",
+ "title": "Problem 34: Digit factorials"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-340-crazy-function",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4c21000cf542c50ffd4",
+ "title": "Problem 340: Crazy Function"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-341-golombs-self-describing-sequence",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4c11000cf542c50ffd3",
+ "title": "Problem 341: Golomb's self-describing sequence"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-342-the-totient-of-a-square-is-a-cube",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4c31000cf542c50ffd5",
+ "title": "Problem 342: The totient of a square is a cube"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-343-fractional-sequences",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4c41000cf542c50ffd6",
+ "title": "Problem 343: Fractional Sequences"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-344-silver-dollar-game",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4c51000cf542c50ffd7",
+ "title": "Problem 344: Silver dollar game"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-345-matrix-sum",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4c81000cf542c50ffda",
+ "title": "Problem 345: Matrix Sum"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-346-strong-repunits",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4c71000cf542c50ffd8",
+ "title": "Problem 346: Strong Repunits"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-347-largest-integer-divisible-by-two-primes",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4c81000cf542c50ffd9",
+ "title": "Problem 347: Largest integer divisible by two primes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-348-sum-of-a-square-and-a-cube",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4c81000cf542c50ffdb",
+ "title": "Problem 348: Sum of a square and a cube"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-349-langtons-ant",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4ca1000cf542c50ffdc",
+ "title": "Problem 349: Langton's ant"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-35-circular-primes",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f38f1000cf542c50fea2",
+ "title": "Problem 35: Circular primes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-350-constraining-the-least-greatest-and-the-greatest-least",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4cb1000cf542c50ffdd",
+ "title": "Problem 350: Constraining the least greatest and the greatest least"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-351-hexagonal-orchards",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4cb1000cf542c50ffde",
+ "title": "Problem 351: Hexagonal orchards"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-352-blood-tests",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4cd1000cf542c50ffdf",
+ "title": "Problem 352: Blood tests"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-353-risky-moon",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4cd1000cf542c50ffe0",
+ "title": "Problem 353: Risky moon"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-354-distances-in-a-bees-honeycomb",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4cf1000cf542c50ffe1",
+ "title": "Problem 354: Distances in a bee's honeycomb"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-355-maximal-coprime-subset",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4d01000cf542c50ffe2",
+ "title": "Problem 355: Maximal coprime subset"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-356-largest-roots-of-cubic-polynomials",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4d01000cf542c50ffe3",
+ "title": "Problem 356: Largest roots of cubic polynomials"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-357-prime-generating-integers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4d11000cf542c50ffe4",
+ "title": "Problem 357: Prime generating integers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-358-cyclic-numbers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4d21000cf542c50ffe5",
+ "title": "Problem 358: Cyclic numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-359-hilberts-new-hotel",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4d31000cf542c50ffe6",
+ "title": "Problem 359: Hilbert's New Hotel"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-36-double-base-palindromes",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3901000cf542c50fea3",
+ "title": "Problem 36: Double-base palindromes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-360-scary-sphere",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4d41000cf542c50ffe7",
+ "title": "Problem 360: Scary Sphere"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-361-subsequence-of-thue-morse-sequence",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4d51000cf542c50ffe8",
+ "title": "Problem 361: Subsequence of Thue-Morse sequence"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-362-squarefree-factors",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4d61000cf542c50ffe9",
+ "title": "Problem 362: Squarefree factors"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-363-bzier-curves",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4d91000cf542c50ffeb",
+ "title": "Problem 363: Bézier Curves"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-364-comfortable-distance",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4d91000cf542c50ffea",
+ "title": "Problem 364: Comfortable distance"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-365-a-huge-binomial-coefficient",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4da1000cf542c50ffec",
+ "title": "Problem 365: A huge binomial coefficient"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-366-stone-game-iii",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4da1000cf542c50ffed",
+ "title": "Problem 366: Stone Game III"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-367-bozo-sort",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4db1000cf542c50ffee",
+ "title": "Problem 367: Bozo sort"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-368-a-kempner-like-series",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4dd1000cf542c50ffef",
+ "title": "Problem 368: A Kempner-like series"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-369-badugi",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4de1000cf542c50fff0",
+ "title": "Problem 369: Badugi"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-37-truncatable-primes",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3911000cf542c50fea4",
+ "title": "Problem 37: Truncatable primes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-370-geometric-triangles",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4de1000cf542c50fff1",
+ "title": "Problem 370: Geometric triangles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-371-licence-plates",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4e01000cf542c50fff2",
+ "title": "Problem 371: Licence plates"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-372-pencils-of-rays",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4e11000cf542c50fff3",
+ "title": "Problem 372: Pencils of rays"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-373-circumscribed-circles",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4e11000cf542c50fff4",
+ "title": "Problem 373: Circumscribed Circles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-374-maximum-integer-partition-product",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4e51000cf542c50fff6",
+ "title": "Problem 374: Maximum Integer Partition Product"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-375-minimum-of-subsequences",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4e41000cf542c50fff5",
+ "title": "Problem 375: Minimum of subsequences"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-376-nontransitive-sets-of-dice",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4e51000cf542c50fff7",
+ "title": "Problem 376: Nontransitive sets of dice"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-377-sum-of-digits-experience-13",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4e51000cf542c50fff8",
+ "title": "Problem 377: Sum of digits, experience 13"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-378-triangle-triples",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4e61000cf542c50fff9",
+ "title": "Problem 378: Triangle Triples"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-379-least-common-multiple-count",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4e81000cf542c50fffa",
+ "title": "Problem 379: Least common multiple count"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-38-pandigital-multiples",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3931000cf542c50fea5",
+ "title": "Problem 38: Pandigital multiples"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-380-amazing-mazes",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4e81000cf542c50fffb",
+ "title": "Problem 380: Amazing Mazes!"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-381-prime-k-factorial",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4ea1000cf542c50fffc",
+ "title": "Problem 381: (prime-k) factorial"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-382-generating-polygons",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4eb1000cf542c50fffd",
+ "title": "Problem 382: Generating polygons"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-383-divisibility-comparison-between-factorials",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4ed1000cf542c50ffff",
+ "title": "Problem 383: Divisibility comparison between factorials"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-384-rudin-shapiro-sequence",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4ed1000cf542c50fffe",
+ "title": "Problem 384: Rudin-Shapiro sequence"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-385-ellipses-inside-triangles",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4ee1000cf542c510000",
+ "title": "Problem 385: Ellipses inside triangles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-386-maximum-length-of-an-antichain",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4ef1000cf542c510001",
+ "title": "Problem 386: Maximum length of an antichain"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-387-harshad-numbers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4f11000cf542c510003",
+ "title": "Problem 387: Harshad Numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-388-distinct-lines",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4f11000cf542c510002",
+ "title": "Problem 388: Distinct Lines"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-389-platonic-dice",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4f21000cf542c510004",
+ "title": "Problem 389: Platonic Dice"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-39-integer-right-triangles",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3931000cf542c50fea6",
+ "title": "Problem 39: Integer right triangles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-390-triangles-with-non-rational-sides-and-integral-area",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4f21000cf542c510005",
+ "title": "Problem 390: Triangles with non rational sides and integral area"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-391-hopping-game",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4f31000cf542c510006",
+ "title": "Problem 391: Hopping Game"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-392-enmeshed-unit-circle",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4f41000cf542c510007",
+ "title": "Problem 392: Enmeshed unit circle"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-393-migrating-ants",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4f61000cf542c510008",
+ "title": "Problem 393: Migrating ants"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-394-eating-pie",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4f71000cf542c510009",
+ "title": "Problem 394: Eating pie"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-395-pythagorean-tree",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4f71000cf542c51000a",
+ "title": "Problem 395: Pythagorean tree"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-396-weak-goodstein-sequence",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4f81000cf542c51000b",
+ "title": "Problem 396: Weak Goodstein sequence"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-397-triangle-on-parabola",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4f91000cf542c51000c",
+ "title": "Problem 397: Triangle on parabola"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-398-cutting-rope",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4fa1000cf542c51000d",
+ "title": "Problem 398: Cutting rope"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-399-squarefree-fibonacci-numbers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4fc1000cf542c51000e",
+ "title": "Problem 399: Squarefree Fibonacci Numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-4-largest-palindrome-product",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3701000cf542c50fe83",
+ "title": "Problem 4: Largest palindrome product"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-40-champernownes-constant",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3941000cf542c50fea7",
+ "title": "Problem 40: Champernowne's constant"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-400-fibonacci-tree-game",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4fe1000cf542c510010",
+ "title": "Problem 400: Fibonacci tree game"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-401-sum-of-squares-of-divisors",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4fd1000cf542c51000f",
+ "title": "Problem 401: Sum of squares of divisors"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-402-integer-valued-polynomials",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f4ff1000cf542c510011",
+ "title": "Problem 402: Integer-valued polynomials"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-403-lattice-points-enclosed-by-parabola-and-line",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5001000cf542c510013",
+ "title": "Problem 403: Lattice points enclosed by parabola and line"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-404-crisscross-ellipses",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5001000cf542c510012",
+ "title": "Problem 404: Crisscross Ellipses"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-405-a-rectangular-tiling",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5021000cf542c510014",
+ "title": "Problem 405: A rectangular tiling"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-406-guessing-game",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5021000cf542c510015",
+ "title": "Problem 406: Guessing Game"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-407-idempotents",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5041000cf542c510016",
+ "title": "Problem 407: Idempotents"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-408-admissible-paths-through-a-grid",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5091000cf542c51001b",
+ "title": "Problem 408: Admissible paths through a grid"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-409-nim-extreme",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5061000cf542c510017",
+ "title": "Problem 409: Nim Extreme"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-41-pandigital-prime",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3951000cf542c50fea8",
+ "title": "Problem 41: Pandigital prime"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-410-circle-and-tangent-line",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5071000cf542c510018",
+ "title": "Problem 410: Circle and tangent line"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-411-uphill-paths",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5081000cf542c510019",
+ "title": "Problem 411: Uphill paths"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-412-gnomon-numbering",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5081000cf542c51001a",
+ "title": "Problem 412: Gnomon numbering"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-413-one-child-numbers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f50a1000cf542c51001c",
+ "title": "Problem 413: One-child Numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-414-kaprekar-constant",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f50b1000cf542c51001d",
+ "title": "Problem 414: Kaprekar constant"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-415-titanic-sets",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f50c1000cf542c51001e",
+ "title": "Problem 415: Titanic sets"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-416-a-frogs-trip",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f50e1000cf542c510020",
+ "title": "Problem 416: A frog's trip"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-417-reciprocal-cycles-ii",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f50d1000cf542c51001f",
+ "title": "Problem 417: Reciprocal cycles II"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-418-factorisation-triples",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f50f1000cf542c510021",
+ "title": "Problem 418: Factorisation triples"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-419-look-and-say-sequence",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5101000cf542c510022",
+ "title": "Problem 419: Look and say sequence"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-42-coded-triangle-numbers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3961000cf542c50fea9",
+ "title": "Problem 42: Coded triangle numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-420-2x2-positive-integer-matrix",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5111000cf542c510023",
+ "title": "Problem 420: 2x2 positive integer matrix"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-421-prime-factors-of-n151",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5131000cf542c510024",
+ "title": "Problem 421: Prime factors of n^15+1"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-422-sequence-of-points-on-a-hyperbola",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5131000cf542c510025",
+ "title": "Problem 422: Sequence of points on a hyperbola"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-423-consecutive-die-throws",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5141000cf542c510027",
+ "title": "Problem 423: Consecutive die throws"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-424-kakuro",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5141000cf542c510026",
+ "title": "Problem 424: Kakuro"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-425-prime-connection",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5151000cf542c510028",
+ "title": "Problem 425: Prime connection"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-426-box-ball-system",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5171000cf542c510029",
+ "title": "Problem 426: Box-ball system"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-427-n-sequences",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5181000cf542c51002a",
+ "title": "Problem 427: n-sequences"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-428-necklace-of-circles",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5191000cf542c51002b",
+ "title": "Problem 428: Necklace of Circles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-429-sum-of-squares-of-unitary-divisors",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5191000cf542c51002c",
+ "title": "Problem 429: Sum of squares of unitary divisors"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-43-sub-string-divisibility",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3971000cf542c50feaa",
+ "title": "Problem 43: Sub-string divisibility"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-430-range-flips",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f51a1000cf542c51002d",
+ "title": "Problem 430: Range flips"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-431-square-space-silo",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f51b1000cf542c51002e",
+ "title": "Problem 431: Square Space Silo"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-432-totient-sum",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f51e1000cf542c510030",
+ "title": "Problem 432: Totient sum"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-433-steps-in-euclids-algorithm",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f51d1000cf542c51002f",
+ "title": "Problem 433: Steps in Euclid's algorithm"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-434-rigid-graphs",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f51f1000cf542c510031",
+ "title": "Problem 434: Rigid graphs"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-435-polynomials-of-fibonacci-numbers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5201000cf542c510032",
+ "title": "Problem 435: Polynomials of Fibonacci numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-436-unfair-wager",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5221000cf542c510033",
+ "title": "Problem 436: Unfair wager"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-437-fibonacci-primitive-roots",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5241000cf542c510036",
+ "title": "Problem 437: Fibonacci primitive roots"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-438-integer-part-of-polynomial-equations-solutions",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5231000cf542c510034",
+ "title": "Problem 438: Integer part of polynomial equation's solutions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-439-sum-of-sum-of-divisors",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5231000cf542c510035",
+ "title": "Problem 439: Sum of sum of divisors"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-44-pentagon-numbers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3981000cf542c50feab",
+ "title": "Problem 44: Pentagon numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-440-gcd-and-tiling",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5241000cf542c510037",
+ "title": "Problem 440: GCD and Tiling"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-441-the-inverse-summation-of-coprime-couples",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5261000cf542c510038",
+ "title": "Problem 441: The inverse summation of coprime couples"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-442-eleven-free-integers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5271000cf542c510039",
+ "title": "Problem 442: Eleven-free integers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-443-gcd-sequence",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5271000cf542c51003a",
+ "title": "Problem 443: GCD sequence"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-444-the-roundtable-lottery",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f52a1000cf542c51003b",
+ "title": "Problem 444: The Roundtable Lottery"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-445-retractions-a",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f52a1000cf542c51003c",
+ "title": "Problem 445: Retractions A"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-446-retractions-b",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f52c1000cf542c51003d",
+ "title": "Problem 446: Retractions B"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-447-retractions-c",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f52c1000cf542c51003e",
+ "title": "Problem 447: Retractions C"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-448-average-least-common-multiple",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f52c1000cf542c51003f",
+ "title": "Problem 448: Average least common multiple"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-449-chocolate-covered-candy",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f52d1000cf542c510040",
+ "title": "Problem 449: Chocolate covered candy"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-45-triangular-pentagonal-and-hexagonal",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3991000cf542c50feac",
+ "title": "Problem 45: Triangular, pentagonal, and hexagonal"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-450-hypocycloid-and-lattice-points",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f52e1000cf542c510041",
+ "title": "Problem 450: Hypocycloid and Lattice points"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-451-modular-inverses",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5311000cf542c510042",
+ "title": "Problem 451: Modular inverses"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-452-long-products",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5311000cf542c510043",
+ "title": "Problem 452: Long Products"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-453-lattice-quadrilaterals",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5311000cf542c510044",
+ "title": "Problem 453: Lattice Quadrilaterals"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-454-diophantine-reciprocals-iii",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5331000cf542c510045",
+ "title": "Problem 454: Diophantine reciprocals III"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-455-powers-with-trailing-digits",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5331000cf542c510046",
+ "title": "Problem 455: Powers With Trailing Digits"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-456-triangles-containing-the-origin-ii",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5351000cf542c510047",
+ "title": "Problem 456: Triangles containing the origin II"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-457-a-polynomial-modulo-the-square-of-a-prime",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5361000cf542c510048",
+ "title": "Problem 457: A polynomial modulo the square of a prime"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-458-permutations-of-project",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5361000cf542c510049",
+ "title": "Problem 458: Permutations of Project"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-459-flipping-game",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5371000cf542c51004a",
+ "title": "Problem 459: Flipping game"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-46-goldbachs-other-conjecture",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f39a1000cf542c50fead",
+ "title": "Problem 46: Goldbach's other conjecture"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-460-an-ant-on-the-move",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5381000cf542c51004b",
+ "title": "Problem 460: An ant on the move"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-461-almost-pi",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f53a1000cf542c51004c",
+ "title": "Problem 461: Almost Pi"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-462-permutation-of-3-smooth-numbers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f53b1000cf542c51004d",
+ "title": "Problem 462: Permutation of 3-smooth numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-463-a-weird-recurrence-relation",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f53c1000cf542c51004e",
+ "title": "Problem 463: A weird recurrence relation"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-464-mbius-function-and-intervals",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f53d1000cf542c51004f",
+ "title": "Problem 464: Möbius function and intervals"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-465-polar-polygons",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f53d1000cf542c510050",
+ "title": "Problem 465: Polar polygons"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-466-distinct-terms-in-a-multiplication-table",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f53e1000cf542c510051",
+ "title": "Problem 466: Distinct terms in a multiplication table"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-467-superinteger",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5411000cf542c510052",
+ "title": "Problem 467: Superinteger"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-468-smooth-divisors-of-binomial-coefficients",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5411000cf542c510054",
+ "title": "Problem 468: Smooth divisors of binomial coefficients"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-469-empty-chairs",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5411000cf542c510053",
+ "title": "Problem 469: Empty chairs"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-47-distinct-primes-factors",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f39c1000cf542c50feae",
+ "title": "Problem 47: Distinct primes factors"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-470-super-ramvok",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5431000cf542c510055",
+ "title": "Problem 470: Super Ramvok"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-471-triangle-inscribed-in-ellipse",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5431000cf542c510056",
+ "title": "Problem 471: Triangle inscribed in ellipse"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-472-comfortable-distance-ii",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5451000cf542c510057",
+ "title": "Problem 472: Comfortable Distance II"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-473-phigital-number-base",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5461000cf542c510058",
+ "title": "Problem 473: Phigital number base"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-474-last-digits-of-divisors",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5471000cf542c510059",
+ "title": "Problem 474: Last digits of divisors"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-475-music-festival",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5481000cf542c51005a",
+ "title": "Problem 475: Music festival"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-476-circle-packing-ii",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f5481000cf542c51005b",
+ "title": "Problem 476: Circle Packing II"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-477-number-sequence-game",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f54a1000cf542c51005c",
+ "title": "Problem 477: Number Sequence Game"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-478-mixtures",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f54c1000cf542c51005e",
+ "title": "Problem 478: Mixtures"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-479-roots-on-the-rise",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f54b1000cf542c51005d",
+ "title": "Problem 479: Roots on the Rise"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-48-self-powers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f39c1000cf542c50feaf",
+ "title": "Problem 48: Self powers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-480-the-last-question",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f54c1000cf542c51005f",
+ "title": "Problem 480: The Last Question"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-49-prime-permutations",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f39d1000cf542c50feb0",
+ "title": "Problem 49: Prime permutations"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-5-smallest-multiple",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3711000cf542c50fe84",
+ "title": "Problem 5: Smallest multiple"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-50-consecutive-prime-sum",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f39e1000cf542c50feb1",
+ "title": "Problem 50: Consecutive prime sum"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-51-prime-digit-replacements",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f39f1000cf542c50feb2",
+ "title": "Problem 51: Prime digit replacements"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-52-permuted-multiples",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3a01000cf542c50feb3",
+ "title": "Problem 52: Permuted multiples"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-53-combinatoric-selections",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3a11000cf542c50feb4",
+ "title": "Problem 53: Combinatoric selections"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-54-poker-hands",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3a21000cf542c50feb5",
+ "title": "Problem 54: Poker hands"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-55-lychrel-numbers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3a31000cf542c50feb6",
+ "title": "Problem 55: Lychrel numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-56-powerful-digit-sum",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3a41000cf542c50feb7",
+ "title": "Problem 56: Powerful digit sum"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-57-square-root-convergents",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3a51000cf542c50feb8",
+ "title": "Problem 57: Square root convergents"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-58-spiral-primes",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3a61000cf542c50feb9",
+ "title": "Problem 58: Spiral primes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-59-xor-decryption",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3a81000cf542c50feba",
+ "title": "Problem 59: XOR decryption"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-6-sum-square-difference",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3721000cf542c50fe85",
+ "title": "Problem 6: Sum square difference"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-60-prime-pair-sets",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3a81000cf542c50febb",
+ "title": "Problem 60: Prime pair sets"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-61-cyclical-figurate-numbers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3a91000cf542c50febc",
+ "title": "Problem 61: Cyclical figurate numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-62-cubic-permutations",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3aa1000cf542c50febd",
+ "title": "Problem 62: Cubic permutations"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-63-powerful-digit-counts",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3ab1000cf542c50febe",
+ "title": "Problem 63: Powerful digit counts"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-64-odd-period-square-roots",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3ac1000cf542c50febf",
+ "title": "Problem 64: Odd period square roots"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-65-convergents-of-e",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3ad1000cf542c50fec0",
+ "title": "Problem 65: Convergents of e"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-66-diophantine-equation",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3ae1000cf542c50fec1",
+ "title": "Problem 66: Diophantine equation"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-67-maximum-path-sum-ii",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3b01000cf542c50fec2",
+ "title": "Problem 67: Maximum path sum II"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-68-magic-5-gon-ring",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3b01000cf542c50fec3",
+ "title": "Problem 68: Magic 5-gon ring"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-69-totient-maximum",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3b11000cf542c50fec4",
+ "title": "Problem 69: Totient maximum"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-7-10001st-prime",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3731000cf542c50fe86",
+ "title": "Problem 7: 10001st prime"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-70-totient-permutation",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3b21000cf542c50fec5",
+ "title": "Problem 70: Totient permutation"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-71-ordered-fractions",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3b31000cf542c50fec6",
+ "title": "Problem 71: Ordered fractions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-72-counting-fractions",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3b41000cf542c50fec7",
+ "title": "Problem 72: Counting fractions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-73-counting-fractions-in-a-range",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3b61000cf542c50fec8",
+ "title": "Problem 73: Counting fractions in a range"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-74-digit-factorial-chains",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3b61000cf542c50fec9",
+ "title": "Problem 74: Digit factorial chains"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-75-singular-integer-right-triangles",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3b71000cf542c50feca",
+ "title": "Problem 75: Singular integer right triangles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-76-counting-summations",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3b81000cf542c50fecb",
+ "title": "Problem 76: Counting summations"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-77-prime-summations",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3b91000cf542c50fecc",
+ "title": "Problem 77: Prime summations"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-78-coin-partitions",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3ba1000cf542c50fecd",
+ "title": "Problem 78: Coin partitions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-79-passcode-derivation",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3bb1000cf542c50fece",
+ "title": "Problem 79: Passcode derivation"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-8-largest-product-in-a-series",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3741000cf542c50fe87",
+ "title": "Problem 8: Largest product in a series"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-80-square-root-digital-expansion",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3bc1000cf542c50fecf",
+ "title": "Problem 80: Square root digital expansion"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-81-path-sum-two-ways",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3bd1000cf542c50fed0",
+ "title": "Problem 81: Path sum: two ways"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-82-path-sum-three-ways",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3be1000cf542c50fed1",
+ "title": "Problem 82: Path sum: three ways"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-83-path-sum-four-ways",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3bf1000cf542c50fed2",
+ "title": "Problem 83: Path sum: four ways"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-84-monopoly-odds",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3c11000cf542c50fed3",
+ "title": "Problem 84: Monopoly odds"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-85-counting-rectangles",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3c11000cf542c50fed4",
+ "title": "Problem 85: Counting rectangles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-86-cuboid-route",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3c31000cf542c50fed5",
+ "title": "Problem 86: Cuboid route"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-87-prime-power-triples",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3c51000cf542c50fed8",
+ "title": "Problem 87: Prime power triples"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-88-product-sum-numbers",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3c51000cf542c50fed6",
+ "title": "Problem 88: Product-sum numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-89-roman-numerals",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3c51000cf542c50fed7",
+ "title": "Problem 89: Roman numerals"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-9-special-pythagorean-triplet",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3761000cf542c50fe88",
+ "title": "Problem 9: Special Pythagorean triplet"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-90-cube-digit-pairs",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3c61000cf542c50fed9",
+ "title": "Problem 90: Cube digit pairs"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-91-right-triangles-with-integer-coordinates",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3c71000cf542c50feda",
+ "title": "Problem 91: Right triangles with integer coordinates"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-92-square-digit-chains",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3c81000cf542c50fedb",
+ "title": "Problem 92: Square digit chains"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-93-arithmetic-expressions",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3ca1000cf542c50fedc",
+ "title": "Problem 93: Arithmetic expressions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-94-almost-equilateral-triangles",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3ca1000cf542c50fedd",
+ "title": "Problem 94: Almost equilateral triangles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-95-amicable-chains",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3cc1000cf542c50fede",
+ "title": "Problem 95: Amicable chains"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-96-su-doku",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3cc1000cf542c50fedf",
+ "title": "Problem 96: Su Doku"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-97-large-non-mersenne-prime",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3ce1000cf542c50fee0",
+ "title": "Problem 97: Large non-Mersenne prime"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-98-anagramic-squares",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3cf1000cf542c50fee1",
+ "title": "Problem 98: Anagramic squares"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/project-euler/problem-99-largest-exponential",
+ "blockName": "Project Euler"
+ },
+ "id": "5900f3d01000cf542c50fee2",
+ "title": "Problem 99: Largest exponential"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/100-doors",
+ "blockName": "Rosetta Code"
+ },
+ "id": "594810f028c0303b75339acb",
+ "title": "100 doors"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/24-game",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5951e88f64ebf159166a1176",
+ "title": "24 game"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/9-billion-names-of-god-the-integer",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5949b579404977fbaefcd736",
+ "title": "9 billion names of God the integer"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/abc-problem",
+ "blockName": "Rosetta Code"
+ },
+ "id": "594810f028c0303b75339acc",
+ "title": "ABC Problem"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/abundant-deficient-and-perfect-number-classifications",
+ "blockName": "Rosetta Code"
+ },
+ "id": "594810f028c0303b75339acd",
+ "title": "Abundant, deficient and perfect number classifications"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/accumulator-factory",
+ "blockName": "Rosetta Code"
+ },
+ "id": "594810f028c0303b75339ace",
+ "title": "Accumulator factory"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/ackermann-function",
+ "blockName": "Rosetta Code"
+ },
+ "id": "594810f028c0303b75339acf",
+ "title": "Ackermann function"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/align-columns",
+ "blockName": "Rosetta Code"
+ },
+ "id": "594810f028c0303b75339ad0",
+ "title": "Align columns"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/amicable-pairs",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5949b579404977fbaefcd737",
+ "title": "Amicable pairs"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/averagesmode",
+ "blockName": "Rosetta Code"
+ },
+ "id": "594d8d0ab97724821379b1e6",
+ "title": "Averages/Mode"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/averagespythagorean-means",
+ "blockName": "Rosetta Code"
+ },
+ "id": "594d966a1467eb84194f0086",
+ "title": "Averages/Pythagorean means"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/averagesroot-mean-square",
+ "blockName": "Rosetta Code"
+ },
+ "id": "594da033de4190850b893874",
+ "title": "Averages/Root mean square"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/babbage-problem",
+ "blockName": "Rosetta Code"
+ },
+ "id": "594db4d0dedb4c06a2a4cefd",
+ "title": "Babbage problem"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/balanced-brackets",
+ "blockName": "Rosetta Code"
+ },
+ "id": "594dc6c729e5700999302b45",
+ "title": "Balanced brackets"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/circles-of-given-radius-through-two-points",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5951815dd895584b06884620",
+ "title": "Circles of given radius through two points"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/closest-pair-problem",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5951a53863c8a34f02bf1bdc",
+ "title": "Closest-pair problem"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/combinations",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5958469238c0d8d2632f46db",
+ "title": "Combinations"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/comma-quibbling",
+ "blockName": "Rosetta Code"
+ },
+ "id": "596e414344c3b2872167f0fe",
+ "title": "Comma quibbling"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/compare-a-list-of-strings",
+ "blockName": "Rosetta Code"
+ },
+ "id": "596e457071c35c882915b3e4",
+ "title": "Compare a list of strings"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/convert-seconds-to-compound-duration",
+ "blockName": "Rosetta Code"
+ },
+ "id": "596fd036dc1ab896c5db98b1",
+ "title": "Convert seconds to compound duration"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/count-occurrences-of-a-substring",
+ "blockName": "Rosetta Code"
+ },
+ "id": "596fda99c69f779975a1b67d",
+ "title": "Count occurrences of a substring"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/count-the-coins",
+ "blockName": "Rosetta Code"
+ },
+ "id": "59713bd26bdeb8a594fb9413",
+ "title": "Count the coins"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/cramers-rule",
+ "blockName": "Rosetta Code"
+ },
+ "id": "59713da0a428c1a62d7db430",
+ "title": "Cramer's rule"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/cumulative-standard-deviation",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7e03",
+ "title": "Cumulative standard deviation"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/cusip",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7e05",
+ "title": "CUSIP"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/cut-a-rectangle",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7e06",
+ "title": "Cut a rectangle"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/date-format",
+ "blockName": "Rosetta Code"
+ },
+ "id": "59669d08d75b60482359409f",
+ "title": "Date format"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/date-manipulation",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5966c21cf732a95f1b67dd28",
+ "title": "Date manipulation"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/day-of-the-week",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5966f99c45e8976909a85575",
+ "title": "Day of the week"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/deal-cards-for-freecell",
+ "blockName": "Rosetta Code"
+ },
+ "id": "59694356a6e7011f7f1c5f4e",
+ "title": "Deal cards for FreeCell"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/deepcopy",
+ "blockName": "Rosetta Code"
+ },
+ "id": "596a8888ab7c01048de257d5",
+ "title": "Deepcopy"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/define-a-primitive-data-type",
+ "blockName": "Rosetta Code"
+ },
+ "id": "597089c87eec450c68aa1643",
+ "title": "Define a primitive data type"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/department-numbers",
+ "blockName": "Rosetta Code"
+ },
+ "id": "59f40b17e79dbf1ab720ed7a",
+ "title": "Department Numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/discordian-date",
+ "blockName": "Rosetta Code"
+ },
+ "id": "59f4eafba0343628bb682785",
+ "title": "Discordian date"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/dot-product",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7e1e",
+ "title": "Dot product"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/element-wise-operations",
+ "blockName": "Rosetta Code"
+ },
+ "id": "599c333915e0ea32d04d4bec",
+ "title": "Element-wise operations"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/emirp-primes",
+ "blockName": "Rosetta Code"
+ },
+ "id": "599d0ba974141b0f508b37d5",
+ "title": "Emirp primes"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/entropy",
+ "blockName": "Rosetta Code"
+ },
+ "id": "599d15309e88c813a40baf58",
+ "title": "Entropy"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/equilibrium-index",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5987fd532b954e0f21b5d3f6",
+ "title": "Equilibrium index"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/ethiopian-multiplication",
+ "blockName": "Rosetta Code"
+ },
+ "id": "599d1566a02b571412643b84",
+ "title": "Ethiopian multiplication"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/euler-method",
+ "blockName": "Rosetta Code"
+ },
+ "id": "59880443fb36441083c6c20e",
+ "title": "Euler method"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/evaluate-binomial-coefficients",
+ "blockName": "Rosetta Code"
+ },
+ "id": "598de241872ef8353c58a7a2",
+ "title": "Evaluate binomial coefficients"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/execute-a-markov-algorithm",
+ "blockName": "Rosetta Code"
+ },
+ "id": "59e09e6d412c5939baa02d16",
+ "title": "Execute a Markov algorithm"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/execute-brain",
+ "blockName": "Rosetta Code"
+ },
+ "id": "59e0a8df964e4540d5abe599",
+ "title": "Execute Brain****"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/extensible-prime-generator",
+ "blockName": "Rosetta Code"
+ },
+ "id": "598ee8b91b410510ae82efef",
+ "title": "Extensible prime generator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/factorial",
+ "blockName": "Rosetta Code"
+ },
+ "id": "597b2b2a2702b44414742771",
+ "title": "Factorial"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/factors-of-a-mersenne-number",
+ "blockName": "Rosetta Code"
+ },
+ "id": "598eea87e5cf4b116c3ff81a",
+ "title": "Factors of a Mersenne number"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/factors-of-an-integer",
+ "blockName": "Rosetta Code"
+ },
+ "id": "597f1e7fbc206f0e9ba95dc4",
+ "title": "Factors of an integer"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/farey-sequence",
+ "blockName": "Rosetta Code"
+ },
+ "id": "59c3ec9f15068017c96eb8a3",
+ "title": "Farey sequence"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/fibonacci-n-step-number-sequences",
+ "blockName": "Rosetta Code"
+ },
+ "id": "598eef80ba501f1268170e1e",
+ "title": "Fibonacci n-step number sequences"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/fibonacci-sequence",
+ "blockName": "Rosetta Code"
+ },
+ "id": "597f24c1dda4e70f53c79c81",
+ "title": "Fibonacci sequence"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/fibonacci-word",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5992e222d397f00d21122931",
+ "title": "Fibonacci word"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/fizzbuzz",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5e9ddb06ec35240f39657419",
+ "title": "FizzBuzz"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/fractran",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a7dad05be01840e1778a0d1",
+ "title": "Fractran"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/gamma-function",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7e76",
+ "title": "Gamma function"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/gaussian-elimination",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7e77",
+ "title": "Gaussian elimination"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/general-fizzbuzz",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7e78",
+ "title": "General FizzBuzz"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/generate-lower-case-ascii-alphabet",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7e7a",
+ "title": "Generate lower case ASCII alphabet"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/generatorexponential",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7e7b",
+ "title": "Generator/Exponential"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/gray-code",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7e80",
+ "title": "Gray code"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/greatest-common-divisor",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7e82",
+ "title": "Greatest common divisor"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/greatest-subsequential-sum",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7e84",
+ "title": "Greatest subsequential sum"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/hailstone-sequence",
+ "blockName": "Rosetta Code"
+ },
+ "id": "595608ff8bcd7a50bd490181",
+ "title": "Hailstone sequence"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/happy-numbers",
+ "blockName": "Rosetta Code"
+ },
+ "id": "594810f028c0303b75339ad1",
+ "title": "Happy numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/harshad-or-niven-series",
+ "blockName": "Rosetta Code"
+ },
+ "id": "595668ca4cfe1af2fb9818d4",
+ "title": "Harshad or Niven series"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/hash-from-two-arrays",
+ "blockName": "Rosetta Code"
+ },
+ "id": "595671d4d2cdc305f0d5b36f",
+ "title": "Hash from two arrays"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/hash-join",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5956795bc9e2c415eb244de1",
+ "title": "Hash join"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/heronian-triangles",
+ "blockName": "Rosetta Code"
+ },
+ "id": "595b98f8b5a2245e243aa831",
+ "title": "Heronian triangles"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/hofstadter-figure-figure-sequences",
+ "blockName": "Rosetta Code"
+ },
+ "id": "59622f89e4e137560018a40e",
+ "title": "Hofstadter Figure-Figure sequences"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/hofstadter-q-sequence",
+ "blockName": "Rosetta Code"
+ },
+ "id": "59637c4d89f6786115efd814",
+ "title": "Hofstadter Q sequence"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/i-before-e-except-after-c",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7eb0",
+ "title": "I before E except after C"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/iban",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7eaf",
+ "title": "IBAN"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/identity-matrix",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7eb1",
+ "title": "Identity matrix"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/iterated-digits-squaring",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7ec1",
+ "title": "Iterated digits squaring"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/jaro-distance",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7ec2",
+ "title": "Jaro distance"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/jortsort",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7ec4",
+ "title": "JortSort"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/josephus-problem",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7ec5",
+ "title": "Josephus problem"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/k-d-tree",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7ecb",
+ "title": "K-d tree"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/kaprekar-numbers",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7eca",
+ "title": "Kaprekar numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/knapsack-problem0-1",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7ed1",
+ "title": "Knapsack problem/0-1"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/knapsack-problembounded",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7ed2",
+ "title": "Knapsack problem/Bounded"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/knapsack-problemcontinuous",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7ed3",
+ "title": "Knapsack problem/Continuous"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/knapsack-problemunbounded",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7ed4",
+ "title": "Knapsack problem/Unbounded"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/knights-tour",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7ed5",
+ "title": "Knight's tour"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/largest-int-from-concatenated-ints",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7edb",
+ "title": "Largest int from concatenated ints"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/last-friday-of-each-month",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7edc",
+ "title": "Last Friday of each month"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/last-letter-first-letter",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5e4ce2b6ac708cc68c1df25e",
+ "title": "Last letter-first letter"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/leap-year",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7ede",
+ "title": "Leap year"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/least-common-multiple",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7edf",
+ "title": "Least common multiple"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/left-factorials",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7ee0",
+ "title": "Left factorials"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/letter-frequency",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5e4ce2bbac708cc68c1df25f",
+ "title": "Letter frequency"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/levenshtein-distance",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5e4ce2eaac708cc68c1df260",
+ "title": "Levenshtein distance"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/linear-congruential-generator",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5e4ce2f5ac708cc68c1df261",
+ "title": "Linear congruential generator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/long-multiplication",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5e4ce2a1ac708cc68c1df25d",
+ "title": "Long multiplication"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/longest-common-subsequence",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5e6dd1278e6ca105cde40ea9",
+ "title": "Longest common subsequence"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/longest-increasing-subsequence",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5e6dd139859c290b6ab80292",
+ "title": "Longest increasing subsequence"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/longest-string-challenge",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5e6dd14192286d95fc43046e",
+ "title": "Longest string challenge"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/look-and-say-sequence",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5e6dd14797f5ce267c2f19d0",
+ "title": "Look-and-say sequence"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/loop-over-multiple-arrays-simultaneously",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5e6dd15004c88cf00d2a78b3",
+ "title": "Loop over multiple arrays simultaneously"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/lu-decomposition",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5e6decd8ec8d7db960950d1c",
+ "title": "LU decomposition"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/lucas-lehmer-test",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5e6dee7749a0b85a3f1fc7d5",
+ "title": "Lucas-Lehmer test"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/ludic-numbers",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5ea281203167d2b0bdefca00",
+ "title": "Ludic numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/luhn-test-of-credit-card-numbers",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5ea28156e79528a9ab248f27",
+ "title": "Luhn test of credit card numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/lychrel-numbers",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5ea2815a8640bcc6cb7dab3c",
+ "title": "Lychrel numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/lzw-compression",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5ea2815e364d9a2222ea55f8",
+ "title": "LZW compression"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/s-expressions",
+ "blockName": "Rosetta Code"
+ },
+ "id": "59667989bf71cf555dd5d2ff",
+ "title": "S-Expressions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/sailors-coconuts-and-a-monkey-problem",
+ "blockName": "Rosetta Code"
+ },
+ "id": "59da22823d04c95919d46269",
+ "title": "Sailors, coconuts and a monkey problem"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/search-a-list-of-records",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5eb3e497b8d6d7f63c5517ea",
+ "title": "Search a list of records"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/sedols",
+ "blockName": "Rosetta Code"
+ },
+ "id": "59d9c6bc214c613ba73ff012",
+ "title": "SEDOLs"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/self-describing-numbers",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5eaf48389ee512d4d103684b",
+ "title": "Self Describing Numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/self-referential-sequence",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5eb3e4a21f462f409d656c73",
+ "title": "Self-referential sequence"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/semiprime",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5eb3e4aa847216613aa81983",
+ "title": "Semiprime"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/set-consolidation",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5eb3e4af7d0e7b760b46cedc",
+ "title": "Set consolidation"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/set-of-real-numbers",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5eb3e4b20aa93c437f9e9717",
+ "title": "Set of real numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/sha-1",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5eb3e4b5f629b9a07429a5d2",
+ "title": "SHA-1"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/sha-256",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5eb3e4c3a894c333d2811a3f",
+ "title": "SHA-256"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/sort-an-array-of-composite-structures",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc7ffe",
+ "title": "Sort an array of composite structures"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/sort-disjoint-sublist",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc8000",
+ "title": "Sort disjoint sublist"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/sort-stability",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc8014",
+ "title": "Sort stability"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/sort-using-a-custom-comparator",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc8016",
+ "title": "Sort using a custom comparator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/sorting-algorithmsbead-sort",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc8001",
+ "title": "Sorting algorithms/Bead sort"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/sorting-algorithmsbogosort",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc8002",
+ "title": "Sorting algorithms/Bogosort"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/sorting-algorithmscocktail-sort",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc8004",
+ "title": "Sorting algorithms/Cocktail sort"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/sorting-algorithmscomb-sort",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc8005",
+ "title": "Sorting algorithms/Comb sort"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/sorting-algorithmsgnome-sort",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc8007",
+ "title": "Sorting algorithms/Gnome sort"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/sorting-algorithmspancake-sort",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc800b",
+ "title": "Sorting algorithms/Pancake sort"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/sorting-algorithmspermutation-sort",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc800c",
+ "title": "Sorting algorithms/Permutation sort"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/sorting-algorithmsshell-sort",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc8010",
+ "title": "Sorting algorithms/Shell sort"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/sorting-algorithmsstooge-sort",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc8012",
+ "title": "Sorting algorithms/Stooge sort"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/sorting-algorithmsstrand-sort",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc8013",
+ "title": "Sorting algorithms/Strand sort"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/soundex",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc8017",
+ "title": "Soundex"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/spiral-matrix",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc801c",
+ "title": "Spiral matrix"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/split-a-character-string-based-on-change-of-character",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc801d",
+ "title": "Split a character string based on change of character"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/state-name-puzzle",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc8024",
+ "title": "State name puzzle"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/stern-brocot-sequence",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc8028",
+ "title": "Stern-Brocot sequence"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/straddling-checkerboard",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc8029",
+ "title": "Straddling checkerboard"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/stream-merge",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc802a",
+ "title": "Stream Merge"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/strip-control-codes-and-extended-characters-from-a-string",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc8036",
+ "title": "Strip control codes and extended characters from a string"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/subleq",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc8038",
+ "title": "Subleq"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/sudoku",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc803c",
+ "title": "Sudoku"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/sum-digits-of-an-integer",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc803f",
+ "title": "Sum digits of an integer"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/sum-multiples-of-3-and-5",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc8040",
+ "title": "Sum multiples of 3 and 5"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/sum-of-a-series",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc8041",
+ "title": "Sum of a series"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/sum-of-squares",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc8042",
+ "title": "Sum of squares"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/sum-to-100",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc8043",
+ "title": "Sum to 100"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/sutherland-hodgman-polygon-clipping",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc8045",
+ "title": "Sutherland-Hodgman polygon clipping"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/symmetric-difference",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5a23c84252665b21eecc8046",
+ "title": "Symmetric difference"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/taxicab-numbers",
+ "blockName": "Rosetta Code"
+ },
+ "id": "594ecc0d9a8cf816e3340187",
+ "title": "Taxicab numbers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/tokenize-a-string-with-escaping",
+ "blockName": "Rosetta Code"
+ },
+ "id": "594faaab4e2a8626833e9c3d",
+ "title": "Tokenize a string with escaping"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/top-rank-per-group",
+ "blockName": "Rosetta Code"
+ },
+ "id": "595011cba5a81735713873bd",
+ "title": "Top rank per group"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/topological-sort",
+ "blockName": "Rosetta Code"
+ },
+ "id": "594fa2746886f41f7d8bf225",
+ "title": "Topological sort"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/towers-of-hanoi",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5951ed8945deab770972ae56",
+ "title": "Towers of Hanoi"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/vector-cross-product",
+ "blockName": "Rosetta Code"
+ },
+ "id": "594810f028c0303b75339ad2",
+ "title": "Vector cross product"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/vector-dot-product",
+ "blockName": "Rosetta Code"
+ },
+ "id": "594810f028c0303b75339ad3",
+ "title": "Vector dot product"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/word-frequency",
+ "blockName": "Rosetta Code"
+ },
+ "id": "5e94a54cc7b022105bf0fd2c",
+ "title": "Word frequency"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/word-wrap",
+ "blockName": "Rosetta Code"
+ },
+ "id": "594810f028c0303b75339ad4",
+ "title": "Word wrap"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/y-combinator",
+ "blockName": "Rosetta Code"
+ },
+ "id": "594810f028c0303b75339ad5",
+ "title": "Y combinator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/zeckendorf-number-representation",
+ "blockName": "Rosetta Code"
+ },
+ "id": "594810f028c0303b75339ad6",
+ "title": "Zeckendorf number representation"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/zhang-suen-thinning-algorithm",
+ "blockName": "Rosetta Code"
+ },
+ "id": "594810f028c0303b75339ad7",
+ "title": "Zhang-Suen thinning algorithm"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/rosetta-code/zig-zag-matrix",
+ "blockName": "Rosetta Code"
+ },
+ "id": "594810f028c0303b75339ad8",
+ "title": "Zig-zag matrix"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/take-home-projects/build-a-freecodecamp-forum-homepage",
+ "blockName": "Take Home Projects"
+ },
+ "id": "bd7156d8c242eddfaeb5bd13",
+ "title": "Build a freeCodeCamp Forum Homepage"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/take-home-projects/build-a-light-bright-app",
+ "blockName": "Take Home Projects"
+ },
+ "id": "5a5d02bd919fcf9ca8cf46cb",
+ "title": "Build a Light-Bright App"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/take-home-projects/build-a-nightlife-coordination-app",
+ "blockName": "Take Home Projects"
+ },
+ "id": "bd7158d8c443eddfaeb5bdff",
+ "title": "Build a Nightlife Coordination App"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/take-home-projects/build-a-pinterest-clone",
+ "blockName": "Take Home Projects"
+ },
+ "id": "bd7158d8c443eddfaeb5bdee",
+ "title": "Build a Pinterest Clone"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/take-home-projects/build-a-pong-game",
+ "blockName": "Take Home Projects"
+ },
+ "id": "5a4b7fcdb66f799f199e11db",
+ "title": "Build a Pong Game"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/take-home-projects/build-a-recipe-box",
+ "blockName": "Take Home Projects"
+ },
+ "id": "bd7155d8c242eddfaeb5bd13",
+ "title": "Build a Recipe Box"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/take-home-projects/build-a-roguelike-dungeon-crawler-game",
+ "blockName": "Take Home Projects"
+ },
+ "id": "bd7153d8c242eddfaeb5bd13",
+ "title": "Build a Roguelike Dungeon Crawler Game"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/take-home-projects/build-a-simon-game",
+ "blockName": "Take Home Projects"
+ },
+ "id": "bd7158d8c442eddfaeb5bd1c",
+ "title": "Build a Simon Game"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/take-home-projects/build-a-tic-tac-toe-game",
+ "blockName": "Take Home Projects"
+ },
+ "id": "bd7158d8c442eedfaeb5bd1c",
+ "title": "Build a Tic Tac Toe Game"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/take-home-projects/build-a-voting-app",
+ "blockName": "Take Home Projects"
+ },
+ "id": "bd7158d8c443eddfaeb5bdef",
+ "title": "Build a Voting App"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/take-home-projects/build-a-wikipedia-viewer",
+ "blockName": "Take Home Projects"
+ },
+ "id": "bd7158d8c442eddfaeb5bd19",
+ "title": "Build a Wikipedia Viewer"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/take-home-projects/build-an-image-search-abstraction-layer",
+ "blockName": "Take Home Projects"
+ },
+ "id": "bd7158d8c443edefaeb5bdee",
+ "title": "Build an Image Search Abstraction Layer"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/take-home-projects/build-the-game-of-life",
+ "blockName": "Take Home Projects"
+ },
+ "id": "bd7154d8c242eddfaeb5bd13",
+ "title": "Build the Game of Life"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/take-home-projects/chart-the-stock-market",
+ "blockName": "Take Home Projects"
+ },
+ "id": "bd7158d8c443eddfaeb5bd0e",
+ "title": "Chart the Stock Market"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/take-home-projects/manage-a-book-trading-club",
+ "blockName": "Take Home Projects"
+ },
+ "id": "bd7158d8c443eddfaeb5bd0f",
+ "title": "Manage a Book Trading Club"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/take-home-projects/map-data-across-the-globe",
+ "blockName": "Take Home Projects"
+ },
+ "id": "bd7108d8c242eddfaeb5bd13",
+ "title": "Map Data Across the Globe"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/take-home-projects/p2p-video-chat-application",
+ "blockName": "Take Home Projects"
+ },
+ "id": "bd7150d8c442eddfafb5bd1c",
+ "title": "P2P Video Chat Application"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/take-home-projects/show-national-contiguity-with-a-force-directed-graph",
+ "blockName": "Take Home Projects"
+ },
+ "id": "bd7198d8c242eddfaeb5bd13",
+ "title": "Show National Contiguity with a Force Directed Graph"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/take-home-projects/show-the-local-weather",
+ "blockName": "Take Home Projects"
+ },
+ "id": "bd7158d8c442eddfaeb5bd10",
+ "title": "Show the Local Weather"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/coding-interview-prep/take-home-projects/use-the-twitch-json-api",
+ "blockName": "Take Home Projects"
+ },
+ "id": "bd7158d8c442eddfaeb5bd1f",
+ "title": "Use the Twitch JSON API"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/how-neural-networks-work/deep-learning-demystified",
+ "blockName": "How Neural Networks Work"
+ },
+ "id": "5e9a0e9ef99a403d019610cc",
+ "title": "Deep Learning Demystified"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/how-neural-networks-work/how-convolutional-neural-networks-work",
+ "blockName": "How Neural Networks Work"
+ },
+ "id": "5e9a0e9ef99a403d019610cd",
+ "title": "How Convolutional Neural Networks work"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/how-neural-networks-work/how-deep-neural-networks-work",
+ "blockName": "How Neural Networks Work"
+ },
+ "id": "5e9a0e9ef99a403d019610ca",
+ "title": "How Deep Neural Networks Work"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/how-neural-networks-work/recurrent-neural-networks-rnn-and-long-short-term-memory-lstm",
+ "blockName": "How Neural Networks Work"
+ },
+ "id": "5e9a0e9ef99a403d019610cb",
+ "title": "Recurrent Neural Networks RNN and Long Short Term Memory LSTM"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/machine-learning-with-python-projects/book-recommendation-engine-using-knn",
+ "blockName": "Machine Learning with Python Projects"
+ },
+ "id": "5e46f8e3ac417301a38fb92f",
+ "title": "Book Recommendation Engine using KNN"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/machine-learning-with-python-projects/cat-and-dog-image-classifier",
+ "blockName": "Machine Learning with Python Projects"
+ },
+ "id": "5e46f8dcac417301a38fb92e",
+ "title": "Cat and Dog Image Classifier"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/machine-learning-with-python-projects/linear-regression-health-costs-calculator",
+ "blockName": "Machine Learning with Python Projects"
+ },
+ "id": "5e46f8edac417301a38fb930",
+ "title": "Linear Regression Health Costs Calculator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/machine-learning-with-python-projects/neural-network-sms-text-classifier",
+ "blockName": "Machine Learning with Python Projects"
+ },
+ "id": "5e46f8edac417301a38fb931",
+ "title": "Neural Network SMS Text Classifier"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/machine-learning-with-python-projects/rock-paper-scissors",
+ "blockName": "Machine Learning with Python Projects"
+ },
+ "id": "5e46f8d6ac417301a38fb92d",
+ "title": "Rock Paper Scissors"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/conclusion",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72da6",
+ "title": "Conclusion"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/convolutional-neural-networks-evaluating-the-model",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72d99",
+ "title": "Convolutional Neural Networks: Evaluating the Model"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/convolutional-neural-networks-picking-a-pretrained-model",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72d9a",
+ "title": "Convolutional Neural Networks: Picking a Pretrained Model"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/convolutional-neural-networks-the-convolutional-layer",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72d97",
+ "title": "Convolutional Neural Networks: The Convolutional Layer"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/convolutional-neural-networks",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72d96",
+ "title": "Convolutional Neural Networks"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/core-learning-algorithms-building-the-model",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72d8e",
+ "title": "Core Learning Algorithms: Building the Model"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/core-learning-algorithms-classification",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72d8d",
+ "title": "Core Learning Algorithms: Classification"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/core-learning-algorithms-clustering",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72d8f",
+ "title": "Core Learning Algorithms: Clustering"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/core-learning-algorithms-hidden-markov-models",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72d90",
+ "title": "Core Learning Algorithms: Hidden Markov Models"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/core-learning-algorithms-the-training-process",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72d8c",
+ "title": "Core Learning Algorithms: The Training Process"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/core-learning-algorithms-training-and-testing-data",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72d8b",
+ "title": "Core Learning Algorithms: Training and Testing Data"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/core-learning-algorithms-using-probabilities-to-make-predictions",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72d91",
+ "title": "Core Learning Algorithms: Using Probabilities to make Predictions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/core-learning-algorithms-working-with-data",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72d8a",
+ "title": "Core Learning Algorithms: Working with Data"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/core-learning-algorithms",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72d89",
+ "title": "Core Learning Algorithms"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/creating-a-convolutional-neural-network",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72d98",
+ "title": "Creating a Convolutional Neural Network"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/introduction-machine-learning-fundamentals",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72d87",
+ "title": "Introduction: Machine Learning Fundamentals"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/introduction-to-tensorflow",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72d88",
+ "title": "Introduction to TensorFlow"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/natural-language-processing-with-rnns-building-the-model",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72da1",
+ "title": "Natural Language Processing With RNNs: Building the Model"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/natural-language-processing-with-rnns-create-a-play-generator",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72da0",
+ "title": "Natural Language Processing With RNNs: Create a Play Generator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/natural-language-processing-with-rnns-making-predictions",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72d9f",
+ "title": "Natural Language Processing With RNNs: Making Predictions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/natural-language-processing-with-rnns-part-2",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72d9c",
+ "title": "Natural Language Processing With RNNs: Part 2"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/natural-language-processing-with-rnns-recurring-neural-networks",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72d9d",
+ "title": "Natural Language Processing With RNNs: Recurring Neural Networks"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/natural-language-processing-with-rnns-sentiment-analysis",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72d9e",
+ "title": "Natural Language Processing With RNNs: Sentiment Analysis"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/natural-language-processing-with-rnns-training-the-model",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72da2",
+ "title": "Natural Language Processing With RNNs: Training the Model"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/natural-language-processing-with-rnns",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72d9b",
+ "title": "Natural Language Processing With RNNs"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/neural-networks-activation-functions",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72d93",
+ "title": "Neural Networks: Activation Functions"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/neural-networks-creating-a-model",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72d95",
+ "title": "Neural Networks: Creating a Model"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/neural-networks-optimizers",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72d94",
+ "title": "Neural Networks: Optimizers"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/neural-networks-with-tensorflow",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72d92",
+ "title": "Neural Networks with TensorFlow"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/reinforcement-learning-with-q-learning-example",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72da5",
+ "title": "Reinforcement Learning With Q-Learning: Example"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/reinforcement-learning-with-q-learning-part-2",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72da4",
+ "title": "Reinforcement Learning With Q-Learning: Part 2"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/machine-learning-with-python/tensorflow/reinforcement-learning-with-q-learning",
+ "blockName": "TensorFlow"
+ },
+ "id": "5e8f2f13c4cdbe86b5c72da3",
+ "title": "Reinforcement Learning With Q-Learning"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/relational-database/build-a-celestial-bodies-database-project/build-a-celestial-bodies-database",
+ "blockName": "Build A Celestial Bodies Database Project"
+ },
+ "id": "5f1a4ef5d5d6b5ab580fc6ae",
+ "title": "Build a Celestial Bodies Database"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/relational-database/build-a-number-guessing-game-project/build-a-number-guessing-game",
+ "blockName": "Build A Number Guessing Game Project"
+ },
+ "id": "602da04c22201c65d2a019f4",
+ "title": "Build a Number Guessing Game"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/relational-database/build-a-periodic-table-database-project/build-a-periodic-table-database",
+ "blockName": "Build A Periodic Table Database Project"
+ },
+ "id": "602d9ff222201c65d2a019f2",
+ "title": "Build a Periodic Table Database"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/relational-database/build-a-salon-appointment-scheduler-project/build-a-salon-appointment-scheduler",
+ "blockName": "Build A Salon Appointment Scheduler Project"
+ },
+ "id": "5f87ac112ae598023a42df1a",
+ "title": "Build a Salon Appointment Scheduler"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/relational-database/build-a-world-cup-database-project/build-a-world-cup-database",
+ "blockName": "Build A World Cup Database Project"
+ },
+ "id": "5f9771307d4d22b9d2b75a94",
+ "title": "Build a World Cup Database"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/relational-database/learn-advanced-bash-by-building-a-kitty-ipsum-translator/build-a-kitty-ipsum-translator",
+ "blockName": "Learn Advanced Bash By Building A Kitty Ipsum Translator"
+ },
+ "id": "602da0de22201c65d2a019f6",
+ "title": "Build a Kitty Ipsum Translator"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/relational-database/learn-bash-and-sql-by-building-a-bike-rental-shop/build-a-bike-rental-shop",
+ "blockName": "Learn Bash and Sql By Building A Bike Rental Shop"
+ },
+ "id": "5f5b969a05380d2179fe6e18",
+ "title": "Build a Bike Rental Shop"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/relational-database/learn-bash-by-building-a-boilerplate/build-a-boilerplate",
+ "blockName": "Learn Bash By Building A Boilerplate"
+ },
+ "id": "5ea8adfab628f68d805bfc5e",
+ "title": "Build a Boilerplate"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/relational-database/learn-bash-scripting-by-building-five-programs/build-five-programs",
+ "blockName": "Learn Bash Scripting By Building Five Programs"
+ },
+ "id": "5f5904ac738bc2fa9efecf5a",
+ "title": "Build Five Programs"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/relational-database/learn-git-by-building-an-sql-reference-object/build-an-sql-reference-object",
+ "blockName": "Learn Git By Building An Sql Reference Object"
+ },
+ "id": "5fa323cdaf6a73463d590659",
+ "title": "Build an SQL Reference Object"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/relational-database/learn-nano-by-building-a-castle/build-a-castle",
+ "blockName": "Learn Nano By Building A Castle"
+ },
+ "id": "5f32db63eb37f7e17323f459",
+ "title": "Build a Castle"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/relational-database/learn-relational-databases-by-building-a-mario-database/build-a-mario-database",
+ "blockName": "Learn Relational Databases By Building A Mario Database"
+ },
+ "id": "5f2c289f164c29556da632fd",
+ "title": "Build a Mario Database"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/relational-database/learn-sql-by-building-a-student-database-part-1/build-a-student-database-part-1",
+ "blockName": "Learn Sql By Building A Student Database Part 1"
+ },
+ "id": "602da0c222201c65d2a019f5",
+ "title": "Build a Student Database: Part 1"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/relational-database/learn-sql-by-building-a-student-database-part-2/build-a-student-database-part-2",
+ "blockName": "Learn Sql By Building A Student Database Part 2"
+ },
+ "id": "618590adb0730ca724e37672",
+ "title": "Build a Student Database: Part 2"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/build-a-personal-portfolio-webpage-project/build-a-personal-portfolio-webpage",
+ "blockName": "Build A Personal Portfolio Webpage Project"
+ },
+ "id": "bd7158d8c242eddfaeb5bd13",
+ "title": "Build a Personal Portfolio Webpage"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/build-a-product-landing-page-project/build-a-product-landing-page",
+ "blockName": "Build A Product Landing Page Project"
+ },
+ "id": "587d78af367417b2b2512b04",
+ "title": "Build a Product Landing Page"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/build-a-survey-form-project/build-a-survey-form",
+ "blockName": "Build A Survey Form Project"
+ },
+ "id": "587d78af367417b2b2512b03",
+ "title": "Build a Survey Form"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/build-a-technical-documentation-page-project/build-a-technical-documentation-page",
+ "blockName": "Build A Technical Documentation Page Project"
+ },
+ "id": "587d78b0367417b2b2512b05",
+ "title": "Build a Technical Documentation Page"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/build-a-tribute-page-project/build-a-tribute-page",
+ "blockName": "Build A Tribute Page Project"
+ },
+ "id": "bd7158d8c442eddfaeb5bd18",
+ "title": "Build a Tribute Page"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-2",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "613297a923965e0703b64796",
+ "title": "Step 2"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-3",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "61329b210dac0b08047fd6ab",
+ "title": "Step 3"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-4",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "61329d52e5010e08d9b9d66b",
+ "title": "Step 4"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-5",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6133acc353338c0bba9cb553",
+ "title": "Step 5"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-6",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6133d11ef548f51f876149e3",
+ "title": "Step 6"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-7",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "613e2546d0594208229ada50",
+ "title": "Step 7"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-8",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "613e275749ebd008e74bb62e",
+ "title": "Step 8"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-9",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6140827cff96e906bd38fc2b",
+ "title": "Step 9"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-10",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6140883f74224508174794c0",
+ "title": "Step 10"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-11",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "61408e4ae3e35d08feb260eb",
+ "title": "Step 11"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-12",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "61408f155e798909b6908712",
+ "title": "Step 12"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-13",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "614090d5a22b6f0a5a6b464c",
+ "title": "Step 13"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-14",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6141fabd6f75610664e908fd",
+ "title": "Step 14"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-15",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6141fed65b61320743da5894",
+ "title": "Step 15"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-16",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "614202874ca576084fca625f",
+ "title": "Step 16"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-17",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "614206033d366c090ca7dd42",
+ "title": "Step 17"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-18",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "61435e3c0679a306c20f1acc",
+ "title": "Step 18"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-19",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6143610161323a081b249c19",
+ "title": "Step 19"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-20",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6143639d5eddc7094161648c",
+ "title": "Step 20"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-21",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6143908b6aafb00a659ca189",
+ "title": "Step 21"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-22",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6143920c8eafb00b735746ce",
+ "title": "Step 22"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-23",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6143931a113bb80c45546287",
+ "title": "Step 23"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-24",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "614394fb41985e0d2012a93e",
+ "title": "Step 24"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-25",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6143956ed76ed60e012faa51",
+ "title": "Step 25"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-26",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "614396f7ae83f20ea6f9f4b3",
+ "title": "Step 26"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-27",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6143cb26f7edff2dc28f7da5",
+ "title": "Step 27"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-28",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6144e818fd5ea704fe56081d",
+ "title": "Step 28"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-29",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6144f8dc6849e405dd8bb829",
+ "title": "Step 29"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-30",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6145e6eeaa66c605eb087fe9",
+ "title": "Step 30"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-32",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6145e8b5080a5f06bb0223d0",
+ "title": "Step 32"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-33",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6145eb5f08a38a0786c7a80c",
+ "title": "Step 33"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-34",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6145ed1f22caab087630aaad",
+ "title": "Step 34"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-35",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6145ee65e2e1530938cb594d",
+ "title": "Step 35"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-36",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6145f02240ff8f09f7ec913c",
+ "title": "Step 36"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-37",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6145f14f019a4b0adb94b051",
+ "title": "Step 37"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-38",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6145f3a5cd9be60b9459cdd6",
+ "title": "Step 38"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-39",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6145f47393fbe70c4d885f9c",
+ "title": "Step 39"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-40",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6145f59029474c0d3dc1c8b8",
+ "title": "Step 40"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-41",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6145f685797bd30df9784e8c",
+ "title": "Step 41"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-42",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6145f829ac6a920ebf5797d7",
+ "title": "Step 42"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-43",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6145f8f8bcd4370f6509078e",
+ "title": "Step 43"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-44",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6145fb5018cb5b100cb2a88c",
+ "title": "Step 44"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-45",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6145fc3707fc3310c277f5c8",
+ "title": "Step 45"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-46",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "614796cb8086be482d60e0ac",
+ "title": "Step 46"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-47",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6147a14ef5668b5881ef2297",
+ "title": "Step 47"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-48",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "614878f7a412310647873015",
+ "title": "Step 48"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-49",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "61487b77d4a37707073a64e5",
+ "title": "Step 49"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-50",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "61487da611a65307e78d2c20",
+ "title": "Step 50"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-51",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "61487f703571b60899055cf9",
+ "title": "Step 51"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-52",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "614880dc16070e093e29bc56",
+ "title": "Step 52"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-53",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "614883b6fa720e09fb167de9",
+ "title": "Step 53"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-54",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "614884c1f5d6f30ab3d78cde",
+ "title": "Step 54"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-55",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "61488ecfd05e290b5712e6da",
+ "title": "Step 55"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-56",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6148d99cdc7acd0c519862cb",
+ "title": "Step 56"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-57",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6148da157cc0bd0d06df5c0a",
+ "title": "Step 57"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-58",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6148dc095264000dce348bf5",
+ "title": "Step 58"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-59",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6148dcaaf2e8750e6cb4501a",
+ "title": "Step 59"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-60",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6148dd31d210990f0fb140f8",
+ "title": "Step 60"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-61",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6148defa9c01520fb9d178a0",
+ "title": "Step 61"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-62",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6148dfab9b54c110577de165",
+ "title": "Step 62"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-63",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6148e0bcc13efd10f7d7a6a9",
+ "title": "Step 63"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-64",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6148e161ecec9511941f8833",
+ "title": "Step 64"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-65",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6148e28706b34912340fd042",
+ "title": "Step 65"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-66",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6148e335c1edd512d00e4691",
+ "title": "Step 66"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-67",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6148e41c728f65138addf9cc",
+ "title": "Step 67"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-68",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6148e5aeb102e3142de026a2",
+ "title": "Step 68"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-1",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "614ccc21ea91ef1736b9b578",
+ "title": "Step 1"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-accessibility-by-building-a-quiz/step-31",
+ "blockName": "Learn Accessibility by Building a Quiz"
+ },
+ "id": "6351e7a8684bf5377c4ee7f7",
+ "title": "Step 31"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-1",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f33071498eb2472b87ddee4",
+ "title": "Step 1"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-2",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3313e74582ad9d063e3a38",
+ "title": "Step 2"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-3",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f331e55dfab7a896e53c3a1",
+ "title": "Step 3"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-4",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3326b143638ee1a09ff1e3",
+ "title": "Step 4"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-5",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f33294a6af5e9188dbdb8f3",
+ "title": "Step 5"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-6",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f332a88dc25a0fd25c7687a",
+ "title": "Step 6"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-7",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f332b23c2045fb843337579",
+ "title": "Step 7"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-11",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f344f9c805cd193c33d829c",
+ "title": "Step 11"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-10",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f344fad8bf01691e71a30eb",
+ "title": "Step 10"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-9",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f344fbc22624a2976425065",
+ "title": "Step 9"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-8",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f344fc1520b6719f2e35605",
+ "title": "Step 8"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-13",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3477ae34c1239cafe128be",
+ "title": "Step 13"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-15",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3477ae8466a9a3d2cc953c",
+ "title": "Step 15"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-12",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3477ae9675db8bb7655b30",
+ "title": "Step 12"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-14",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3477aefa51bfc29327200b",
+ "title": "Step 14"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-16",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3477cb2e27333b1ab2b955",
+ "title": "Step 16"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-18",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3477cb303c5cb61b43aa9b",
+ "title": "Step 18"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-17",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3477cbcb6ba47918c1da92",
+ "title": "Step 17"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-19",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f34a1fd611d003edeafd681",
+ "title": "Step 19"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-24",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f356ed60785e1f3e9850b6e",
+ "title": "Step 24"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-22",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f356ed60a5decd94ab66986",
+ "title": "Step 22"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-26",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f356ed6199b0cdef1d2be8f",
+ "title": "Step 26"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-21",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f356ed63c7807a4f1e6d054",
+ "title": "Step 21"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-23",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f356ed63e0fa262326eef05",
+ "title": "Step 23"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-25",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f356ed656a336993abd9f7c",
+ "title": "Step 25"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-27",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f356ed69db0a491745e2bb6",
+ "title": "Step 27"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-20",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f356ed6cf6eab5f15f5cfe6",
+ "title": "Step 20"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-29",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f35e5c4321f818cdc4bed30",
+ "title": "Step 29"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-28",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f35e5c44359872a137bd98f",
+ "title": "Step 28"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-38",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3c866d0fc037f7311b4ac8",
+ "title": "Step 38"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-32",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3c866d28d7ad0de6470505",
+ "title": "Step 32"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-31",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3c866d5414453fc2d7b480",
+ "title": "Step 31"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-30",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3c866daec9a49519871816",
+ "title": "Step 30"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-37",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3c866dbf362f99b9a0c6d0",
+ "title": "Step 37"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-39",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3c866dd0d0275f01d4d847",
+ "title": "Step 39"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-36",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3c866de7a5b784048f94b1",
+ "title": "Step 36"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-41",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3cade94c6576e7f7b7953f",
+ "title": "Step 41"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-42",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3cade9993019e26313fa8e",
+ "title": "Step 42"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-46",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3cade99dda4e6071a85dfd",
+ "title": "Step 46"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-40",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3cade9fa77275d9f4efe62",
+ "title": "Step 40"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-66",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3ef6e01f288a026d709587",
+ "title": "Step 66"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-56",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3ef6e03d719d5ac4738993",
+ "title": "Step 56"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-55",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3ef6e04559b939080db057",
+ "title": "Step 55"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-54",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3ef6e050279c7a4a7101d3",
+ "title": "Step 54"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-57",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3ef6e05473f91f948724ab",
+ "title": "Step 57"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-58",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3ef6e056bdde6ae6892ba2",
+ "title": "Step 58"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-60",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3ef6e06d34faac0447fc44",
+ "title": "Step 60"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-63",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3ef6e07276f782bb46b93d",
+ "title": "Step 63"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-48",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3ef6e0819d4f23ca7285e6",
+ "title": "Step 48"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-61",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3ef6e087d56ed3ffdc36be",
+ "title": "Step 61"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-64",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3ef6e0a81099d9a697b550",
+ "title": "Step 64"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-65",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3ef6e0b431cc215bb16f55",
+ "title": "Step 65"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-47",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3ef6e0e0c3feaebcf647ad",
+ "title": "Step 47"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-59",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3ef6e0e9629bad967cd71e",
+ "title": "Step 59"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-53",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3ef6e0eaa7da26e3d34d78",
+ "title": "Step 53"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-62",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3ef6e0f8c230bdd2349716",
+ "title": "Step 62"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-67",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f3f26fa39591db45e5cd7a0",
+ "title": "Step 67"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-68",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f459225127805351a6ad057",
+ "title": "Step 68"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-69",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f459a7ceb8b5c446656d88b",
+ "title": "Step 69"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-70",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f459cf202c2a3472fae6a9f",
+ "title": "Step 70"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-71",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f459fd48bdc98491ca6d1a3",
+ "title": "Step 71"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-72",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f45a05977e2fa49d9119437",
+ "title": "Step 72"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-73",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f45a276c093334f0f6e9df4",
+ "title": "Step 73"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-74",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f45a5a7c49a8251f0bdb527",
+ "title": "Step 74"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-78",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f45a66d4a2b0453301e5a26",
+ "title": "Step 78"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-79",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f45b0731d39e15d54df4dfc",
+ "title": "Step 79"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-80",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f45b25e7ec2405f166b9de1",
+ "title": "Step 80"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-81",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f45b3c93c027860d9298dbd",
+ "title": "Step 81"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-82",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f45b45d099f3e621fbbb256",
+ "title": "Step 82"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-83",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f45b4c81cea7763550e40df",
+ "title": "Step 83"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-84",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f45b715301bbf667badc04a",
+ "title": "Step 84"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-85",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f46e270702a8456a664f0df",
+ "title": "Step 85"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-86",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f46e36e745ead58487aabf2",
+ "title": "Step 86"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-87",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f46e7a4750dd05b5a673920",
+ "title": "Step 87"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-88",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f46e8284aae155c83015dee",
+ "title": "Step 88"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-77",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f46ede1ff8fec5ba656b44c",
+ "title": "Step 77"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-75",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f46fc57528aa1c4b5ea7c2e",
+ "title": "Step 75"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-76",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f4701b942c824109626c3d8",
+ "title": "Step 76"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-89",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f475bb508746c16c9431d42",
+ "title": "Step 89"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-90",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f475e1c7f71a61d913836c6",
+ "title": "Step 90"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-45",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f47633757ae3469f2d33d2e",
+ "title": "Step 45"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-91",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f47fe7e31980053a8d4403b",
+ "title": "Step 91"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-49",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f716ad029ee4053c7027a7a",
+ "title": "Step 49"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-52",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f716bee5838c354c728a7c5",
+ "title": "Step 52"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-43",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f7691dafd882520797cd2f0",
+ "title": "Step 43"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-44",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f7692f7c5b3ce22a57788b6",
+ "title": "Step 44"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-33",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f769541be494f25449b292f",
+ "title": "Step 33"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-34",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f76967fad478126d6552b0d",
+ "title": "Step 34"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-35",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f769702e6e33127d14aa120",
+ "title": "Step 35"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-50",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f7b87422a560036fd03ccff",
+ "title": "Step 50"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-51",
+ "blockName": "Learn Basic CSS by Building a Cafe Menu"
+ },
+ "id": "5f7b88d37b1f98386f04edc0",
+ "title": "Step 51"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-1",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6140c7e645d8e905819f1dd4",
+ "title": "Step 1"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-2",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6140c9d35015ae0ba0c250e8",
+ "title": "Step 2"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-3",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6140cbeec34e970dfe75e710",
+ "title": "Step 3"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-4",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6140cd32d018ed0f600eefce",
+ "title": "Step 4"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-6",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6140cdebd39d6a101e747529",
+ "title": "Step 6"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-7",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6140cfc08ca9c5128c3e6478",
+ "title": "Step 7"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-8",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6140d0069049f5139d78da40",
+ "title": "Step 8"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-9",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6140d10d50636e14695013b2",
+ "title": "Step 9"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-10",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6140d1a351e88f159ed54fca",
+ "title": "Step 10"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-11",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6140d263016325162fd076fe",
+ "title": "Step 11"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-12",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6140d2b687a2cd17bac5730c",
+ "title": "Step 12"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-13",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6140d36b8b747718b50d4b7a",
+ "title": "Step 13"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-14",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6140d3dc359b371b1a21d783",
+ "title": "Step 14"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-15",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6140d4bc9db3c81c51a09ab7",
+ "title": "Step 15"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-16",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6140d94b5fab7f1d73c9bedb",
+ "title": "Step 16"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-17",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6140dc5e13d0c81e7496f182",
+ "title": "Step 17"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-18",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6140dd77e0bc5a1f70bd7466",
+ "title": "Step 18"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-19",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6140de31b1f5b420410728ff",
+ "title": "Step 19"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-20",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6140df547f09402144e40b92",
+ "title": "Step 20"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-21",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6140e0d875ec16262f26432b",
+ "title": "Step 21"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-22",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6140f4b5c1555a2960de1e5f",
+ "title": "Step 22"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-23",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "614100d7d335bb2a5ff74f1f",
+ "title": "Step 23"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-24",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "61410126fa3a6d2b3cda502e",
+ "title": "Step 24"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-25",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6141019eadec6d2c6c6f007b",
+ "title": "Step 25"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-26",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6141026ec9882f2d39dcf2b8",
+ "title": "Step 26"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-27",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6169ab1aaeb4cd1174def700",
+ "title": "Step 27"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-28",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6169b1357fcb701bb5efc619",
+ "title": "Step 28"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-29",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "6169b284950e171d8d0bb16a",
+ "title": "Step 29"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-animation-by-building-a-ferris-wheel/step-5",
+ "blockName": "Learn CSS Animation by Building a Ferris Wheel"
+ },
+ "id": "617ace7d831f9c16a569b38a",
+ "title": "Step 5"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-1",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61695197ac34f0407e339882",
+ "title": "Step 1"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-2",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61695ab9f6ffe951c16d03dd",
+ "title": "Step 2"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-3",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61695c4aad56f95497c19583",
+ "title": "Step 3"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-4",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61695d1fbc003856628bf561",
+ "title": "Step 4"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-5",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "616965351e74d4689eb6de30",
+ "title": "Step 5"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-6",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "616968c2c94c8071b349c146",
+ "title": "Step 6"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-7",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61696ef7ac756c829f9e4048",
+ "title": "Step 7"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-8",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "616971b3cd990186b66c99a1",
+ "title": "Step 8"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-9",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "616d3a67ccf800ad94ec89ae",
+ "title": "Step 9"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-10",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "616d47bc9eedc4bc7f621bec",
+ "title": "Step 10"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-11",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "616d4a84b756d9c4b8255093",
+ "title": "Step 11"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-12",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "616d50b93ba424d6282c99cf",
+ "title": "Step 12"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-13",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "616d525007b8c5d8b3308b1c",
+ "title": "Step 13"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-14",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "616d55bd160a95e22453a081",
+ "title": "Step 14"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-15",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "616d595270d902f0e7086e18",
+ "title": "Step 15"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-16",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61764c602bee6974e7790f35",
+ "title": "Step 16"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-17",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61764f23ea21477b76f3b80f",
+ "title": "Step 17"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-18",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61764f7e5240eb7ccc7f6a0a",
+ "title": "Step 18"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-19",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61764fdda535587e1fefb3aa",
+ "title": "Step 19"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-20",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "6176519636a76b810ab1219a",
+ "title": "Step 20"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-21",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "617b65579ce424bf5f02ca73",
+ "title": "Step 21"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-22",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "617b8b38f32bf2080a140675",
+ "title": "Step 22"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-23",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "617b8e0d93a8d10d9a90e720",
+ "title": "Step 23"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-24",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "617b92b9de349513466f6156",
+ "title": "Step 24"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-25",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "617b954d9f4f6217a749380e",
+ "title": "Step 25"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-26",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "617b97abd9f3f61d1590b815",
+ "title": "Step 26"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-27",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "617b9ad735109e217284e095",
+ "title": "Step 27"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-28",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "617bb5624a75e86463b7e638",
+ "title": "Step 28"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-29",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "617bb77353188166af43f3ac",
+ "title": "Step 29"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-30",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "617bb9fdef27bc6aa0470ac2",
+ "title": "Step 30"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-31",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "617bbb6b97a83f6d1f7d6e38",
+ "title": "Step 31"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-32",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "617bc3386dc7d07d6469bf20",
+ "title": "Step 32"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-33",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "617bc4824e233180553a8069",
+ "title": "Step 33"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-34",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "617bd6ec666b1da2587e4e37",
+ "title": "Step 34"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-35",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "618a00ed1ca871a2b3aca0cb",
+ "title": "Step 35"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-36",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "618a0927005553b74bfa05ae",
+ "title": "Step 36"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-37",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "618a0b2befb143baefab632b",
+ "title": "Step 37"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-38",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "618a1275e873dcc803c2d1aa",
+ "title": "Step 38"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-39",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "618a132676346ac9f7fd59dd",
+ "title": "Step 39"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-40",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "618a16873520a8d088ffdf44",
+ "title": "Step 40"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-41",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "618a16d21bd3dad1bb3aa8ef",
+ "title": "Step 41"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-42",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "619b72a0db211f1c29afb906",
+ "title": "Step 42"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-43",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "619b7396e57b771f903be90d",
+ "title": "Step 43"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-44",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "619b7424f43ec9215e538afe",
+ "title": "Step 44"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-45",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "619b74fa777a2b2473c94f82",
+ "title": "Step 45"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-46",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "619b761916dac02643940022",
+ "title": "Step 46"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-47",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "619b7c3c83de403126b69c1e",
+ "title": "Step 47"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-48",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "619b7fd56aa2253778bcf5f7",
+ "title": "Step 48"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-49",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61a489b8579e87364b2d2cdb",
+ "title": "Step 49"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-50",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61a493ead935c148d2b76312",
+ "title": "Step 50"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-53",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61a498399534644f59cff05e",
+ "title": "Step 53"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-54",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61a49d15bdbb5e57cc6fd280",
+ "title": "Step 54"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-55",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61a4a53c4459446dc134a1c6",
+ "title": "Step 55"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-56",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61a4a6e908bc34725b4c25ac",
+ "title": "Step 56"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-57",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61a4a7877da33a73a1c1723e",
+ "title": "Step 57"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-58",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61a4ac092eb21e7dbfe61c33",
+ "title": "Step 58"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-59",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61a4acbb5587197f68544d00",
+ "title": "Step 59"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-60",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61a4ada3aabeec822b2975d9",
+ "title": "Step 60"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-61",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61a4ae5f29eb5584187201c3",
+ "title": "Step 61"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-63",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61a5be9833e7dc178de2af10",
+ "title": "Step 63"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-64",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61a5bfe091060f1d6a629dd0",
+ "title": "Step 64"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-65",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61a5c906ab73313316e342f0",
+ "title": "Step 65"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-66",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61a5ca57f50ded36d33eef96",
+ "title": "Step 66"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-67",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61a5d594b887335228ee6533",
+ "title": "Step 67"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-68",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61a5d6701ee08953ca375243",
+ "title": "Step 68"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-69",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61a5d79c858bef560e26c685",
+ "title": "Step 69"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-70",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61a5d7ef1cfcf45764df07a2",
+ "title": "Step 70"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-71",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61adc60b69cd4b87739d2174",
+ "title": "Step 71"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-79",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61adc91467b5d59328b9f781",
+ "title": "Step 79"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-80",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61add79e739a5faee9d96080",
+ "title": "Step 80"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-81",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61add929e41980b1edbdba7e",
+ "title": "Step 81"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-82",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61addaf7e83988b59a7d18ff",
+ "title": "Step 82"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-83",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61ade49b2dad60c076cbd32d",
+ "title": "Step 83"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-72",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61b092eb9e7fc020b43b1bb2",
+ "title": "Step 72"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-73",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61b093179e7fc020b43b1bb3",
+ "title": "Step 73"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-74",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61b093219e7fc020b43b1bb4",
+ "title": "Step 74"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-75",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61b093329e7fc020b43b1bb5",
+ "title": "Step 75"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-76",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61b093429e7fc020b43b1bb6",
+ "title": "Step 76"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-77",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61b0934c9e7fc020b43b1bb7",
+ "title": "Step 77"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-78",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61b0936d9e7fc020b43b1bb8",
+ "title": "Step 78"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-51",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61b095989e7fc020b43b1bb9",
+ "title": "Step 51"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-52",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61b095a79e7fc020b43b1bba",
+ "title": "Step 52"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-62",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61b095c79e7fc020b43b1bbb",
+ "title": "Step 62"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-84",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61b09f739aa6572d2064f9b8",
+ "title": "Step 84"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-85",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61b0a1b2af494934b7ec1a72",
+ "title": "Step 85"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-86",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61b0a44a6b865738ba49b9fb",
+ "title": "Step 86"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-87",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61b306305810f1c9040ce5a2",
+ "title": "Step 87"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-88",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61b30995968123ceb6b76167",
+ "title": "Step 88"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-89",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61b30a286c228bd0c493c09a",
+ "title": "Step 89"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-90",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61b31287fb580ae75a486047",
+ "title": "Step 90"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-91",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61b315e76a63b3ecbbb11b75",
+ "title": "Step 91"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-92",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61b3183655ec10efd8c0bb07",
+ "title": "Step 92"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-93",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61b31a451057fff645ec09be",
+ "title": "Step 93"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-colors-by-building-a-set-of-colored-markers/step-94",
+ "blockName": "Learn CSS Colors by Building a Set of Colored Markers"
+ },
+ "id": "61b31cd7b0c76bfc076b4719",
+ "title": "Step 94"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-flexbox-by-building-a-photo-gallery/step-1",
+ "blockName": "Learn CSS Flexbox by Building a Photo Gallery"
+ },
+ "id": "61537485c4f2a624f18d7794",
+ "title": "Step 1"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-flexbox-by-building-a-photo-gallery/step-2",
+ "blockName": "Learn CSS Flexbox by Building a Photo Gallery"
+ },
+ "id": "61537a8054753e2f1f2a1574",
+ "title": "Step 2"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-flexbox-by-building-a-photo-gallery/step-3",
+ "blockName": "Learn CSS Flexbox by Building a Photo Gallery"
+ },
+ "id": "61537bb9b1a29430ac15ad38",
+ "title": "Step 3"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-flexbox-by-building-a-photo-gallery/step-4",
+ "blockName": "Learn CSS Flexbox by Building a Photo Gallery"
+ },
+ "id": "61537c5f81f0cf325b4a854c",
+ "title": "Step 4"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-flexbox-by-building-a-photo-gallery/step-5",
+ "blockName": "Learn CSS Flexbox by Building a Photo Gallery"
+ },
+ "id": "61537c9eecea6a335db6da79",
+ "title": "Step 5"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-flexbox-by-building-a-photo-gallery/step-6",
+ "blockName": "Learn CSS Flexbox by Building a Photo Gallery"
+ },
+ "id": "61537d86bdc3dd343688fceb",
+ "title": "Step 6"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-flexbox-by-building-a-photo-gallery/step-7",
+ "blockName": "Learn CSS Flexbox by Building a Photo Gallery"
+ },
+ "id": "615380dff67172357fcf0425",
+ "title": "Step 7"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-flexbox-by-building-a-photo-gallery/step-9",
+ "blockName": "Learn CSS Flexbox by Building a Photo Gallery"
+ },
+ "id": "6153893900438b4643590367",
+ "title": "Step 9"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-flexbox-by-building-a-photo-gallery/step-10",
+ "blockName": "Learn CSS Flexbox by Building a Photo Gallery"
+ },
+ "id": "6153897c27f6334716ee5abe",
+ "title": "Step 10"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-flexbox-by-building-a-photo-gallery/step-11",
+ "blockName": "Learn CSS Flexbox by Building a Photo Gallery"
+ },
+ "id": "615389bd81347947ea7ba896",
+ "title": "Step 11"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-flexbox-by-building-a-photo-gallery/step-12",
+ "blockName": "Learn CSS Flexbox by Building a Photo Gallery"
+ },
+ "id": "6153908a366afb4d57185c8d",
+ "title": "Step 12"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-flexbox-by-building-a-photo-gallery/step-13",
+ "blockName": "Learn CSS Flexbox by Building a Photo Gallery"
+ },
+ "id": "615392916d83fa4f02f7e2cf",
+ "title": "Step 13"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-flexbox-by-building-a-photo-gallery/step-14",
+ "blockName": "Learn CSS Flexbox by Building a Photo Gallery"
+ },
+ "id": "6153938dce8b294ff8f5a4e9",
+ "title": "Step 14"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-flexbox-by-building-a-photo-gallery/step-15",
+ "blockName": "Learn CSS Flexbox by Building a Photo Gallery"
+ },
+ "id": "6153947986535e5117e60615",
+ "title": "Step 15"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-flexbox-by-building-a-photo-gallery/step-16",
+ "blockName": "Learn CSS Flexbox by Building a Photo Gallery"
+ },
+ "id": "61539e07e7430b528fbffe21",
+ "title": "Step 16"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-flexbox-by-building-a-photo-gallery/step-17",
+ "blockName": "Learn CSS Flexbox by Building a Photo Gallery"
+ },
+ "id": "61539f32a206bd53ec116465",
+ "title": "Step 17"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-flexbox-by-building-a-photo-gallery/step-18",
+ "blockName": "Learn CSS Flexbox by Building a Photo Gallery"
+ },
+ "id": "6153a04847abee57a3a406ac",
+ "title": "Step 18"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-flexbox-by-building-a-photo-gallery/step-19",
+ "blockName": "Learn CSS Flexbox by Building a Photo Gallery"
+ },
+ "id": "6153a3485f0b20591d26d2a1",
+ "title": "Step 19"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-flexbox-by-building-a-photo-gallery/step-20",
+ "blockName": "Learn CSS Flexbox by Building a Photo Gallery"
+ },
+ "id": "6153a3952facd25a83fe8083",
+ "title": "Step 20"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-flexbox-by-building-a-photo-gallery/step-21",
+ "blockName": "Learn CSS Flexbox by Building a Photo Gallery"
+ },
+ "id": "6153a3ebb4f7f05b8401b716",
+ "title": "Step 21"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-flexbox-by-building-a-photo-gallery/step-8",
+ "blockName": "Learn CSS Flexbox by Building a Photo Gallery"
+ },
+ "id": "615f171d05def3218035dc85",
+ "title": "Step 8"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-1",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "61437d575fb98f57fa8f7f36",
+ "title": "Step 1"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-2",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "614385513d91ae5c251c2052",
+ "title": "Step 2"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-3",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6143862a5e54455d262c212e",
+ "title": "Step 3"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-4",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6143869bb45bd85e3b1926aa",
+ "title": "Step 4"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-7",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "614387cbefeeba5f3654a291",
+ "title": "Step 7"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-9",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "614389f601bb4f611db98563",
+ "title": "Step 9"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-10",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "61438b5b66d76a6264430f2a",
+ "title": "Step 10"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-11",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "61438ec09438696391076d6a",
+ "title": "Step 11"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-12",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "61439dc084fa5f659cf75d7c",
+ "title": "Step 12"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-13",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "61439dfc811e12666b04be6f",
+ "title": "Step 13"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-14",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "61439e33e4fb7967609e0c83",
+ "title": "Step 14"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-15",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6143a1a228f7d068ab16a130",
+ "title": "Step 15"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-16",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6143a73279ce6369de4b9bcc",
+ "title": "Step 16"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-17",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6143a778bffc206ac6b1dbe3",
+ "title": "Step 17"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-18",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6143a83fcc32c26bcfae3efa",
+ "title": "Step 18"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-19",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6143b97c06c3306d23d5da47",
+ "title": "Step 19"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-20",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6143b9e1f5035c6e5f2a8231",
+ "title": "Step 20"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-21",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6143bb50e8e48c6f5ef9d8d5",
+ "title": "Step 21"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-22",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6143c2a363865c715f1a3f72",
+ "title": "Step 22"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-23",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6143cd08fe927072ca3a371d",
+ "title": "Step 23"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-24",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6143cdf48b634a747de42104",
+ "title": "Step 24"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-25",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6143d003ad9e9d76766293ec",
+ "title": "Step 25"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-26",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6143d2842b497779bad947de",
+ "title": "Step 26"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-27",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6144d66a5358db0c80628757",
+ "title": "Step 27"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-28",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6144d7dbdd3e580da730ff45",
+ "title": "Step 28"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-29",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6144de308591ec10e27d5383",
+ "title": "Step 29"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-30",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6144e1ba93e435127a7f516d",
+ "title": "Step 30"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-31",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6144ee46a9d6e614c598cc05",
+ "title": "Step 31"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-32",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6144ee790af79815ad15a832",
+ "title": "Step 32"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-33",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6144f1410990ea17187a722b",
+ "title": "Step 33"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-34",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6144f3818bfbc51844152e36",
+ "title": "Step 34"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-35",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6144f42204c8c8195f1f3345",
+ "title": "Step 35"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-36",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6144f47b7c631e1a6f304dd5",
+ "title": "Step 36"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-37",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148b07081759c2c691166a9",
+ "title": "Step 37"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-38",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148b0d764e4192e5712ed92",
+ "title": "Step 38"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-39",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148b185ef37522f688316b0",
+ "title": "Step 39"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-40",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148b30464daf630848c21d4",
+ "title": "Step 40"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-41",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148b4b150434734143db6f2",
+ "title": "Step 41"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-42",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148b5623efa8f369f2c3643",
+ "title": "Step 42"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-44",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148b59ef318e03875f35c4a",
+ "title": "Step 44"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-45",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148bd62bbb8c83a5f1fc1b3",
+ "title": "Step 45"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-46",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148be3d605d6b3ca9425d11",
+ "title": "Step 46"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-47",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148be82ca63c63daa8cca49",
+ "title": "Step 47"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-48",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148bf49fcc7913f05dbf9b7",
+ "title": "Step 48"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-49",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148bfc43df3bc40fe0e6405",
+ "title": "Step 49"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-50",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148c004ffc8434252940dc3",
+ "title": "Step 50"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-51",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148c224ecb157439bc5247c",
+ "title": "Step 51"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-52",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148c434bd731d45617a76c6",
+ "title": "Step 52"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-53",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148c5036ddad94692a66230",
+ "title": "Step 53"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-54",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148c58bace368497fb11bcf",
+ "title": "Step 54"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-55",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148c6aa9981d74af202125e",
+ "title": "Step 55"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-56",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148c721e74ecd4c619ae51c",
+ "title": "Step 56"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-57",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148ceaf5d897d4d8b3554b3",
+ "title": "Step 57"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-58",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148cf094b3f2b4e8a032c63",
+ "title": "Step 58"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-59",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148d0b863d10d50544ace0e",
+ "title": "Step 59"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-60",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148d1bdf39c5b5186f5974b",
+ "title": "Step 60"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-61",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148d1f9eb63c252e1f8acc4",
+ "title": "Step 61"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-62",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148d2444d01ab541e64a1e4",
+ "title": "Step 62"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-63",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148d33e31fccf558696c745",
+ "title": "Step 63"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-64",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148d3fff5186b57123d97e2",
+ "title": "Step 64"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-65",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148d4d57b965358c9fa38bf",
+ "title": "Step 65"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-66",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148d7720f0db36775db868a",
+ "title": "Step 66"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-67",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148d94fdf6a5d6899f8ff15",
+ "title": "Step 67"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-68",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148d9825b50a3698aeee644",
+ "title": "Step 68"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-69",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148e162e255676ae0da6a76",
+ "title": "Step 69"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-70",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148e19c3e26436be0155690",
+ "title": "Step 70"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-71",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148e246146b646cf4255f0c",
+ "title": "Step 71"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-72",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148e2dcdd60306dd77d41cc",
+ "title": "Step 72"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-73",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148e4d6861a486f60681f36",
+ "title": "Step 73"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-74",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148e5a204d99e70343a63e4",
+ "title": "Step 74"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-75",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148e62a6f768f71c4f04828",
+ "title": "Step 75"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-76",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148e789329dc9736ce59b85",
+ "title": "Step 76"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-77",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148f34ebedc2274bceeb99c",
+ "title": "Step 77"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-78",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148f600cde42b7670c2611f",
+ "title": "Step 78"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-79",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148f693e0728f77c87f3020",
+ "title": "Step 79"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-80",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6148f6f7d8914c78e93136ca",
+ "title": "Step 80"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-43",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "614e0e503b110f76d3ac2ff6",
+ "title": "Step 43"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-6",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "614e0e588f0e8a772a8a81a6",
+ "title": "Step 6"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-5",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6165d3b702a5d92ad970b30c",
+ "title": "Step 5"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-grid-by-building-a-magazine/step-8",
+ "blockName": "Learn CSS Grid by Building a Magazine"
+ },
+ "id": "6169cd8a558aa8434e0ad7f6",
+ "title": "Step 8"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-1",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619665c9abd72906f3ad30f9",
+ "title": "Step 1"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-2",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "61967e74a8e3690ab6292daa",
+ "title": "Step 2"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-3",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "61968df2acd5550bf1616c34",
+ "title": "Step 3"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-5",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "61968e9243a4090cc805531c",
+ "title": "Step 5"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-6",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "61968f8877c6720d6d61aaf5",
+ "title": "Step 6"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-7",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619691693bc14b0e528f5a20",
+ "title": "Step 7"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-8",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "6196928658b6010f28c39484",
+ "title": "Step 8"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-10",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619692ff79f5770fc6d8c0b4",
+ "title": "Step 10"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-11",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "6196990f966e8f10a40094f6",
+ "title": "Step 11"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-12",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619699c10a0f6e11591d73c4",
+ "title": "Step 12"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-13",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "61969aa6acef5b12200f672e",
+ "title": "Step 13"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-14",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "61969c487ced6f12db8fef94",
+ "title": "Step 14"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-15",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "61969d66cfcdba137d021558",
+ "title": "Step 15"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-16",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "61969e7451455614217e901b",
+ "title": "Step 16"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-17",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "6196adc17f77a714d51485f2",
+ "title": "Step 17"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-18",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "6196aead7ac7bf1584b17a7f",
+ "title": "Step 18"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-19",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "6196ce0415498d2463989e84",
+ "title": "Step 19"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-20",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "6196cee94c6da1253809dff9",
+ "title": "Step 20"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-21",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "6196d00a5d7292262bc02f4c",
+ "title": "Step 21"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-22",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "6196d0cda039d026f7f78d1e",
+ "title": "Step 22"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-24",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "6196d213d99f16287bff22ae",
+ "title": "Step 24"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-25",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "6196d2c0f22ca0293107c048",
+ "title": "Step 25"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-26",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "6196d32d1340d829f0f6f57d",
+ "title": "Step 26"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-27",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "6196d41d40bf9b2aaea5d520",
+ "title": "Step 27"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-28",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "6197cff995d03905b0cca8ad",
+ "title": "Step 28"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-29",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "6197f40a16afea068c7e60c8",
+ "title": "Step 29"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-9",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "6197f667297bb30a552ce017",
+ "title": "Step 9"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-30",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "61993b72e874e709b8dfd666",
+ "title": "Step 30"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-31",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "61993cf26a8e0f0a553db223",
+ "title": "Step 31"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-32",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "61993dbb35adf30b10d49e38",
+ "title": "Step 32"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-33",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "61993e9adc9e9a0bb4d28fff",
+ "title": "Step 33"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-34",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "6199409834ccaf0d10736596",
+ "title": "Step 34"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-35",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "6199429802b7c10dc79ff871",
+ "title": "Step 35"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-36",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619943285a41720e6370d985",
+ "title": "Step 36"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-37",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619943876b706d0f35c01dbc",
+ "title": "Step 37"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-38",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "6199442866286d0ff421a4fc",
+ "title": "Step 38"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-39",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619bcf239fc15905ecd66fce",
+ "title": "Step 39"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-40",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619be73b3c806006ccc00bb0",
+ "title": "Step 40"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-41",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619be7af7b0bf60770f5d2a4",
+ "title": "Step 41"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-42",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619be80062551a080e32c821",
+ "title": "Step 42"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-43",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619be8ce4ea49008c5bfbc30",
+ "title": "Step 43"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-44",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619be946958c6009844f1dee",
+ "title": "Step 44"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-45",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619c155df0063a0a3fec0e32",
+ "title": "Step 45"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-46",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619c16debd0c270b01c5ce38",
+ "title": "Step 46"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-47",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619cfdf2e63ddf05feab86ad",
+ "title": "Step 47"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-48",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d019488f98c06acbbb71a",
+ "title": "Step 48"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-49",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d022dc8400c0763829a17",
+ "title": "Step 49"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-50",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d02c7bc95bf0827a5d296",
+ "title": "Step 50"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-51",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d033915012509031f309a",
+ "title": "Step 51"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-52",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d03dadadb6509a16f4f5f",
+ "title": "Step 52"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-53",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d0503e03a790a4179d463",
+ "title": "Step 53"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-54",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d05c54dabca0b10058235",
+ "title": "Step 54"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-55",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d0882f54bf40bdc4671ed",
+ "title": "Step 55"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-56",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d090cd8d6db0c93dc5087",
+ "title": "Step 56"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-57",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d0b51ca42ed0d74582186",
+ "title": "Step 57"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-58",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d0bc9cb05360e1bf549c3",
+ "title": "Step 58"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-59",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d0c1594c38c0ebae75878",
+ "title": "Step 59"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-60",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d0d18ca99870f884a7bff",
+ "title": "Step 60"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-61",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d0daf214542102739b0da",
+ "title": "Step 61"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-62",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d0e56f9ca9710fcb974e3",
+ "title": "Step 62"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-63",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d0eec0ac40611b41e2ccc",
+ "title": "Step 63"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-64",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d0fc9825c271253df28d4",
+ "title": "Step 64"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-65",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d102d786c3d13124c37c6",
+ "title": "Step 65"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-66",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d107edf7ddf13cc77106a",
+ "title": "Step 66"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-67",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d10cc98145f14820399c5",
+ "title": "Step 67"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-68",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d115e2adcd71538e82ebb",
+ "title": "Step 68"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-69",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d11e6d5ef9515d2a16033",
+ "title": "Step 69"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-70",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d129a417d0716a94de913",
+ "title": "Step 70"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-71",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d1340361095175f4b5115",
+ "title": "Step 71"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-72",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d15797b580c1828b05426",
+ "title": "Step 72"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-73",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d15d955d9d418c4487bbc",
+ "title": "Step 73"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-74",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d1629a8adc61960ca8b40",
+ "title": "Step 74"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-75",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d1c5fc9f8941a400955da",
+ "title": "Step 75"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-76",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d1dab9ff3421ae1976991",
+ "title": "Step 76"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-77",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d1deb8b04811b8839ffe4",
+ "title": "Step 77"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-78",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d1e7a8e81a61c5a819dc4",
+ "title": "Step 78"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-79",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d1ed33c9a071cf657a0d6",
+ "title": "Step 79"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-80",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d1fb5d244c31db8a7fdb7",
+ "title": "Step 80"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-81",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d204bd73ae51e743b8e94",
+ "title": "Step 81"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-82",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d20b12996101f430920fb",
+ "title": "Step 82"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-83",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d21fe6a3f9b2016be9d9d",
+ "title": "Step 83"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-84",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d229b0e542520cd91c685",
+ "title": "Step 84"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-85",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d23089e787e216a7043d6",
+ "title": "Step 85"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-86",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d237a107c10221ed743fa",
+ "title": "Step 86"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-87",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d26b12e651022d80cd017",
+ "title": "Step 87"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-88",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d2712853306238f41828e",
+ "title": "Step 88"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-89",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d2b7a84e78b246f2d17a2",
+ "title": "Step 89"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-90",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d2bd9c1d43c2526e96f1f",
+ "title": "Step 90"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-91",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d2d4e80400325ff89664a",
+ "title": "Step 91"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-92",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d2ebc81ba81271460850d",
+ "title": "Step 92"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-93",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d2f0e9440bc27caee1cec",
+ "title": "Step 93"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-94",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d2fd3ff4f772882e3d998",
+ "title": "Step 94"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-95",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d30350883802921bfcccc",
+ "title": "Step 95"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-96",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d324f5915c929f36ae91d",
+ "title": "Step 96"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-97",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d32c7fa21f32aaa91d499",
+ "title": "Step 97"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-98",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d333b738e3c2b5d58b095",
+ "title": "Step 98"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-99",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d337765b9f02c10e93722",
+ "title": "Step 99"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-100",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d33c51140292cc5a21742",
+ "title": "Step 100"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-101",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d3482f505452d861d0f62",
+ "title": "Step 101"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-102",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d3561a951bf2e41a24f10",
+ "title": "Step 102"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-103",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d36103839c82efa95dd34",
+ "title": "Step 103"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-104",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "619d3711d04d623000013e9e",
+ "title": "Step 104"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-4",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "61a8fe15a6a31306e60d1e89",
+ "title": "Step 4"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-1",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98c9",
+ "title": "Step 1"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-2",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98ca",
+ "title": "Step 2"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-3",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98cb",
+ "title": "Step 3"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-4",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98cc",
+ "title": "Step 4"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-5",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98cd",
+ "title": "Step 5"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-6",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98ce",
+ "title": "Step 6"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-7",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98cf",
+ "title": "Step 7"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-8",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98d0",
+ "title": "Step 8"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-9",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98d1",
+ "title": "Step 9"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-10",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98d2",
+ "title": "Step 10"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-11",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98d3",
+ "title": "Step 11"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-12",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98d4",
+ "title": "Step 12"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-13",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98d5",
+ "title": "Step 13"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-14",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98d6",
+ "title": "Step 14"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-15",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98d7",
+ "title": "Step 15"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-16",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98d8",
+ "title": "Step 16"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-17",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98d9",
+ "title": "Step 17"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-18",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98da",
+ "title": "Step 18"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-19",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98db",
+ "title": "Step 19"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-20",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98dc",
+ "title": "Step 20"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-21",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98dd",
+ "title": "Step 21"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-22",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98de",
+ "title": "Step 22"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-23",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98df",
+ "title": "Step 23"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-24",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98e0",
+ "title": "Step 24"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-25",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98e1",
+ "title": "Step 25"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-26",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98e2",
+ "title": "Step 26"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-27",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98e3",
+ "title": "Step 27"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-28",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98e4",
+ "title": "Step 28"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-29",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98e5",
+ "title": "Step 29"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-30",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98e6",
+ "title": "Step 30"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-31",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98e7",
+ "title": "Step 31"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-32",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98e8",
+ "title": "Step 32"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-33",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98e9",
+ "title": "Step 33"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-34",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98ea",
+ "title": "Step 34"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-35",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98eb",
+ "title": "Step 35"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-36",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98ec",
+ "title": "Step 36"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-37",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98ed",
+ "title": "Step 37"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-38",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98ee",
+ "title": "Step 38"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-39",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98ef",
+ "title": "Step 39"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-40",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98f0",
+ "title": "Step 40"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-41",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98f1",
+ "title": "Step 41"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-42",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98f2",
+ "title": "Step 42"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-43",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98f3",
+ "title": "Step 43"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-44",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98f4",
+ "title": "Step 44"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-45",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98f5",
+ "title": "Step 45"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-46",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98f6",
+ "title": "Step 46"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-47",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98f7",
+ "title": "Step 47"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-48",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98f8",
+ "title": "Step 48"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-49",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98f9",
+ "title": "Step 49"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-50",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98fa",
+ "title": "Step 50"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-51",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98fb",
+ "title": "Step 51"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-52",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98fc",
+ "title": "Step 52"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-53",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98fd",
+ "title": "Step 53"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-54",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98fe",
+ "title": "Step 54"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-55",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e98ff",
+ "title": "Step 55"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-56",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9900",
+ "title": "Step 56"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-57",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9901",
+ "title": "Step 57"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-58",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9902",
+ "title": "Step 58"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-59",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9903",
+ "title": "Step 59"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-60",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9904",
+ "title": "Step 60"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-61",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9905",
+ "title": "Step 61"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-62",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9906",
+ "title": "Step 62"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-63",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9907",
+ "title": "Step 63"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-64",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9908",
+ "title": "Step 64"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-65",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9909",
+ "title": "Step 65"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-66",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e990a",
+ "title": "Step 66"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-67",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e990b",
+ "title": "Step 67"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-68",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e990c",
+ "title": "Step 68"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-69",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e990d",
+ "title": "Step 69"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-70",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e990e",
+ "title": "Step 70"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-71",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e990f",
+ "title": "Step 71"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-72",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9910",
+ "title": "Step 72"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-73",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9911",
+ "title": "Step 73"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-74",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9912",
+ "title": "Step 74"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-75",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9913",
+ "title": "Step 75"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-76",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9914",
+ "title": "Step 76"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-106",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9915",
+ "title": "Step 106"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-77",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9916",
+ "title": "Step 77"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-78",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9917",
+ "title": "Step 78"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-79",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9918",
+ "title": "Step 79"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-80",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9919",
+ "title": "Step 80"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-81",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e991a",
+ "title": "Step 81"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-82",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e991b",
+ "title": "Step 82"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-83",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e991c",
+ "title": "Step 83"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-84",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e991d",
+ "title": "Step 84"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-85",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e991e",
+ "title": "Step 85"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-86",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e991f",
+ "title": "Step 86"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-87",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9920",
+ "title": "Step 87"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-88",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9921",
+ "title": "Step 88"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-89",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9922",
+ "title": "Step 89"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-90",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9923",
+ "title": "Step 90"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-91",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9924",
+ "title": "Step 91"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-92",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9925",
+ "title": "Step 92"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-93",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9926",
+ "title": "Step 93"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-94",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9927",
+ "title": "Step 94"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-95",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9928",
+ "title": "Step 95"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-96",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9929",
+ "title": "Step 96"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-97",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e992a",
+ "title": "Step 97"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-98",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e992b",
+ "title": "Step 98"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-99",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e992c",
+ "title": "Step 99"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-100",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e992d",
+ "title": "Step 100"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-101",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e992e",
+ "title": "Step 101"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-102",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e992f",
+ "title": "Step 102"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-103",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9930",
+ "title": "Step 103"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-109",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9931",
+ "title": "Step 109"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-104",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9932",
+ "title": "Step 104"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-105",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9933",
+ "title": "Step 105"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-107",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9934",
+ "title": "Step 107"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-108",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9935",
+ "title": "Step 108"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-110",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9936",
+ "title": "Step 110"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-111",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9937",
+ "title": "Step 111"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-112",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9938",
+ "title": "Step 112"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-113",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e9939",
+ "title": "Step 113"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-114",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e993a",
+ "title": "Step 114"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-115",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e993b",
+ "title": "Step 115"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-116",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e993c",
+ "title": "Step 116"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-117",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e993d",
+ "title": "Step 117"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-variables-by-building-a-city-skyline/step-118",
+ "blockName": "Learn CSS Variables by Building a City Skyline"
+ },
+ "id": "5d822fd413a79914d39e993e",
+ "title": "Step 118"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-1",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5dc174fcf86c76b9248c6eb2",
+ "title": "Step 1"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-2",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5dc1798ff86c76b9248c6eb3",
+ "title": "Step 2"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-3",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5dc17d3bf86c76b9248c6eb4",
+ "title": "Step 3"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-4",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5dc17dc8f86c76b9248c6eb5",
+ "title": "Step 4"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-5",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5dc2385ff86c76b9248c6eb7",
+ "title": "Step 5"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-6",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5dc23991f86c76b9248c6eb8",
+ "title": "Step 6"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-7",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5dc23f9bf86c76b9248c6eba",
+ "title": "Step 7"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-8",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5dc24073f86c76b9248c6ebb",
+ "title": "Step 8"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-9",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5dc24165f86c76b9248c6ebc",
+ "title": "Step 9"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-10",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5dc24614f86c76b9248c6ebd",
+ "title": "Step 10"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-11",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ddbd81294d8ddc1510a8e56",
+ "title": "Step 11"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-12",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5dfa22d1b521be39a3de7be0",
+ "title": "Step 12"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-14",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5dfa2407b521be39a3de7be1",
+ "title": "Step 14"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-15",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5dfa30b9eacea3f48c6300ad",
+ "title": "Step 15"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-18",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5dfa3589eacea3f48c6300ae",
+ "title": "Step 18"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-19",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5dfa371beacea3f48c6300af",
+ "title": "Step 19"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-20",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5dfa37b9eacea3f48c6300b0",
+ "title": "Step 20"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-21",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5dfb5ecbeacea3f48c6300b1",
+ "title": "Step 21"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-22",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5dfb6250eacea3f48c6300b2",
+ "title": "Step 22"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-23",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5dfb655eeacea3f48c6300b3",
+ "title": "Step 23"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-24",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5dfb6a35eacea3f48c6300b4",
+ "title": "Step 24"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-25",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804d0",
+ "title": "Step 25"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-26",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804d1",
+ "title": "Step 26"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-27",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804d2",
+ "title": "Step 27"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-28",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804d3",
+ "title": "Step 28"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-32",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804d4",
+ "title": "Step 32"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-34",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804d5",
+ "title": "Step 34"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-35",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804d6",
+ "title": "Step 35"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-36",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804d7",
+ "title": "Step 36"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-37",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804d8",
+ "title": "Step 37"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-40",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804d9",
+ "title": "Step 40"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-42",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804da",
+ "title": "Step 42"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-41",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804db",
+ "title": "Step 41"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-44",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804dc",
+ "title": "Step 44"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-45",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804dd",
+ "title": "Step 45"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-48",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804de",
+ "title": "Step 48"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-46",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804df",
+ "title": "Step 46"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-50",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804e1",
+ "title": "Step 50"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-54",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804e2",
+ "title": "Step 54"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-58",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804e3",
+ "title": "Step 58"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-61",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804e5",
+ "title": "Step 61"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-62",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804e7",
+ "title": "Step 62"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-63",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804e8",
+ "title": "Step 63"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-64",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804e9",
+ "title": "Step 64"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-65",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804ea",
+ "title": "Step 65"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-66",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804eb",
+ "title": "Step 66"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-67",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804ec",
+ "title": "Step 67"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-68",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5ef9b03c81a63668521804ee",
+ "title": "Step 68"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-29",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5efada803cbd2bbdab94e332",
+ "title": "Step 29"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-30",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5efae0543cbd2bbdab94e333",
+ "title": "Step 30"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-31",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5efae16e3cbd2bbdab94e334",
+ "title": "Step 31"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-38",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5efb23e70dc218d6c85f89b1",
+ "title": "Step 38"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-43",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5efb2c990dc218d6c85f89b2",
+ "title": "Step 43"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-56",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5efc4f528d6a74d05e68af74",
+ "title": "Step 56"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-57",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5efc518e8d6a74d05e68af75",
+ "title": "Step 57"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-55",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5efc54138d6a74d05e68af76",
+ "title": "Step 55"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-59",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5efc575c8d6a74d05e68af77",
+ "title": "Step 59"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-47",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5f05a1d8e233dff4a68508d8",
+ "title": "Step 47"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-16",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5f07be6ef7412fbad0c5626b",
+ "title": "Step 16"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-17",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5f07c98cdb9413cbd4b16750",
+ "title": "Step 17"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-33",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5f07fb1579dc934717801375",
+ "title": "Step 33"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-51",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5f0d48e7b435f13ab6550051",
+ "title": "Step 51"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-52",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5f0d4ab1b435f13ab6550052",
+ "title": "Step 52"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-53",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5f0d4d04b435f13ab6550053",
+ "title": "Step 53"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-49",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5f1a80975fc4bcae0edb3497",
+ "title": "Step 49"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-60",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "5f1a89f1190aff21ae42105a",
+ "title": "Step 60"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-69",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "62bb4009e3458a128ff57d5d",
+ "title": "Step 69"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-13",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "62dabe2ef403a12d5d295273",
+ "title": "Step 13"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-39",
+ "blockName": "Learn HTML by Building a Cat Photo App"
+ },
+ "id": "7cf9b03d81a65668421804c3",
+ "title": "Step 39"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-1",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60eebd07ea685b0e777b5583",
+ "title": "Step 1"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-2",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60f027099a15b00485563dd2",
+ "title": "Step 2"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-3",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60f027c87bc98f050395c139",
+ "title": "Step 3"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-4",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60f0286404aefb0562a4fdf9",
+ "title": "Step 4"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-6",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60f02e7361b68405e27b62a5",
+ "title": "Step 6"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-7",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60f030d388cb74067cf291c3",
+ "title": "Step 7"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-8",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60f1922fcbd2410527b3bd89",
+ "title": "Step 8"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-9",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60f1a5e2d2c23707a4f9a660",
+ "title": "Step 9"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-10",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60f1a9cbd23023082e149fee",
+ "title": "Step 10"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-11",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60f5c3e399ff1a05629964e4",
+ "title": "Step 11"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-13",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60f5cb8875ab6a0610f05071",
+ "title": "Step 13"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-14",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60f5d2776c854e069560fbe6",
+ "title": "Step 14"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-15",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60f5dc35c07ac1078f140916",
+ "title": "Step 15"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-16",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60f803d5241e6a0433a523a1",
+ "title": "Step 16"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-17",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60f805f813eaf2049bc2ceea",
+ "title": "Step 17"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-19",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60f80e0081e0f2052ae5b505",
+ "title": "Step 19"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-20",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60f81167d0d4910809f88945",
+ "title": "Step 20"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-21",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60f81616cff80508badf9ad5",
+ "title": "Step 21"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-22",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60f83e7bfc09900959f41e20",
+ "title": "Step 22"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-23",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60f84ec41116b209c280ba91",
+ "title": "Step 23"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-24",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60f852f645b5310a8264f555",
+ "title": "Step 24"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-25",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60f85a62fb30c80bcea0cedb",
+ "title": "Step 25"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-26",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60f8604682407e0d017bbf7f",
+ "title": "Step 26"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-27",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60f8618d191b940d62038513",
+ "title": "Step 27"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-28",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60fab4a123ce4b04526b082b",
+ "title": "Step 28"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-30",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60fab8367d35de04e5cb7929",
+ "title": "Step 30"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-31",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60fab9f17fa294054b74228c",
+ "title": "Step 31"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-32",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60fabf0dd4959805dbae09e6",
+ "title": "Step 32"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-33",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60fac4095512d3066053d73c",
+ "title": "Step 33"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-34",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60fac56271087806def55b33",
+ "title": "Step 34"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-35",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60fac8d7fdfaee0796934f20",
+ "title": "Step 35"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-36",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60faca286cb48b07f6482970",
+ "title": "Step 36"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-37",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60facde2d0dc61085b41063f",
+ "title": "Step 37"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-39",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60facf914c7b9b08d7510c2c",
+ "title": "Step 39"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-40",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60fad0a812d9890938524f50",
+ "title": "Step 40"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-41",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60fad1cafcde010995e15306",
+ "title": "Step 41"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-42",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60fad6dfcc0d930a59becf12",
+ "title": "Step 42"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-43",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60fad8e6148f310bba7890b1",
+ "title": "Step 43"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-44",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60fad99e09f9d30c1657e790",
+ "title": "Step 44"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-45",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60fadb18058e950c73925279",
+ "title": "Step 45"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-46",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60fadce90f85c50d0bb0dd4f",
+ "title": "Step 46"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-48",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60fadd972e6ffe0d6858fa2d",
+ "title": "Step 48"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-49",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60fadfa2b540b70dcfa8b771",
+ "title": "Step 49"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-50",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60fc219d333e37046f474a6e",
+ "title": "Step 50"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-51",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60fc22d1e64d1b04cdd4e602",
+ "title": "Step 51"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-52",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60fc236dc04532052926fdac",
+ "title": "Step 52"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-53",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60ffe1bc30415f042faea936",
+ "title": "Step 53"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-54",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60ffe3936796ac04959285a9",
+ "title": "Step 54"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-55",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60ffe4f4ec18cd04dc470c56",
+ "title": "Step 55"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-56",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60ffe69ee377c6055e192a46",
+ "title": "Step 56"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-57",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60ffe7d8aae62c05bcc9e7eb",
+ "title": "Step 57"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-58",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60ffe8a5ceb0e90618db06d9",
+ "title": "Step 58"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-59",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60ffe947a868ec068f7850f6",
+ "title": "Step 59"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-60",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60ffe9cb47809106eda2f2c9",
+ "title": "Step 60"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-61",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60ffec2825da1007509ddd06",
+ "title": "Step 61"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-62",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60ffecefac971607ae73c60f",
+ "title": "Step 62"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-63",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "60ffefd6479a3d084fb77cbc",
+ "title": "Step 63"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-47",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "62b30924c5e4ef0daba23b5e",
+ "title": "Step 47"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-5",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "62cc5b1779e4d313466f73c5",
+ "title": "Step 5"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-18",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "62ff8b9dab5ac88e4d3d43a3",
+ "title": "Step 18"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-29",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "62ff8e998d3e7eae14d6ae3b",
+ "title": "Step 29"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-38",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "62ff919a7b5612c0670923a5",
+ "title": "Step 38"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-html-forms-by-building-a-registration-form/step-12",
+ "blockName": "Learn HTML Forms by Building a Registration Form"
+ },
+ "id": "63541ef4f96cd82e8e6c788a",
+ "title": "Step 12"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-1",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c51578",
+ "title": "Step 1"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-2",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c51579",
+ "title": "Step 2"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-4",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c5157a",
+ "title": "Step 4"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-5",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c5157b",
+ "title": "Step 5"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-6",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c5157c",
+ "title": "Step 6"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-7",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c5157d",
+ "title": "Step 7"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-8",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c5157e",
+ "title": "Step 8"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-9",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c5157f",
+ "title": "Step 9"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-10",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c51580",
+ "title": "Step 10"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-11",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c51581",
+ "title": "Step 11"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-12",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c51582",
+ "title": "Step 12"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-13",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c51583",
+ "title": "Step 13"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-14",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c51584",
+ "title": "Step 14"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-15",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c51585",
+ "title": "Step 15"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-16",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c51586",
+ "title": "Step 16"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-17",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c51587",
+ "title": "Step 17"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-18",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c51588",
+ "title": "Step 18"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-19",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c51589",
+ "title": "Step 19"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-20",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c5158a",
+ "title": "Step 20"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-21",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c5158b",
+ "title": "Step 21"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-22",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c5158c",
+ "title": "Step 22"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-23",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c5158d",
+ "title": "Step 23"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-24",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c5158e",
+ "title": "Step 24"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-25",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c5158f",
+ "title": "Step 25"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-26",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c51590",
+ "title": "Step 26"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-27",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c51591",
+ "title": "Step 27"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-28",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c51592",
+ "title": "Step 28"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-29",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c51593",
+ "title": "Step 29"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-30",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c51594",
+ "title": "Step 30"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-31",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c51595",
+ "title": "Step 31"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-32",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c51596",
+ "title": "Step 32"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-33",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c51597",
+ "title": "Step 33"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-34",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c51598",
+ "title": "Step 34"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-35",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c51599",
+ "title": "Step 35"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-36",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c5159a",
+ "title": "Step 36"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-37",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c5159b",
+ "title": "Step 37"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-38",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c5159c",
+ "title": "Step 38"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-39",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c5159d",
+ "title": "Step 39"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-40",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c5159e",
+ "title": "Step 40"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-42",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c5159f",
+ "title": "Step 42"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-43",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515a0",
+ "title": "Step 43"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-44",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515a1",
+ "title": "Step 44"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-45",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515a2",
+ "title": "Step 45"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-46",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515a3",
+ "title": "Step 46"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-47",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515a4",
+ "title": "Step 47"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-48",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515a5",
+ "title": "Step 48"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-49",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515a6",
+ "title": "Step 49"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-50",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515a7",
+ "title": "Step 50"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-51",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515a8",
+ "title": "Step 51"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-52",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515a9",
+ "title": "Step 52"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-53",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515aa",
+ "title": "Step 53"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-54",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515ab",
+ "title": "Step 54"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-55",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515ac",
+ "title": "Step 55"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-56",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515ad",
+ "title": "Step 56"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-57",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515ae",
+ "title": "Step 57"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-58",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515af",
+ "title": "Step 58"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-59",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515b0",
+ "title": "Step 59"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-60",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515b1",
+ "title": "Step 60"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-61",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515b2",
+ "title": "Step 61"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-62",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515b3",
+ "title": "Step 62"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-63",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515b4",
+ "title": "Step 63"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-64",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515b5",
+ "title": "Step 64"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-65",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515b6",
+ "title": "Step 65"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-66",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515b7",
+ "title": "Step 66"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-67",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515b8",
+ "title": "Step 67"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-68",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515b9",
+ "title": "Step 68"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-69",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515ba",
+ "title": "Step 69"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-70",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515bc",
+ "title": "Step 70"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-79",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515bd",
+ "title": "Step 79"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-80",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515be",
+ "title": "Step 80"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-81",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515bf",
+ "title": "Step 81"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-82",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515c0",
+ "title": "Step 82"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-83",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515c1",
+ "title": "Step 83"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-84",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515c2",
+ "title": "Step 84"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-85",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515c3",
+ "title": "Step 85"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-86",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515c4",
+ "title": "Step 86"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-87",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515c5",
+ "title": "Step 87"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-88",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515c6",
+ "title": "Step 88"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-89",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b69a66b6ddb80858c515c7",
+ "title": "Step 89"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-3",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60b80da8676fb3227967a731",
+ "title": "Step 3"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-75",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60ba890832b4940f24d1936b",
+ "title": "Step 75"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-74",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60ba89123a445e0f5c9e4022",
+ "title": "Step 74"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-73",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60ba8913f1704c0f7a8906b8",
+ "title": "Step 73"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-72",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60ba89146b25080f99ab54ad",
+ "title": "Step 72"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-71",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60ba8914bab51f0fb8228e9c",
+ "title": "Step 71"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-76",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60ba929345ab0714a3743655",
+ "title": "Step 76"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-77",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60ba9296d4d6b414c1b10995",
+ "title": "Step 77"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-78",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60ba92987c1e4914dfa7a0b9",
+ "title": "Step 78"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-intermediate-css-by-building-a-picasso-painting/step-41",
+ "blockName": "Learn Intermediate CSS by Building a Picasso Painting"
+ },
+ "id": "60bad32219ebcb4a8810ac6a",
+ "title": "Step 41"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-1",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd5a93fd62bb35968adeab",
+ "title": "Step 1"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-2",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd6343fb42013d99bcd7f3",
+ "title": "Step 2"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-3",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd66c687e610436494c6f1",
+ "title": "Step 3"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-4",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd67a656743144844941cb",
+ "title": "Step 4"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-5",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd6ab779390f49148773bb",
+ "title": "Step 5"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-6",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd6b7c83dbf54a08cf0498",
+ "title": "Step 6"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-7",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd6cc9475a784b7776233e",
+ "title": "Step 7"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-8",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd70336ebb3e4f62ee81ba",
+ "title": "Step 8"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-9",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd719788899952e67692b9",
+ "title": "Step 9"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-10",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd71d596e8f253b9408b39",
+ "title": "Step 10"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-11",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd75ea7f663457612dba02",
+ "title": "Step 11"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-12",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd7648a7ba2e5882436831",
+ "title": "Step 12"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-13",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd778081276b59d59abad6",
+ "title": "Step 13"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-14",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd77f7ad2aeb5ae34d07d6",
+ "title": "Step 14"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-15",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd78621573aa5e8b512f5e",
+ "title": "Step 15"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-16",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd7a160ed17960e971f28b",
+ "title": "Step 16"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-17",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd7b3fcaa5406257abc5d1",
+ "title": "Step 17"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-18",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd8e491324ce717da97ffe",
+ "title": "Step 18"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-19",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd8fd08af43372f02952d0",
+ "title": "Step 19"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-20",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd9126aa72a474301fc49f",
+ "title": "Step 20"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-21",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd933ba685de776a94997e",
+ "title": "Step 21"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-22",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd94056e0355785fbba4d3",
+ "title": "Step 22"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-23",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd986ddbcbd47ba8fbc5ec",
+ "title": "Step 23"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-24",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd990577d8227dd93fbeeb",
+ "title": "Step 24"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-25",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd9a4ff2fc4481b9157bd7",
+ "title": "Step 25"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-26",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd9ad665a4a282c8106be3",
+ "title": "Step 26"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-27",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd9b7285bde783ad5b8aac",
+ "title": "Step 27"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-28",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fd9d9fbdfe078800317055",
+ "title": "Step 28"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-29",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fda307bde0b091cf7d884a",
+ "title": "Step 29"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-30",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fda339eadcfd92a6812bed",
+ "title": "Step 30"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-31",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fdac1e31692f9a9ad97295",
+ "title": "Step 31"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-32",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fdaea3999cb19d76ce717b",
+ "title": "Step 32"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-33",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fdaf9ff894b6a084ecdc1b",
+ "title": "Step 33"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-34",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fdafe6f07fd7a1c6785bc2",
+ "title": "Step 34"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-35",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "61fdb04d9939f0a26ca51c2b",
+ "title": "Step 35"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-36",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "620159cd5431aa34bc6a4c9c",
+ "title": "Step 36"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-37",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "62015a5da1c95c358f079ebb",
+ "title": "Step 37"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-38",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "62015cd2654a1139321a89d2",
+ "title": "Step 38"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-39",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "62015d8942384c3aed48329e",
+ "title": "Step 39"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-40",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "620167374bb8b4455cd11125",
+ "title": "Step 40"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-41",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "620174ed519dd7506c1a4b61",
+ "title": "Step 41"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-42",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "620175b3710a0951cfa86edf",
+ "title": "Step 42"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-43",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "6201782cc420715562f36271",
+ "title": "Step 43"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-44",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "620179bc0a6a2358c72b90ad",
+ "title": "Step 44"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-45",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "62017b6f47454059bf2d3bd1",
+ "title": "Step 45"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-46",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "62017f47c87be96457c49f46",
+ "title": "Step 46"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-47",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "62017fa5bbef406580ceb44f",
+ "title": "Step 47"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-48",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "62018243f046a368fab8ffb6",
+ "title": "Step 48"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-49",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "6201830cb0c74b69f1b41635",
+ "title": "Step 49"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-50",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "620186f4b6b8356d2def576b",
+ "title": "Step 50"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-51",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "62018ba1aa263770c953be66",
+ "title": "Step 51"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-52",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "62018c3e94434a71af1d5eaa",
+ "title": "Step 52"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-53",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "62018ec29b3ae674f40bef31",
+ "title": "Step 53"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-54",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "62019093fe30e278e797d2f6",
+ "title": "Step 54"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-55",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "620191707bc65579ddd3ce15",
+ "title": "Step 55"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-56",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "620192a767533a7ad19d96d7",
+ "title": "Step 56"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-57",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "6201995d9ab88e80f1989dce",
+ "title": "Step 57"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-58",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "620199c7a7a32c81d4db3410",
+ "title": "Step 58"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-59",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "6201a1a7af32c287bd6b8183",
+ "title": "Step 59"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-60",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "6201a1cc668a34888f5b2f52",
+ "title": "Step 60"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-61",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "6201a20d742f5c89736c8cfb",
+ "title": "Step 61"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-62",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "6201a42e39bf3b95b6a33bf3",
+ "title": "Step 62"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-63",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "6201a4adcc6414968b391592",
+ "title": "Step 63"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-64",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "6201a5258af7b398b030bfaf",
+ "title": "Step 64"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/step-65",
+ "blockName": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet"
+ },
+ "id": "6201a59be346d399c21d10b1",
+ "title": "Step 65"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-1",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612e6afc009b450a437940a1",
+ "title": "Step 1"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-2",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612e77aba7ca691f598feb02",
+ "title": "Step 2"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-3",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612e78af05201622d4bab8aa",
+ "title": "Step 3"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-4",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612e7d1c29fb872d6384379c",
+ "title": "Step 4"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-5",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612e804c54d5e7308d7ebe56",
+ "title": "Step 5"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-6",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612e813b3ba67633222cbe54",
+ "title": "Step 6"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-7",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612e8279827a28352ce83a72",
+ "title": "Step 7"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-8",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612e83ec2eca1e370f830511",
+ "title": "Step 8"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-9",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612e89562043183c86df287c",
+ "title": "Step 9"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-10",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612e89d254fe5d3df7d6693d",
+ "title": "Step 10"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-11",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612e8eebe3a6dc3fcc33a66f",
+ "title": "Step 11"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-12",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612e95ef2e4bdf41f69067f9",
+ "title": "Step 12"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-13",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612e96fc87fe8e44f69f7ec5",
+ "title": "Step 13"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-14",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612e98f3245c98475e49cfc6",
+ "title": "Step 14"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-15",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612e9a21381a1949327512e6",
+ "title": "Step 15"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-16",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612e9d142affc44a453655db",
+ "title": "Step 16"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-17",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612e9f1e7e5ccd4fa9ada0be",
+ "title": "Step 17"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-18",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612ea4c4993aba52ab4aa32e",
+ "title": "Step 18"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-19",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612ea97df5742154772f312e",
+ "title": "Step 19"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-20",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612ead8788d28655ef8db056",
+ "title": "Step 20"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-21",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612eaf56b7ba3257fdbfb0db",
+ "title": "Step 21"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-22",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612eb4893b63c75bb9251ddf",
+ "title": "Step 22"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-23",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612eb75153591b5e3b1ab65e",
+ "title": "Step 23"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-24",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612eb7ca8c275d5f89c73333",
+ "title": "Step 24"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-25",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612eb8e984cd73677a92b7e9",
+ "title": "Step 25"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-26",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612eb934f64a4d6890a45518",
+ "title": "Step 26"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-27",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612ebcba99bfa46a15370b11",
+ "title": "Step 27"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-28",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612ebe7fe6d07e6b76d1cae2",
+ "title": "Step 28"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-29",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612ebedec97e096c8bf64999",
+ "title": "Step 29"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-30",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612ebf9a210f2b6d77001e68",
+ "title": "Step 30"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-31",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612ec0490ae8626e9adf82e4",
+ "title": "Step 31"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-32",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612ec19d5268da7074941f84",
+ "title": "Step 32"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-responsive-web-design-by-building-a-piano/step-33",
+ "blockName": "Learn Responsive Web Design by Building a Piano"
+ },
+ "id": "612ec29c84b9a6718b1f5cec",
+ "title": "Step 33"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-1",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad6996a",
+ "title": "Step 1"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-2",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad6996b",
+ "title": "Step 2"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-3",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad6996c",
+ "title": "Step 3"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-4",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad6996d",
+ "title": "Step 4"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-5",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad6996e",
+ "title": "Step 5"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-6",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad6996f",
+ "title": "Step 6"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-7",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69970",
+ "title": "Step 7"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-8",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69971",
+ "title": "Step 8"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-9",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69972",
+ "title": "Step 9"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-10",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69973",
+ "title": "Step 10"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-11",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69974",
+ "title": "Step 11"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-12",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69975",
+ "title": "Step 12"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-13",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69976",
+ "title": "Step 13"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-14",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69977",
+ "title": "Step 14"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-15",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69978",
+ "title": "Step 15"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-16",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69979",
+ "title": "Step 16"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-17",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad6997a",
+ "title": "Step 17"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-18",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad6997b",
+ "title": "Step 18"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-19",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad6997c",
+ "title": "Step 19"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-20",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad6997d",
+ "title": "Step 20"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-21",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad6997e",
+ "title": "Step 21"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-22",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad6997f",
+ "title": "Step 22"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-23",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69980",
+ "title": "Step 23"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-24",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69981",
+ "title": "Step 24"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-25",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69982",
+ "title": "Step 25"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-26",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69983",
+ "title": "Step 26"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-27",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69984",
+ "title": "Step 27"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-28",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69986",
+ "title": "Step 28"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-29",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69987",
+ "title": "Step 29"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-30",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69988",
+ "title": "Step 30"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-31",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69989",
+ "title": "Step 31"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-32",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad6998a",
+ "title": "Step 32"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-33",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad6998b",
+ "title": "Step 33"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-34",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad6998c",
+ "title": "Step 34"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-35",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad6998d",
+ "title": "Step 35"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-36",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad6998e",
+ "title": "Step 36"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-37",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad6998f",
+ "title": "Step 37"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-38",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69990",
+ "title": "Step 38"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-39",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69991",
+ "title": "Step 39"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-40",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69992",
+ "title": "Step 40"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-41",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69993",
+ "title": "Step 41"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-42",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69994",
+ "title": "Step 42"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-43",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69995",
+ "title": "Step 43"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-44",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69996",
+ "title": "Step 44"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-the-css-box-model-by-building-a-rothko-painting/step-45",
+ "blockName": "Learn the CSS Box Model by Building a Rothko Painting"
+ },
+ "id": "60a3e3396c7b40068ad69997",
+ "title": "Step 45"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-1",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f2abbe7d18d49a1e0e1c8",
+ "title": "Step 1"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-2",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f2d4150fe0d4cbd0f2628",
+ "title": "Step 2"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-3",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f34948891834dd77655a6",
+ "title": "Step 3"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-4",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f34ecc1091b4fd5a8a484",
+ "title": "Step 4"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-5",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f357957e370510f21ea16",
+ "title": "Step 5"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-6",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f378014c2da526a109c81",
+ "title": "Step 6"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-7",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f38279e5c3d53692ea441",
+ "title": "Step 7"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-8",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f38cabc64e3556f98cc1a",
+ "title": "Step 8"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-9",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f3949f58e12577dcefb00",
+ "title": "Step 9"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-10",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f39d7da41b15851fa3fb9",
+ "title": "Step 10"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-11",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f3b091162165948e1cb33",
+ "title": "Step 11"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-12",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f3cafd794015aa9547a6d",
+ "title": "Step 12"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-13",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f3d9e59db4b5b8e960762",
+ "title": "Step 13"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-14",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f3e1b7233ee5c7595771f",
+ "title": "Step 14"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-15",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f3e4af8008c5d494d3afe",
+ "title": "Step 15"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-16",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f3ed16592445e57941aec",
+ "title": "Step 16"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-17",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f405b89a7ec5f8e2d11f4",
+ "title": "Step 17"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-18",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f40b01f680e608d360ed4",
+ "title": "Step 18"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-19",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f4172e9eec061d6456221",
+ "title": "Step 19"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-20",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f41c979787462e76dab90",
+ "title": "Step 20"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-21",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f423cf65d5864132a0956",
+ "title": "Step 21"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-22",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f42a021625f656101ef93",
+ "title": "Step 22"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-23",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f4bfb9de4a16703b56eb6",
+ "title": "Step 23"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-24",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f4ce9d877b668417c0c42",
+ "title": "Step 24"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-25",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f4dde9d72e3694cb9ee3b",
+ "title": "Step 25"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-26",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f4ec58334106a4170c2a8",
+ "title": "Step 26"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-27",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f4f9e4a40566b776a8f38",
+ "title": "Step 27"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-28",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f50473cc0196c6dd3892a",
+ "title": "Step 28"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-29",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f51257a8a516d80b6c743",
+ "title": "Step 29"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-30",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f51e4e5b24a6e80eccce1",
+ "title": "Step 30"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-31",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f522dea4f776f64dc3e91",
+ "title": "Step 31"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-32",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f5486b8fd4b71633f69b0",
+ "title": "Step 32"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-33",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f575b50b91e72af079480",
+ "title": "Step 33"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-34",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f5af373a68e744a3c5a76",
+ "title": "Step 34"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-35",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f5c1cb7575c7551ed8a40",
+ "title": "Step 35"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-36",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f5fd85d0062761f288364",
+ "title": "Step 36"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-37",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f61338c8ca176d6445574",
+ "title": "Step 37"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-38",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f666ac5edea782feb7e75",
+ "title": "Step 38"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-39",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f671b6d1919792745aa5d",
+ "title": "Step 39"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-40",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f6823d0815b7a991f2a75",
+ "title": "Step 40"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-41",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f6a7d4ba8037bc086c2c7",
+ "title": "Step 41"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-42",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f6b2d164f81809efd9bdc",
+ "title": "Step 42"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-43",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f6cc778f7698258467596",
+ "title": "Step 43"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-44",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f6fddaac1e083502d3e6a",
+ "title": "Step 44"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-45",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f70077a4ff98424236c1e",
+ "title": "Step 45"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-46",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f72a872354a850d4f533e",
+ "title": "Step 46"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-47",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f74a71f1e498619e38ee8",
+ "title": "Step 47"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-48",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f7ad94380408d971d14f6",
+ "title": "Step 48"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-49",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f7bc680f7168ea01ebf99",
+ "title": "Step 49"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-50",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f7c71eab8218f846e4503",
+ "title": "Step 50"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-51",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f7d489a581590d1350288",
+ "title": "Step 51"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-52",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f7de4487b64919bb4aa5e",
+ "title": "Step 52"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-53",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f7e7281626a92bbd62da8",
+ "title": "Step 53"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-54",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f7ecb09de9a938ef94756",
+ "title": "Step 54"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-55",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f7fa959ab75948f96a0d6",
+ "title": "Step 55"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-56",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f808d85793195b0f53be9",
+ "title": "Step 56"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-57",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f829d07b18f96f6f6684b",
+ "title": "Step 57"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-58",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f83ef928ec9982b785b6a",
+ "title": "Step 58"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-59",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f84f246e8ba98e3cd97be",
+ "title": "Step 59"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-60",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f887466db4ba14b5342cc",
+ "title": "Step 60"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-61",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f89e055040ba294719d2f",
+ "title": "Step 61"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-62",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f8bfe0f30a1a3c340356b",
+ "title": "Step 62"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-63",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f8f1223601fa546e93f31",
+ "title": "Step 63"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-64",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f905fbd1017a65ca224eb",
+ "title": "Step 64"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-65",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f94786869e1a7fec54375",
+ "title": "Step 65"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-typography-by-building-a-nutrition-label/step-66",
+ "blockName": "Learn Typography by Building a Nutrition Label"
+ },
+ "id": "615f951dff9317a900ef683f",
+ "title": "Step 66"
+ }
+ }
+ },
+ {
+ "node": {
+ "challenge": {
+ "fields": {
+ "slug": "/learn/2022/responsive-web-design/learn-css-transforms-by-building-a-penguin/step-23",
+ "blockName": "Learn CSS Transforms by Building a Penguin"
+ },
+ "id": "6196d1ac33c68d27dcda5796",
+ "title": "Step 23"
+ }
+ }
+ }
+]
diff --git a/client/src/__mocks__/fileMock.ts b/client/src/__mocks__/file-mock.ts
similarity index 100%
rename from client/src/__mocks__/fileMock.ts
rename to client/src/__mocks__/file-mock.ts
diff --git a/client/src/__mocks__/styleMock.ts b/client/src/__mocks__/style-mock.ts
similarity index 100%
rename from client/src/__mocks__/styleMock.ts
rename to client/src/__mocks__/style-mock.ts
diff --git a/client/src/analytics/index.ts b/client/src/analytics/index.ts
new file mode 100644
index 00000000000000..32a21405122791
--- /dev/null
+++ b/client/src/analytics/index.ts
@@ -0,0 +1,25 @@
+import TagManager from 'react-gtm-module';
+
+import {
+ devAnalyticsId,
+ prodAnalyticsId,
+ prodAnalyticsESId
+} from '../../../config/analytics-settings';
+
+import envData from '../../../config/env.json';
+
+const { deploymentEnv, clientLocale } = envData;
+
+const analyticsIDSelector = () => {
+ if (deploymentEnv === 'staging') return devAnalyticsId;
+ else if (clientLocale === 'espanol') return prodAnalyticsESId;
+ else return prodAnalyticsId;
+};
+
+const gtmId = analyticsIDSelector();
+
+if (typeof document !== `undefined`) {
+ TagManager.initialize({ gtmId });
+}
+
+export default TagManager;
diff --git a/client/src/analytics/index.tsx b/client/src/analytics/index.tsx
deleted file mode 100644
index 8362761097bd8e..00000000000000
--- a/client/src/analytics/index.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import ReactGA from 'react-ga';
-import {
- devAnalyticsId,
- prodAnalyticsId
-} from '../../../config/analytics-settings';
-import envData from '../../../config/env.json';
-
-const { deploymentEnv } = envData;
-
-const analyticsId: string =
- deploymentEnv === 'staging'
- ? (devAnalyticsId as string)
- : (prodAnalyticsId as string);
-
-ReactGA.initialize(analyticsId);
-
-export default ReactGA;
diff --git a/client/src/assets/icons/API-icon.tsx b/client/src/assets/icons/api.tsx
similarity index 100%
rename from client/src/assets/icons/API-icon.tsx
rename to client/src/assets/icons/api.tsx
diff --git a/client/src/assets/icons/certification-icon.tsx b/client/src/assets/icons/certification.tsx
similarity index 100%
rename from client/src/assets/icons/certification-icon.tsx
rename to client/src/assets/icons/certification.tsx
diff --git a/client/src/assets/icons/D3-icon.tsx b/client/src/assets/icons/d3.tsx
similarity index 100%
rename from client/src/assets/icons/D3-icon.tsx
rename to client/src/assets/icons/d3.tsx
diff --git a/client/src/assets/icons/Database-icon.tsx b/client/src/assets/icons/database.tsx
similarity index 100%
rename from client/src/assets/icons/Database-icon.tsx
rename to client/src/assets/icons/database.tsx
diff --git a/client/src/assets/icons/FreeCodeCamp-logo.tsx b/client/src/assets/icons/freecodecamp.tsx
similarity index 100%
rename from client/src/assets/icons/FreeCodeCamp-logo.tsx
rename to client/src/assets/icons/freecodecamp.tsx
diff --git a/client/src/assets/icons/help.tsx b/client/src/assets/icons/help.tsx
index f745414e83a791..e6d3760857c9cd 100644
--- a/client/src/assets/icons/help.tsx
+++ b/client/src/assets/icons/help.tsx
@@ -1,20 +1,47 @@
import React from 'react';
+const wrapper = {
+ display: 'grid',
+ placeItems: 'center',
+ position: 'relative',
+ padding: 'inherit'
+} as React.CSSProperties;
+
+const speechBubbleIcon = {
+ position: 'absolute'
+} as React.CSSProperties;
+
+const questionMarkIcon = {
+ position: 'absolute',
+ top: '-3px',
+ width: '9px'
+} as React.CSSProperties;
+
function Help(
props: JSX.IntrinsicAttributes & React.SVGProps
): JSX.Element {
return (
<>
-
-
-
+
>
);
}
diff --git a/client/src/assets/icons/index.tsx b/client/src/assets/icons/index.tsx
index 45f29522fd6003..528a9ef7746573 100644
--- a/client/src/assets/icons/index.tsx
+++ b/client/src/assets/icons/index.tsx
@@ -1,17 +1,18 @@
import React from 'react';
import { SuperBlocks } from '../../../../config/certification-settings';
-import APIIcon from './API-icon';
-import D3Icon from './D3-icon';
-import DatabaseIcon from './Database-icon';
-import JavaScriptIcon from './JavaScript-icon';
-import ReactIcon from './React-icon';
-import TensorflowIcon from './Tensorflow-icon';
+import APIIcon from './api';
+import D3Icon from './d3';
+import DatabaseIcon from './database';
+import JavaScriptIcon from './javascript';
+import ReactIcon from './react';
+import TensorflowIcon from './tensorflow';
import Algorithm from './algorithm';
import Analytics from './analytics';
import Clipboard from './clipboard';
-import PythonIcon from './python-icon';
+import PythonIcon from './python';
import ResponsiveDesign from './responsive-design';
import Shield from './shield';
+import VikingHelmet from './viking-helmet';
const iconMap = {
[SuperBlocks.RespWebDesignNew]: ResponsiveDesign,
@@ -27,7 +28,8 @@ const iconMap = {
[SuperBlocks.DataAnalysisPy]: Analytics,
[SuperBlocks.InfoSec]: Shield,
[SuperBlocks.MachineLearningPy]: TensorflowIcon,
- [SuperBlocks.CodingInterviewPrep]: Algorithm
+ [SuperBlocks.CodingInterviewPrep]: Algorithm,
+ [SuperBlocks.TheOdinProject]: VikingHelmet
};
const generateIconComponent = (
diff --git a/client/src/assets/icons/input-reset.tsx b/client/src/assets/icons/input-reset.tsx
new file mode 100644
index 00000000000000..25c5311b8a236f
--- /dev/null
+++ b/client/src/assets/icons/input-reset.tsx
@@ -0,0 +1,24 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+
+const InputReset = (): JSX.Element => {
+ const { t } = useTranslation();
+
+ return (
+ <>
+ {t('icons.input-reset')}
+
+
+
+ >
+ );
+};
+
+InputReset.displayName = 'InputReset';
+export default InputReset;
diff --git a/client/src/assets/icons/JavaScript-icon.tsx b/client/src/assets/icons/javascript.tsx
similarity index 100%
rename from client/src/assets/icons/JavaScript-icon.tsx
rename to client/src/assets/icons/javascript.tsx
diff --git a/client/src/assets/icons/Magnifier.tsx b/client/src/assets/icons/magnifier.tsx
similarity index 93%
rename from client/src/assets/icons/Magnifier.tsx
rename to client/src/assets/icons/magnifier.tsx
index 42e5a13c1e2e97..9c6faed41623a2 100644
--- a/client/src/assets/icons/Magnifier.tsx
+++ b/client/src/assets/icons/magnifier.tsx
@@ -6,7 +6,7 @@ const Magnifier = (): JSX.Element => {
return (
<>
- {t('icons.Magnifier')}
+ {t('icons.magnifier')}
- {t('icons.spacer')}
+): JSX.Element {
+ return (
+ <>
+
+
+
+ >
+ );
+}
+
+VikingHelmet.displayName = 'VikingHelmet';
+
+export default VikingHelmet;
diff --git a/client/src/client-only-routes/show-certification.tsx b/client/src/client-only-routes/show-certification.tsx
index cac667f9e79c55..6edff2f96a58b2 100644
--- a/client/src/client-only-routes/show-certification.tsx
+++ b/client/src/client-only-routes/show-certification.tsx
@@ -1,5 +1,6 @@
import { Grid, Row, Col, Image, Button } from '@freecodecamp/react-bootstrap';
import { isEmpty } from 'lodash-es';
+import { QRCodeSVG } from 'qrcode.react';
import React, { useEffect, useState } from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { connect } from 'react-redux';
@@ -8,7 +9,7 @@ import { createSelector } from 'reselect';
import envData from '../../../config/env.json';
import { getLangCode } from '../../../config/i18n';
-import FreeCodeCampLogo from '../assets/icons/FreeCodeCamp-logo';
+import FreeCodeCampLogo from '../assets/icons/freecodecamp';
import DonateForm from '../components/Donation/donate-form';
import { createFlashMessage } from '../components/Flash/redux';
@@ -30,6 +31,7 @@ import certificateMissingMessage from '../utils/certificate-missing-message';
import reallyWeirdErrorMessage from '../utils/really-weird-error-message';
import standardErrorMessage from '../utils/standard-error-message';
+import { PaymentContext } from '../../../config/donation-settings';
import ShowProjectLinks from './show-project-links';
const { clientLocale } = envData;
@@ -153,12 +155,8 @@ const ShowCertification = (props: ShowCertificationProps): JSX.Element => {
) {
setIsDonationDisplayed(true);
executeGA({
- type: 'event',
- data: {
- category: 'Donation View',
- action: 'Displayed Certificate Donation',
- nonInteraction: true
- }
+ event: 'donationview',
+ action: 'Displayed Certificate Donation'
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -176,20 +174,7 @@ const ShowCertification = (props: ShowCertificationProps): JSX.Element => {
setIsDonationClosed(true);
};
- const handleProcessing = (
- duration: string,
- amount: number,
- action: string
- ) => {
- props.executeGA({
- type: 'event',
- data: {
- category: 'Donation',
- action: `certificate ${action}`,
- label: duration,
- value: amount
- }
- });
+ const handleProcessing = () => {
setIsDonationSubmitted(true);
};
@@ -269,6 +254,7 @@ const ShowCertification = (props: ShowCertificationProps): JSX.Element => {
defaultTheme={Themes.Default}
handleProcessing={handleProcessing}
isMinimalForm={true}
+ paymentContext={PaymentContext.Certificate}
/>
@@ -346,7 +332,9 @@ const ShowCertification = (props: ShowCertificationProps): JSX.Element => {
placeholder
- {{ title: certTitle }}
+
+ {{ title: t(`certification.title.${certTitle}`, certTitle) }}
+
{{ time: completionTime }}
@@ -366,6 +354,9 @@ const ShowCertification = (props: ShowCertificationProps): JSX.Element => {
{t('certification.executive')}
+
+
+
{t('certification.verify', { certURL: certURL })}
diff --git a/client/src/client-only-routes/show-project-links.tsx b/client/src/client-only-routes/show-project-links.tsx
index cbe56ea2a05228..94d8a603759e46 100644
--- a/client/src/client-only-routes/show-project-links.tsx
+++ b/client/src/client-only-routes/show-project-links.tsx
@@ -1,14 +1,15 @@
+import { Table } from '@freecodecamp/react-bootstrap';
import { find, first } from 'lodash-es';
import React, { useState } from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { connect } from 'react-redux';
+import { Link, Spacer } from '../components/helpers';
import ProjectModal from '../components/SolutionViewer/ProjectModal';
-import { Spacer, Link } from '../components/helpers';
import { CompletedChallenge, User } from '../redux/prop-types';
import {
- projectMap,
- legacyProjectMap
+ legacyProjectMap,
+ projectMap
} from '../resources/cert-and-project-map';
import { SolutionDisplayWidget } from '../components/solution-display-widget';
@@ -16,8 +17,8 @@ import ProjectPreviewModal from '../templates/Challenges/components/project-prev
import { openModal } from '../templates/Challenges/redux/actions';
-import '../components/layouts/project-links.css';
import { regeneratePathAndHistory } from '../../../utils/polyvinyl';
+import '../components/layouts/project-links.css';
interface ShowProjectLinksProps {
certName: string;
name: string;
@@ -82,6 +83,7 @@ const ShowProjectLinks = (props: ShowProjectLinksProps): JSX.Element => {
{
const { certSlug } = first(mapToUse) as { certSlug: string };
const certLocation = `/certification/${username}/${certSlug}`;
return (
-
-
- {t(`certification.project.title.${cert.title}`, cert.title)}
-
-
+
+
+
+ {t(`certification.title.${cert.title}`, cert.title)}
+
+
+
);
});
}
@@ -125,12 +124,14 @@ const ShowProjectLinks = (props: ShowProjectLinksProps): JSX.Element => {
id: string;
}[];
return project.map(({ link, title, id }) => (
-
-
- {t(`certification.project.title.${title}`, title)}
-
- : {getProjectSolution(id, title)}
-
+
+
+
+ {t(`certification.project.title.${title}`, title)}
+
+
+ {getProjectSolution(id, title)}
+
));
};
@@ -160,7 +161,15 @@ const ShowProjectLinks = (props: ShowProjectLinksProps): JSX.Element => {
{ user: name }
)}
- {renderProjectsFor(certName)}
+
+
+
+ {t('profile.challenge')}
+ {t('settings.labels.solution')}
+
+
+ {renderProjectsFor(certName)}
+
{
const MAX_LOGS_SIZE = 64 * 1024;
let logs: string[] = [];
+
function flushLogs() {
if (logs.length) {
ctx.postMessage({
@@ -21,16 +22,38 @@ const __utils = (() => {
}
}
- const oldLog = ctx.console.log.bind(ctx.console);
- function proxyLog(...args: string[]) {
+ function pushLogs(logs: string[], args: string[]) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
logs.push(args.map(arg => __format(arg)).join(' '));
if (logs.join('\n').length > MAX_LOGS_SIZE) {
flushLogs();
}
+ }
+
+ const oldLog = ctx.console.log.bind(ctx.console);
+ function proxyLog(...args: string[]) {
+ pushLogs(logs, args);
return oldLog(...args);
}
+ const oldInfo = ctx.console.info.bind(ctx.console);
+ function proxyInfo(...args: string[]) {
+ pushLogs(logs, args);
+ return oldInfo(...args);
+ }
+
+ const oldWarn = ctx.console.warn.bind(ctx.console);
+ function proxyWarn(...args: string[]) {
+ pushLogs(logs, args);
+ return oldWarn(...args);
+ }
+
+ const oldError = ctx.console.error.bind(ctx.console);
+ function proxyError(...args: string[]) {
+ pushLogs(logs, args);
+ return oldError(...args);
+ }
+
// unless data.type is truthy, this sends data out to the testRunner
function postResult(data: unknown) {
flushLogs();
@@ -47,6 +70,9 @@ const __utils = (() => {
const toggleProxyLogger = (on: unknown) => {
ctx.console.log = on ? proxyLog : oldLog;
+ ctx.console.info = on ? proxyInfo : oldInfo;
+ ctx.console.warn = on ? proxyWarn : oldWarn;
+ ctx.console.error = on ? proxyError : oldError;
};
return {
diff --git a/client/src/components/Donation/donate-form.tsx b/client/src/components/Donation/donate-form.tsx
index 4c5a91307c5a87..164cf6f6fc7173 100644
--- a/client/src/components/Donation/donate-form.tsx
+++ b/client/src/components/Donation/donate-form.tsx
@@ -9,40 +9,49 @@ import { createSelector } from 'reselect';
import {
amountsConfig,
durationsConfig,
- defaultAmount,
defaultDonation,
modalDefaultDonation
} from '../../../../config/donation-settings';
import { defaultDonationFormState } from '../../redux';
-import {
- addDonation,
- updateDonationFormState,
- postChargeStripe,
- postChargeStripeCard
-} from '../../redux/actions';
+import { updateDonationFormState, postCharge } from '../../redux/actions';
import {
isSignedInSelector,
userSelector,
isDonatingSelector,
signInLoadingSelector,
- donationFormStateSelector,
- isVariantASelector
+ donationFormStateSelector
} from '../../redux/selectors';
import Spacer from '../helpers/spacer';
import { Themes } from '../settings/theme';
import DonateCompletion from './donate-completion';
import PatreonButton from './patreon-button';
-import type { AddDonationData } from './paypal-button';
import PaypalButton from './paypal-button';
-import StripeCardForm, { HandleAuthentication } from './stripe-card-form';
+import StripeCardForm from './stripe-card-form';
import WalletsWrapper from './walletsButton';
import SecurityLockIcon from './security-lock-icon';
+import {
+ PaymentProvider,
+ PaymentContext,
+ PostPayment,
+ HandleAuthentication,
+ DonationApprovalData,
+ DonationAmount,
+ DonationConfig
+} from './types';
import './donation.css';
-const numToCommas = (num: number): string =>
+const numToCommas = (num: number) =>
num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
+// the number is used to indicate to the doner about how much hours of free education their dontation will provide.
+const contributedHoursOfFreeEduction = 50;
+const convertAmountToUSD = 100;
+const convertToTimeContributed = (amount: number) =>
+ numToCommas((amount / convertAmountToUSD) * contributedHoursOfFreeEduction);
+const formattedAmountLabel = (amount: number) =>
+ numToCommas(amount / convertAmountToUSD);
+
type DonateFormState = {
processing: boolean;
redirecting: boolean;
@@ -54,23 +63,26 @@ type DonateFormState = {
};
};
-type DonateFormComponentState = {
- donationAmount: number;
- donationDuration: string;
-};
+type DonateFormComponentState = DonationConfig;
+
+type PostCharge = (data: {
+ paymentProvider: PaymentProvider;
+ paymentContext: PaymentContext;
+ amount: number;
+ duration: string;
+ data?: DonationApprovalData;
+ token?: Token;
+ email?: string;
+ name?: string | undefined;
+ paymentMethodId?: string;
+ handleAuthentication?: HandleAuthentication;
+}) => void;
type DonateFormProps = {
- addDonation: (data: unknown) => unknown;
- postChargeStripe: (data: unknown) => unknown;
- postChargeStripeCard: (data: {
- paymentMethodId: string;
- amount: number;
- duration: string;
- handleAuthentication: HandleAuthentication;
- }) => void;
+ postCharge: PostCharge;
defaultTheme?: Themes;
email: string;
- handleProcessing: (duration: string, amount: number, action: string) => void;
+ handleProcessing?: () => void;
donationFormState: DonateFormState;
isMinimalForm?: boolean;
isSignedIn: boolean;
@@ -81,8 +93,8 @@ type DonateFormProps = {
{ usd, hours }?: { usd?: string | number; hours?: string }
) => string;
theme: Themes;
- updateDonationFormState: (state: AddDonationData) => unknown;
- isVariantA: boolean;
+ updateDonationFormState: (state: DonationApprovalData) => unknown;
+ paymentContext: PaymentContext;
};
const mapStateToProps = createSelector(
@@ -91,30 +103,37 @@ const mapStateToProps = createSelector(
isDonatingSelector,
donationFormStateSelector,
userSelector,
- isVariantASelector,
(
showLoading: DonateFormProps['showLoading'],
isSignedIn: DonateFormProps['isSignedIn'],
isDonating: DonateFormProps['isDonating'],
donationFormState: DonateFormState,
- { email, theme }: { email: string; theme: Themes },
- isVariantA: boolean
+ { email, theme }: { email: string; theme: Themes }
) => ({
isSignedIn,
isDonating,
showLoading,
donationFormState,
email,
- theme,
- isVariantA
+ theme
})
);
const mapDispatchToProps = {
- addDonation,
- updateDonationFormState,
- postChargeStripe,
- postChargeStripeCard
+ postCharge,
+ updateDonationFormState
+};
+
+const PaymentButtonsLoader = () => {
+ return (
+
+
+
+ );
};
class DonateForm extends Component {
@@ -124,27 +143,20 @@ class DonateForm extends Component {
constructor(props: DonateFormProps) {
super(props);
- this.durations = durationsConfig as {
- month: 'monthly';
- onetime: 'one-time';
- };
+ this.durations = durationsConfig;
this.amounts = amountsConfig;
- const initialAmountAndDuration = this.props.isMinimalForm
+ const initialAmountAndDuration: DonationConfig = this.props.isMinimalForm
? modalDefaultDonation
: defaultDonation;
this.state = { ...initialAmountAndDuration };
this.onDonationStateChange = this.onDonationStateChange.bind(this);
- this.getActiveDonationAmount = this.getActiveDonationAmount.bind(this);
this.getDonationButtonLabel = this.getDonationButtonLabel.bind(this);
this.handleSelectAmount = this.handleSelectAmount.bind(this);
- this.handleSelectDuration = this.handleSelectDuration.bind(this);
this.resetDonation = this.resetDonation.bind(this);
- this.postStripeDonation = this.postStripeDonation.bind(this);
- this.postStripeCardDonation = this.postStripeCardDonation.bind(this);
- this.postPatreonRedirect = this.postPatreonRedirect.bind(this);
+ this.postPayment = this.postPayment.bind(this);
this.handlePaymentButtonLoad = this.handlePaymentButtonLoad.bind(this);
}
@@ -152,7 +164,7 @@ class DonateForm extends Component {
this.resetDonation();
}
- onDonationStateChange(donationState: AddDonationData) {
+ onDonationStateChange(donationState: DonationApprovalData) {
// scroll to top
window.scrollTo(0, 0);
this.props.updateDonationFormState({
@@ -171,30 +183,12 @@ class DonateForm extends Component {
});
}
- // onload
- getActiveDonationAmount(
- durationSelected: 'month' | 'onetime',
- amountSelected: number
- ): number {
- return this.amounts[durationSelected].includes(amountSelected)
- ? amountSelected
- : defaultAmount[durationSelected] || this.amounts[durationSelected][0];
- }
-
- convertToTimeContributed(amount: number) {
- return numToCommas((amount / 100) * 50);
- }
-
- getFormattedAmountLabel(amount: number): string {
- return `${numToCommas(amount / 100)}`;
- }
-
getDonationButtonLabel() {
const { donationAmount, donationDuration } = this.state;
const { t } = this.props;
- const usd = this.getFormattedAmountLabel(donationAmount);
+ const usd = formattedAmountLabel(donationAmount);
let donationBtnLabel = t('donate.confirm');
- if (donationDuration === 'onetime') {
+ if (donationDuration === 'one-time') {
donationBtnLabel = t('donate.confirm-2', {
usd: usd
});
@@ -209,98 +203,41 @@ class DonateForm extends Component {
return donationBtnLabel;
}
- handleSelectDuration(donationDuration: 'month' | 'onetime') {
- const donationAmount = this.getActiveDonationAmount(donationDuration, 0);
- this.setState({ donationDuration, donationAmount });
- }
-
- postStripeDonation(
- token: Token,
- payerEmail: string | undefined,
- payerName: string | undefined
- ) {
- const { email } = this.props;
+ postPayment = ({
+ paymentProvider,
+ data,
+ payerEmail,
+ payerName,
+ token,
+ paymentMethodId,
+ handleAuthentication
+ }: PostPayment): void => {
const { donationAmount: amount, donationDuration: duration } = this.state;
- payerEmail = email ? email : payerEmail;
- window.scrollTo(0, 0);
- // change the donation modal button label to close
- // or display the close button for the cert donation section
- if (this.props.handleProcessing) {
- this.props.handleProcessing(duration, amount, 'Stripe payment submition');
- }
- this.props.postChargeStripe({
- token,
- amount,
- duration,
- email: payerEmail,
- name: payerName
- });
- }
+ const { paymentContext, email } = this.props;
- postStripeCardDonation(
- paymentMethodId: string,
- handleAuthentication: HandleAuthentication
- ) {
- const { donationAmount: amount, donationDuration: duration } = this.state;
- this.props.handleProcessing(
- duration,
- amount,
- 'Stripe card payment submission'
- );
- this.props.postChargeStripeCard({
- paymentMethodId,
+ this.props.postCharge({
+ paymentProvider,
+ paymentContext,
amount,
duration,
+ data,
+ token,
+ email: email || payerEmail,
+ name: payerName,
+ paymentMethodId,
handleAuthentication
});
- }
-
- postPatreonRedirect() {
- const { donationAmount: amount, donationDuration: duration } = this.state;
- this.props.handleProcessing(
- duration,
- amount,
- 'Patreon payment redirection'
- );
- }
+ if (this.props.handleProcessing) this.props.handleProcessing();
+ };
- handleSelectAmount(donationAmount: number) {
+ handleSelectAmount(donationAmount: DonationAmount) {
this.setState({ donationAmount });
}
- renderDonationDescription() {
- const { donationAmount, donationDuration } = this.state;
- const { t } = this.props;
- const usd = this.getFormattedAmountLabel(donationAmount);
- const hours = this.convertToTimeContributed(donationAmount);
-
- let donationDescription = t('donate.your-donation-3', { usd, hours });
-
- if (donationDuration === 'onetime') {
- donationDescription = t('donate.your-donation', { usd, hours });
- } else if (donationDuration === 'month') {
- donationDescription = t('donate.your-donation-2', { usd, hours });
- }
-
- return {donationDescription}
;
- }
-
resetDonation() {
return this.props.updateDonationFormState({ ...defaultDonationFormState });
}
- paymentButtonsLoader() {
- return (
-
-
-
- );
- }
-
renderCompletion(props: {
processing: boolean;
redirecting: boolean;
@@ -316,21 +253,18 @@ class DonateForm extends Component {
const { donationAmount, donationDuration } = this.state;
const {
donationFormState: { loading, processing },
- handleProcessing,
- addDonation,
defaultTheme,
theme,
t,
isMinimalForm,
isSignedIn,
- isDonating,
- isVariantA
+ isDonating
} = this.props;
const priorityTheme = defaultTheme ? defaultTheme : theme;
- const isOneTime = donationDuration === 'onetime';
+ const isOneTime = donationDuration === 'one-time';
const walletlabel = `${t(
isOneTime ? 'donate.wallet-label' : 'donate.wallet-label-1',
- { usd: donationAmount / 100 }
+ { usd: donationAmount / convertAmountToUSD }
)}:`;
const showMinimalPayments = isSignedIn && (isMinimalForm || !isDonating);
@@ -346,41 +280,38 @@ class DonateForm extends Component {
{t('donate.secure-donation')}
- {loading.stripe && loading.paypal && this.paymentButtonsLoader()}
+ {loading.stripe && loading.paypal && }
{(!loading.stripe || !loading.paypal) && (
-
+
)}
{showMinimalPayments && (
<>
{t('donate.or-card')}
>
)}
@@ -390,9 +321,21 @@ class DonateForm extends Component {
}
renderPageForm() {
+ const { donationAmount, donationDuration } = this.state;
+ const { t } = this.props;
+ const usd = formattedAmountLabel(donationAmount);
+ const hours = convertToTimeContributed(donationAmount);
+
+ let donationDescription = t('donate.your-donation-3', { usd, hours });
+
+ if (donationDuration === 'one-time') {
+ donationDescription = t('donate.your-donation', { usd, hours });
+ } else if (donationDuration === 'month') {
+ donationDescription = t('donate.your-donation-2', { usd, hours });
+ }
return (
<>
- {this.renderDonationDescription()}
+ {donationDescription}
{this.renderButtonGroup()}
>
);
diff --git a/client/src/components/Donation/donation-modal.tsx b/client/src/components/Donation/donation-modal.tsx
index c6b12f97380d33..f87e0bb17ad7cd 100644
--- a/client/src/components/Donation/donation-modal.tsx
+++ b/client/src/components/Donation/donation-modal.tsx
@@ -6,7 +6,10 @@ import { connect } from 'react-redux';
import { goToAnchor } from 'react-scrollable-anchor';
import { bindActionCreators, Dispatch, AnyAction } from 'redux';
import { createSelector } from 'reselect';
-import { modalDefaultDonation } from '../../../../config/donation-settings';
+import {
+ modalDefaultDonation,
+ PaymentContext
+} from '../../../../config/donation-settings';
import Cup from '../../assets/icons/cup';
import Heart from '../../assets/icons/heart';
@@ -20,10 +23,12 @@ import { playTone } from '../../utils/tone';
import { Spacer } from '../helpers';
import DonateForm from './donate-form';
+type RecentlyClaimedBlock = null | { block: string; superBlock: string };
+
const mapStateToProps = createSelector(
isDonationModalOpenSelector,
recentlyClaimedBlockSelector,
- (show: boolean, recentlyClaimedBlock: string) => ({
+ (show: boolean, recentlyClaimedBlock: RecentlyClaimedBlock) => ({
show,
recentlyClaimedBlock
})
@@ -43,7 +48,7 @@ type DonateModalProps = {
closeDonationModal: typeof closeDonationModal;
executeGA: typeof executeGA;
location?: WindowLocation;
- recentlyClaimedBlock: string;
+ recentlyClaimedBlock: RecentlyClaimedBlock;
show: boolean;
};
@@ -56,49 +61,30 @@ function DonateModal({
}: DonateModalProps): JSX.Element {
const [closeLabel, setCloseLabel] = React.useState(false);
const { t } = useTranslation();
- const handleProcessing = (
- duration: string,
- amount: number,
- action: string
- ) => {
- executeGA({
- type: 'event',
- data: {
- category: 'Donation',
- action: `Modal ${action}`,
- label: duration,
- value: amount
- }
- });
+ const handleProcessing = () => {
setCloseLabel(true);
};
useEffect(() => {
if (show) {
void playTone('donation');
- executeGA({ type: 'modal', data: '/donation-modal' });
+ executeGA({ event: 'pageview', pagePath: '/donation-modal' });
executeGA({
- type: 'event',
- data: {
- category: 'Donation View',
- action: `Displayed ${
- recentlyClaimedBlock ? 'block' : 'progress'
- } donation modal`,
- nonInteraction: true
- }
+ event: 'donationview',
+ action: `Displayed ${
+ recentlyClaimedBlock !== null ? 'Block' : 'Progress'
+ } Donation Modal`
});
}
}, [show, recentlyClaimedBlock, executeGA]);
- const getDonationText = () => {
+ const getCommonDonationText = () => {
const donationDuration = modalDefaultDonation.donationDuration;
switch (donationDuration) {
- case 'onetime':
+ case 'one-time':
return {t('donate.duration')} ;
case 'month':
return {t('donate.duration-2')} ;
- case 'year':
- return {t('donate.duration-3')} ;
default:
return {t('donate.duration-4')} ;
}
@@ -111,32 +97,28 @@ function DonateModal({
}
};
- const blockDonationText = (
+ const donationText = (
-
-
-
- {!closeLabel && (
-
- {t('donate.nicely-done', { block: recentlyClaimedBlock })}
-
- {getDonationText()}
-
+ {recentlyClaimedBlock !== null ? (
+
+ ) : (
+
)}
-
-
- );
-
- const progressDonationText = (
-
-
-
{!closeLabel && (
- {getDonationText()}
+ {recentlyClaimedBlock !== null && (
+
+ {t('donate.nicely-done', {
+ block: t(
+ `intro:${recentlyClaimedBlock.superBlock}.blocks.${recentlyClaimedBlock.block}.title`
+ )
+ })}
+
+ )}
+ {getCommonDonationText()}
)}
@@ -151,13 +133,14 @@ function DonateModal({
show={show}
>
- {recentlyClaimedBlock ? blockDonationText : progressDonationText}
+ {donationText}
diff --git a/client/src/components/Donation/donation-text-components.tsx b/client/src/components/Donation/donation-text-components.tsx
index 8df1792ca2fc48..208f989ccfda67 100644
--- a/client/src/components/Donation/donation-text-components.tsx
+++ b/client/src/components/Donation/donation-text-components.tsx
@@ -47,11 +47,13 @@ const FaqItem = (
const [isExpanded, setExpanded] = useState(false);
return (
-
setExpanded(!isExpanded)}>
+ setExpanded(!isExpanded)}
+ aria-expanded={isExpanded}
+ >
-
- {title}
-
+ {title}
{isExpanded && (
<>
diff --git a/client/src/components/Donation/donation.css b/client/src/components/Donation/donation.css
index b955c1dc26067a..2bb6675f6e148e 100644
--- a/client/src/components/Donation/donation.css
+++ b/client/src/components/Donation/donation.css
@@ -224,7 +224,7 @@
margin-bottom: 3px;
}
.amount-values.btn-group > .btn:first-child {
- margin-left: 2px;
+ margin-inline-start: 2px;
margin-bottom: 3px;
}
.amount-values.btn-group .btn + .btn {
@@ -519,11 +519,17 @@ a.patreon-button:hover {
}
.separator:not(:empty)::before {
- margin-right: 0.25em;
+ margin-inline-end: 0.25em;
}
.separator:not(:empty)::after {
- margin-left: 0.25em;
+ margin-inline-start: 0.25em;
+}
+
+.faq-item h3 {
+ font-size: 1rem;
+ line-height: 1.5;
+ margin: 0;
}
.faq-item div {
@@ -550,7 +556,7 @@ a.patreon-button:hover {
margin-bottom: 0;
padding: 0 4px;
left: 0;
- margin-left: -2px;
+ margin-inline-start: -2px;
}
.confirm-donation-btn svg.svg-inline--fa.fa-lock {
diff --git a/client/src/components/Donation/patreon-button.tsx b/client/src/components/Donation/patreon-button.tsx
index 7ea2702dcf13df..d40b355e1c3852 100644
--- a/client/src/components/Donation/patreon-button.tsx
+++ b/client/src/components/Donation/patreon-button.tsx
@@ -1,21 +1,23 @@
import React from 'react';
import {
donationUrls,
- patreonDefaultPledgeAmount
+ patreonDefaultPledgeAmount,
+ PaymentProvider
} from '../../../../config/donation-settings';
import envData from '../../../../config/env.json';
import PatreonLogo from '../../assets/images/components/patreon-logo';
+import { PostPayment } from './types';
const { patreonClientId }: { patreonClientId: string | null } = envData as {
patreonClientId: string | null;
};
interface PatreonButtonProps {
- postPatreonRedirect: () => void;
+ postPayment: (arg0: PostPayment) => void;
}
const PatreonButton = ({
- postPatreonRedirect
+ postPayment
}: PatreonButtonProps): JSX.Element | null => {
if (
!patreonClientId ||
@@ -36,7 +38,7 @@ const PatreonButton = ({
className='patreon-button link-button'
data-patreon-widget-type='become-patron-button'
href={href}
- onClick={postPatreonRedirect}
+ onClick={() => postPayment({ paymentProvider: PaymentProvider.Patreon })}
rel='noreferrer'
target='_blank'
>
diff --git a/client/src/components/Donation/paypal-button-script-loader.tsx b/client/src/components/Donation/paypal-button-script-loader.tsx
index 501164c47545dc..aa14fc5f724692 100644
--- a/client/src/components/Donation/paypal-button-script-loader.tsx
+++ b/client/src/components/Donation/paypal-button-script-loader.tsx
@@ -4,7 +4,7 @@ import ReactDOM from 'react-dom';
import { scriptLoader, scriptRemover } from '../../utils/script-loaders';
-import type { AddDonationData } from './paypal-button';
+import type { DonationApprovalData } from './types';
/* eslint-disable @typescript-eslint/naming-convention */
type PayPalButtonScriptLoaderProps = {
@@ -30,7 +30,7 @@ type PayPalButtonScriptLoaderProps = {
) => unknown;
isSubscription: boolean;
onApprove: (
- data: AddDonationData,
+ data: DonationApprovalData,
actions?: { order: { capture: () => Promise } }
) => unknown;
isPaypalLoading: boolean;
@@ -66,7 +66,7 @@ declare global {
}
}
-export class PayPalButtonScriptLoader extends Component<
+export default class PayPalButtonScriptLoader extends Component<
PayPalButtonScriptLoaderProps,
PayPalButtonScriptLoaderState
> {
@@ -188,7 +188,7 @@ export class PayPalButtonScriptLoader extends Component<
onApprove={
isSubscription
? (
- data: AddDonationData,
+ data: DonationApprovalData,
actions: { order: { capture: () => Promise } }
) => onApprove(data, actions)
: (
diff --git a/client/src/components/Donation/paypal-button.test.tsx b/client/src/components/Donation/paypal-button.test.tsx
deleted file mode 100644
index 5c60f0ec5d349e..00000000000000
--- a/client/src/components/Donation/paypal-button.test.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-import { render } from '@testing-library/react';
-import React from 'react';
-import { Themes } from '../settings/theme';
-
-import { PaypalButton } from './paypal-button';
-
-const commonProps = {
- donationAmount: 500,
- donationDuration: 'month',
- handleProcessing: () => null,
- isDonating: false,
- onDonationStateChange: () => null,
- isPaypalLoading: true,
- t: jest.fn(),
- theme: Themes.Night,
- handlePaymentButtonLoad: jest.fn(),
- isMinimalForm: true
-};
-
-const donationData = {
- redirecting: false,
- processing: false,
- success: false,
- error: null
-};
-
-jest.mock('../../analytics');
-
-describe(' ', () => {
- it('does not call addDonate api on payment approval when user is not signed ', () => {
- const ref = React.createRef();
- const isSubscription = true;
- const addDonation = jest.fn();
- render(
-
- );
-
- ref.current?.handleApproval(donationData, isSubscription);
- expect(addDonation).toBeCalledTimes(0);
- });
- it('calls addDonate api on payment approval when user is signed in', () => {
- const ref = React.createRef();
- const isSubscription = true;
- const addDonation = jest.fn();
- render(
-
- );
-
- ref.current?.handleApproval(donationData, isSubscription);
- expect(addDonation).toBeCalledTimes(1);
- });
-});
diff --git a/client/src/components/Donation/paypal-button.tsx b/client/src/components/Donation/paypal-button.tsx
index 7d51b8063a7e31..3e54d4fd1190ee 100644
--- a/client/src/components/Donation/paypal-button.tsx
+++ b/client/src/components/Donation/paypal-button.tsx
@@ -5,23 +5,23 @@ import { createSelector } from 'reselect';
import {
paypalConfigurator,
paypalConfigTypes,
- defaultDonation
+ defaultDonation,
+ PaymentProvider
} from '../../../../config/donation-settings';
import envData from '../../../../config/env.json';
import { userSelector, signInLoadingSelector } from '../../redux/selectors';
import { Themes } from '../settings/theme';
-import { PayPalButtonScriptLoader } from './paypal-button-script-loader';
+import {
+ DonationApprovalData,
+ PostPayment,
+ DonationDuration,
+ DonationAmount
+} from './types';
+import PayPalButtonScriptLoader from './paypal-button-script-loader';
type PaypalButtonProps = {
- addDonation: (data: AddDonationData) => void;
- isSignedIn: boolean;
- donationAmount: number;
- donationDuration: string;
- handleProcessing: (
- duration: string,
- amount: number,
- action: string
- ) => unknown;
+ donationAmount: DonationAmount;
+ donationDuration: DonationDuration;
isDonating: boolean;
onDonationStateChange: ({
redirecting,
@@ -35,13 +35,13 @@ type PaypalButtonProps = {
error: string | null;
}) => void;
isPaypalLoading: boolean;
- skipAddDonation?: boolean;
t: (label: string) => string;
ref?: Ref;
theme: Themes;
isSubscription?: boolean;
handlePaymentButtonLoad: (provider: 'stripe' | 'paypal') => void;
isMinimalForm: boolean | undefined;
+ postPayment: (arg0: PostPayment) => void;
};
type PaypalButtonState = {
@@ -50,17 +50,6 @@ type PaypalButtonState = {
planId: string | null;
};
-export interface AddDonationData {
- redirecting: boolean;
- processing: boolean;
- success: boolean;
- error: string | null;
- loading?: {
- stripe: boolean;
- paypal: boolean;
- };
-}
-
const {
paypalClientId,
deploymentEnv
@@ -70,10 +59,7 @@ const {
deploymentEnv: 'staging' | 'live';
};
-export class PaypalButton extends Component<
- PaypalButtonProps,
- PaypalButtonState
-> {
+class PaypalButton extends Component {
static displayName = 'PaypalButton';
state: PaypalButtonState = {
amount: defaultDonation.donationAmount,
@@ -82,7 +68,6 @@ export class PaypalButton extends Component<
};
constructor(props: PaypalButtonProps) {
super(props);
- this.handleApproval = this.handleApproval.bind(this);
}
static getDerivedStateFromProps(
@@ -90,8 +75,8 @@ export class PaypalButton extends Component<
): PaypalButtonState {
const { donationAmount, donationDuration } = props;
const configurationObj: {
- amount: number;
- duration: string;
+ amount: DonationAmount;
+ duration: DonationDuration;
planId: string | null;
} = paypalConfigurator(
donationAmount,
@@ -105,30 +90,10 @@ export class PaypalButton extends Component<
return { ...configurationObj };
}
- handleApproval = (data: AddDonationData, isSubscription: boolean): void => {
- const { amount, duration } = this.state;
- const { isSignedIn = false } = this.props;
-
- // If the user is signed in and the payment is subscritipn call the api
- if (isSignedIn && isSubscription) {
- this.props.addDonation(data);
- }
-
- this.props.handleProcessing(duration, amount, 'Paypal payment submission');
-
- // Show success anytime because the payment has gone through paypal
- this.props.onDonationStateChange({
- redirecting: false,
- processing: false,
- success: true,
- error: data.error ? data.error : null
- });
- };
-
render(): JSX.Element | null {
const { duration, planId, amount } = this.state;
const { t, theme, isPaypalLoading, isMinimalForm } = this.props;
- const isSubscription = duration !== 'onetime';
+ const isSubscription = duration !== 'one-time';
const buttonColor = theme === Themes.Night ? 'white' : 'gold';
if (!paypalClientId) {
return null;
@@ -177,8 +142,11 @@ export class PaypalButton extends Component<
isMinimalForm={isMinimalForm}
isPaypalLoading={isPaypalLoading}
isSubscription={isSubscription}
- onApprove={(data: AddDonationData) => {
- this.handleApproval(data, isSubscription);
+ onApprove={(data: DonationApprovalData) => {
+ this.props.postPayment({
+ paymentProvider: PaymentProvider.Paypal,
+ data
+ });
}}
onCancel={() => {
this.props.onDonationStateChange({
diff --git a/client/src/components/Donation/stripe-card-form.tsx b/client/src/components/Donation/stripe-card-form.tsx
index deb1d9c0f2e7db..f10ac62de7081b 100644
--- a/client/src/components/Donation/stripe-card-form.tsx
+++ b/client/src/components/Donation/stripe-card-form.tsx
@@ -9,33 +9,23 @@ import {
import { loadStripe } from '@stripe/stripe-js';
import type {
StripeCardNumberElementChangeEvent,
- StripeCardExpiryElementChangeEvent,
- PaymentIntentResult
+ StripeCardExpiryElementChangeEvent
} from '@stripe/stripe-js';
import React, { useState } from 'react';
+import { PaymentProvider } from '../../../../config/donation-settings';
import envData from '../../../../config/env.json';
import { Themes } from '../settings/theme';
-import { AddDonationData } from './paypal-button';
-import SecurityLockIcon from './security-lock-icon';
+import { DonationApprovalData, PostPayment } from './types';
const { stripePublicKey }: { stripePublicKey: string | null } = envData;
-export type HandleAuthentication = (
- clientSecret: string,
- paymentMethod: string
-) => Promise;
-
interface FormPropTypes {
- onDonationStateChange: (donationState: AddDonationData) => void;
- postStripeCardDonation: (
- paymentMethodId: string,
- handleAuthentication: HandleAuthentication
- ) => void;
+ onDonationStateChange: (donationState: DonationApprovalData) => void;
+ postPayment: (arg0: PostPayment) => void;
t: (label: string) => string;
theme: Themes;
processing: boolean;
- isVariantA: boolean;
}
interface Element {
@@ -50,9 +40,8 @@ const StripeCardForm = ({
theme,
t,
onDonationStateChange,
- postStripeCardDonation,
- processing,
- isVariantA
+ postPayment,
+ processing
}: FormPropTypes): JSX.Element => {
const [isSubmissionValid, setSubmissionValidity] = useState(true);
const [isTokenizing, setTokenizing] = useState(false);
@@ -124,7 +113,11 @@ const StripeCardForm = ({
error: t('donate.went-wrong')
});
} else if (paymentMethod)
- postStripeCardDonation(paymentMethod.id, handleAuthentication);
+ postPayment({
+ paymentProvider: PaymentProvider.StripeCard,
+ paymentMethodId: paymentMethod.id,
+ handleAuthentication
+ });
}
}
return setTokenizing(false);
@@ -170,7 +163,6 @@ const StripeCardForm = ({
disabled={!stripe || !elements || isSubmitting}
type='submit'
>
- {!isVariantA && }
{t('buttons.donate')}
diff --git a/client/src/components/Donation/types.ts b/client/src/components/Donation/types.ts
new file mode 100644
index 00000000000000..956c8da1518ec5
--- /dev/null
+++ b/client/src/components/Donation/types.ts
@@ -0,0 +1,37 @@
+import type { Token, PaymentIntentResult } from '@stripe/stripe-js';
+
+export type PaymentContext = 'modal' | 'donate page' | 'certificate';
+export type PaymentProvider = 'patreon' | 'paypal' | 'stripe' | 'stripe card';
+
+export type HandleAuthentication = (
+ clientSecret: string,
+ paymentMethod: string
+) => Promise
;
+
+export type DonationAmount = 500 | 1000 | 2000 | 3000 | 4000 | 5000;
+export type DonationDuration = 'one-time' | 'month';
+export interface DonationConfig {
+ donationAmount: DonationAmount;
+ donationDuration: DonationDuration;
+}
+
+export interface PostPayment {
+ paymentProvider: PaymentProvider;
+ data?: DonationApprovalData;
+ token?: Token;
+ payerEmail?: string | undefined;
+ payerName?: string | undefined;
+ paymentMethodId?: string;
+ handleAuthentication?: HandleAuthentication;
+}
+
+export interface DonationApprovalData {
+ redirecting: boolean;
+ processing: boolean;
+ success: boolean;
+ error: string | null;
+ loading?: {
+ stripe: boolean;
+ paypal: boolean;
+ };
+}
diff --git a/client/src/components/Donation/walletsButton.tsx b/client/src/components/Donation/walletsButton.tsx
index c3831744609f9d..668b279ee6085a 100644
--- a/client/src/components/Donation/walletsButton.tsx
+++ b/client/src/components/Donation/walletsButton.tsx
@@ -8,7 +8,8 @@ import type { Token, PaymentRequest } from '@stripe/stripe-js';
import React, { useState, useEffect } from 'react';
import envData from '../../../../config/env.json';
import { Themes } from '../settings/theme';
-import { AddDonationData } from './paypal-button';
+import { PaymentProvider } from '../../../../config/donation-settings';
+import { DonationApprovalData, PostPayment } from './types';
const { stripePublicKey }: { stripePublicKey: string | null } = envData;
@@ -16,12 +17,8 @@ interface WrapperProps {
label: string;
amount: number;
theme: Themes;
- postStripeDonation: (
- token: Token,
- payerEmail: string | undefined,
- payerName: string | undefined
- ) => void;
- onDonationStateChange: (donationState: AddDonationData) => void;
+ postPayment: (arg0: PostPayment) => void;
+ onDonationStateChange: (donationState: DonationApprovalData) => void;
refreshErrorMessage: string;
handlePaymentButtonLoad: (provider: 'stripe' | 'paypal') => void;
}
@@ -35,7 +32,7 @@ const WalletsButton = ({
amount,
theme,
refreshErrorMessage,
- postStripeDonation,
+ postPayment,
onDonationStateChange,
handlePaymentButtonLoad
}: WalletsButtonProps) => {
@@ -63,7 +60,12 @@ const WalletsButton = ({
const { token, payerEmail, payerName } = event;
setToken(token);
event.complete('success');
- postStripeDonation(token, payerEmail, payerName);
+ postPayment({
+ paymentProvider: PaymentProvider.Stripe,
+ token,
+ payerEmail,
+ payerName
+ });
});
void pr.canMakePayment().then(canMakePaymentRes => {
@@ -74,7 +76,7 @@ const WalletsButton = ({
checkpaymentPossiblity(false);
}
});
- }, [label, amount, stripe, postStripeDonation, handlePaymentButtonLoad]);
+ }, [label, amount, stripe, postPayment, handlePaymentButtonLoad]);
const displayRefreshError = (): void => {
onDonationStateChange({
diff --git a/client/src/components/Flash/index.tsx b/client/src/components/Flash/index.tsx
index 6accd829365ded..e753212cf45df4 100644
--- a/client/src/components/Flash/index.tsx
+++ b/client/src/components/Flash/index.tsx
@@ -1,5 +1,5 @@
import { Alert } from '@freecodecamp/react-bootstrap';
-import React, { useState, useEffect } from 'react';
+import React from 'react';
import { useTranslation } from 'react-i18next';
import { TransitionGroup, CSSTransition } from 'react-transition-group';
import { FlashState } from '../../redux/types';
@@ -15,45 +15,24 @@ type FlashProps = {
function Flash({ flashMessage, removeFlashMessage }: FlashProps): JSX.Element {
const { type, message, id, variables } = flashMessage;
const { t } = useTranslation();
- const [flashMessageHeight, setFlashMessageHeight] = useState(0);
-
- useEffect(() => {
- const flashMessageElem: HTMLElement | null =
- document.querySelector('.flash-message');
- setFlashMessageHeight(flashMessageElem?.offsetHeight || 0);
- document.documentElement.style.setProperty(
- '--flash-message-height',
- `${flashMessageHeight}px`
- );
- }, [flashMessageHeight]);
function handleClose() {
- document.documentElement.style.setProperty('--flash-message-height', '0px');
removeFlashMessage();
}
return (
- <>
-
-
-
- {t(message, variables)}
-
-
-
- {flashMessage && (
-
- )}
- >
+
+
+
+ {t(message, variables)}
+
+
+
);
}
diff --git a/client/src/components/Footer/footer.css b/client/src/components/Footer/footer.css
index 69748558984d31..730b1096829151 100644
--- a/client/src/components/Footer/footer.css
+++ b/client/src/components/Footer/footer.css
@@ -10,12 +10,8 @@
}
.footer-container {
- margin-right: auto;
- margin-left: auto;
- padding-left: 15px;
- padding-right: 15px;
- padding-top: 40px;
- padding-bottom: 40px;
+ margin-inline: auto;
+ padding: 40px 15px;
font-size: 16px;
overflow-x: hidden;
}
@@ -57,8 +53,7 @@
display: flex;
flex-direction: column;
flex: 0 0 100%;
- padding-left: 15px;
- padding-right: 15px;
+ padding-inline: 15px;
font-size: 16px;
}
@@ -77,8 +72,7 @@
flex: 1 0 90%;
display: flex;
flex-direction: column;
- padding-left: 15px;
- padding-right: 15px;
+ padding-inline: 15px;
margin-bottom: 30px;
}
@@ -125,7 +119,7 @@ p.footer-donation a:hover {
flex-direction: row;
}
.footer-right {
- padding-left: 15px;
+ padding-inline-start: 15px;
}
.footer-col-1,
.footer-col-2,
@@ -152,7 +146,7 @@ p.footer-donation a:hover {
flex-direction: column;
}
.footer-right {
- padding-left: 0;
+ padding-inline-start: 0;
}
.footer-container .col-spacer {
margin-top: 40px;
diff --git a/client/src/components/FourOhFour/404.css b/client/src/components/FourOhFour/404.css
index ebc2607d8efc52..ef87fe44c3f41d 100644
--- a/client/src/components/FourOhFour/404.css
+++ b/client/src/components/FourOhFour/404.css
@@ -15,7 +15,8 @@
.quote-wrapper {
background-color: var(--tertiary-background);
- padding: 20px 20px 20px 42px;
+ padding-inline: 42px 20px;
+ padding-block: 20px;
border-width: 0;
position: relative;
max-width: 980px;
@@ -34,7 +35,7 @@
color: var(--tertiary-color);
font-family: 'Arial', sans-serif;
font-style: normal;
- padding-left: 15px;
+ padding-inline-start: 15px;
padding-top: 5px;
position: absolute;
border-radius: 0;
diff --git a/client/src/components/Header/components/nav-links.tsx b/client/src/components/Header/components/nav-links.tsx
index dc9bd246338de5..bd6da9d1a3364e 100644
--- a/client/src/components/Header/components/nav-links.tsx
+++ b/client/src/components/Header/components/nav-links.tsx
@@ -1,6 +1,3 @@
-/* eslint-disable @typescript-eslint/ban-ts-comment */
-/* eslint-disable @typescript-eslint/no-unsafe-call */
-// @ts-nocheck
import {
faCheckSquare,
faHeart,
@@ -11,7 +8,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import React, { Component, Fragment, createRef } from 'react';
import { TFunction, withTranslation } from 'react-i18next';
import { connect } from 'react-redux';
-import envData from '../../../../../config/env.json';
+import { clientLocale, radioLocation } from '../../../../../config/env.json';
import {
availableLangs,
LangNames,
@@ -26,14 +23,6 @@ import { Themes } from '../../settings/theme';
import LanguageGlobe from '../../../assets/icons/language-globe';
import { User } from '../../../redux/prop-types';
-interface NavigationLocationApi {
- clientLocale: string;
- radioLocation: string;
- apiLocation: string;
-}
-
-const { clientLocale, radioLocation } = envData as NavigationLocationApi;
-
const locales = availableLangs.client.filter(
lang => !hiddenLangs.includes(lang)
);
@@ -50,10 +39,10 @@ interface NavLinksProps {
t: TFunction;
showMenu: () => void;
hideMenu: () => void;
- toggleNightMode: (theme: Themes) => void;
+ toggleNightMode: (theme: Themes) => Themes;
user?: User;
navigate?: (location: string) => void;
- showLanguageMenu: (elementToFocus: HTMLButtonElement) => void;
+ showLanguageMenu: (elementToFocus: HTMLButtonElement | null) => void;
hideLanguageMenu: () => void;
menuButtonRef: React.RefObject;
openSignoutModal: () => void;
@@ -65,7 +54,7 @@ const mapDispatchToProps = {
openSignoutModal
};
-export class NavLinks extends Component {
+class NavLinks extends Component {
static displayName: string;
langButtonRef: React.RefObject;
firstLangOptionRef: React.RefObject;
@@ -95,11 +84,14 @@ export class NavLinks extends Component {
);
}
- getPreviousMenuItem(target: HTMLButtonElement): HTMLButtonElement {
+ getPreviousMenuItem(target: HTMLButtonElement | null) {
const { menuButtonRef } = this.props;
const previousSibling =
target?.closest('.nav-list > li')?.previousElementSibling;
- return previousSibling?.querySelector('a, button') ?? menuButtonRef.current;
+ const previousButton = previousSibling?.querySelector<
+ HTMLButtonElement | HTMLAnchorElement
+ >('a, button');
+ return previousButton ?? menuButtonRef.current;
}
handleLanguageChange = (event: React.MouseEvent): void => {
@@ -144,7 +136,9 @@ export class NavLinks extends Component {
}
};
- handleMenuKeyDown = (event: React.KeyboardEvent): void => {
+ handleMenuKeyDown = (
+ event: React.KeyboardEvent
+ ) => {
const { menuButtonRef, hideMenu } = this.props;
if (event.key === 'Escape') {
menuButtonRef.current?.focus();
@@ -153,7 +147,7 @@ export class NavLinks extends Component {
}
};
- handleLanguageButtonClick = (): void => {
+ handleLanguageButtonClick = () => {
const { isLanguageMenuDisplayed, hideLanguageMenu, showLanguageMenu } =
this.props;
if (isLanguageMenuDisplayed) {
@@ -163,38 +157,72 @@ export class NavLinks extends Component {
}
};
+ handleSignOutKeys = (
+ event: React.KeyboardEvent
+ ) => {
+ const { menuButtonRef, hideMenu } = this.props;
+ const DoKeyPress = new Map void }>([
+ [
+ 'Escape',
+ {
+ select: () => {
+ menuButtonRef.current?.focus();
+ hideMenu();
+ event.preventDefault();
+ }
+ }
+ ],
+ [
+ 'Tab',
+ {
+ select: () => {
+ const camperPressedTheShiftKey = event.shiftKey;
+ if (!camperPressedTheShiftKey) {
+ hideMenu();
+ }
+ }
+ }
+ ]
+ ]);
+ DoKeyPress.get(event.key)?.select();
+ };
handleLanguageButtonKeyDown = (
event: React.KeyboardEvent
): void => {
const { menuButtonRef, showLanguageMenu, hideMenu } = this.props;
- interface DoKeyPressProp {
- Escape: () => void;
- ArrowDown: () => void;
- ArrowUp: () => void;
- }
-
- // eslint naming convention should be ignored in key press function, because following the name convention harms accessiblity.
-
- const DoKeyPress: DoKeyPressProp = {
- // eslint-disable-next-line @typescript-eslint/naming-convention
- Escape: () => {
- menuButtonRef.current?.focus();
- hideMenu();
- event.preventDefault();
- },
- // eslint-disable-next-line @typescript-eslint/naming-convention
- ArrowDown: () => {
- showLanguageMenu(this.firstLangOptionRef.current);
- event.preventDefault();
- },
- // eslint-disable-next-line @typescript-eslint/naming-convention
- ArrowUp: () => {
- showLanguageMenu(this.lastLangOptionRef.current);
- event.preventDefault();
- }
- };
- DoKeyPress[event.key]?.();
+ // the strings in map need to start with a Capital latter, because event.key preduce a string that starts with a capital latter
+ const DoKeyPress = new Map void }>([
+ [
+ 'Escape',
+ {
+ select: () => {
+ menuButtonRef.current?.focus();
+ hideMenu();
+ event.preventDefault();
+ }
+ }
+ ],
+ [
+ 'ArrowDown',
+ {
+ select: () => {
+ showLanguageMenu(this.firstLangOptionRef.current);
+ event.preventDefault();
+ }
+ }
+ ],
+ [
+ 'ArrowUp',
+ {
+ select: () => {
+ showLanguageMenu(this.lastLangOptionRef.current);
+ event.preventDefault();
+ }
+ }
+ ]
+ ]);
+ DoKeyPress.get(event.key)?.select();
};
handleLanguageMenuKeyDown = (
@@ -209,70 +237,93 @@ export class NavLinks extends Component {
this.lastLangOptionRef.current?.focus();
event.preventDefault();
};
- const DoKeyPress = {
- // eslint-disable-next-line @typescript-eslint/naming-convention
- Tab: () => {
- if (!event.shiftKey) {
- // Let the Tab work as normal.
- hideLanguageMenu();
- // Close the menu if focus is now outside of the menu. This will
- // happen when there is no Sign Out menu item.
- setTimeout(() => {
- const currentlyFocusedElement = document.activeElement;
- if (
- currentlyFocusedElement &&
- !currentlyFocusedElement.closest('.nav-list')
- ) {
- hideMenu();
+ const DoKeyPress = new Map void }>([
+ [
+ 'Tab',
+ {
+ select: () => {
+ if (!event.shiftKey) {
+ // Let the Tab work as normal.
+ hideLanguageMenu();
+ // Close the menu if focus is now outside of the menu. This will
+ // happen when there is no Sign Out menu item.
+ setTimeout(() => {
+ const currentlyFocusedElement = document.activeElement;
+ if (
+ currentlyFocusedElement &&
+ !currentlyFocusedElement.closest('.nav-list')
+ ) {
+ hideMenu();
+ }
+ }, 200);
+ return;
}
- }, 200);
- return;
+ // Because FF adds an extra Tab stop to the lang menu (because it
+ // is scrollable) we need to manually focus the previous menu item.
+ const currentButton = this.langButtonRef.current;
+ this.getPreviousMenuItem(currentButton)?.focus();
+ hideLanguageMenu();
+ event.preventDefault();
+ }
}
- // Because FF adds an extra Tab stop to the lang menu (because it
- // is scrollable) we need to manually focus the previous menu item.
- this.getPreviousMenuItem(this.langButtonRef.current).focus();
- hideLanguageMenu();
- event.preventDefault();
- },
- // eslint-disable-next-line @typescript-eslint/naming-convention
- ArrowUp: () => {
- const ArrowUpItemToFocus =
- event.target === this.firstLangOptionRef.current
- ? this.lastLangOptionRef.current
- : (event.currentTarget.parentNode?.previousSibling
- ?.firstChild as HTMLElement);
- ArrowUpItemToFocus?.focus();
- event.preventDefault();
- },
- // eslint-disable-next-line @typescript-eslint/naming-convention
- ArrowDown: () => {
- const ArrowDownItemToFocus =
- event.target === this.lastLangOptionRef.current
- ? this.firstLangOptionRef.current
- : (event.currentTarget.parentNode?.nextSibling
- ?.firstChild as HTMLElement);
- ArrowDownItemToFocus?.focus();
- event.preventDefault();
- },
- // eslint-disable-next-line @typescript-eslint/naming-convention
- Escape: () => {
- // Set focus to language button first so we don't lose focus
- // for screen readers.
- this.langButtonRef.current?.focus();
- hideLanguageMenu();
- event.preventDefault();
- },
- Home: focusFirstLanguageMenuItem,
- PageUp: focusFirstLanguageMenuItem,
- End: focusLastLanguageMenuItem,
- PageDown: focusLastLanguageMenuItem
- };
- DoKeyPress[event.key]?.();
+ ],
+ [
+ 'Escape',
+ {
+ select: () => {
+ this.langButtonRef.current?.focus();
+ hideLanguageMenu();
+ event.preventDefault();
+ }
+ }
+ ],
+ [
+ 'ArrowDown',
+ {
+ select: () => {
+ const isFocusOnLastLanguageOption =
+ event.target === this.lastLangOptionRef.current;
+ const selectCancelButton = this.firstLangOptionRef.current?.focus();
+ const selectNextLanguage = (
+ event.currentTarget.parentNode?.nextSibling
+ ?.firstChild as HTMLButtonElement
+ )?.focus();
+ isFocusOnLastLanguageOption
+ ? selectCancelButton
+ : selectNextLanguage;
+ event.preventDefault();
+ }
+ }
+ ],
+ [
+ 'ArrowUp',
+ {
+ select: () => {
+ const isFocusOnCancelButton =
+ event.target === this.firstLangOptionRef.current;
+ const selectLastLanguage = this.lastLangOptionRef.current?.focus();
+ // selectPreviousLanguage is a childNode and doesn't have focus property but it still works somehow,
+ // IDK how it works, and how to please TypeScript, for now I am lying to TypeScript
+ const selectPreviousLanguage = (
+ event.currentTarget.parentNode?.previousSibling
+ ?.firstChild as HTMLButtonElement
+ )?.focus();
+ isFocusOnCancelButton ? selectLastLanguage : selectPreviousLanguage;
+ event.preventDefault();
+ }
+ }
+ ],
+ ['Home', { select: focusFirstLanguageMenuItem }],
+ ['PageUp', { select: focusFirstLanguageMenuItem }],
+ ['End', { select: focusLastLanguageMenuItem }],
+ ['PageDown', { select: focusLastLanguageMenuItem }]
+ ]);
+ DoKeyPress.get(event.key)?.select();
};
// Added to the last item in the nav menu. Will close the menu if
// the user Tabs out of the menu.
- handleBlur = (event: React.FocusEvent): void => {
+ handleBlur = (event: React.FocusEvent) => {
const { hideMenu, menuButtonRef } = this.props;
if (
event.relatedTarget &&
@@ -296,9 +347,11 @@ export class NavLinks extends Component {
fetchState,
t,
toggleNightMode,
- user: { isDonating = false, username, theme }
+ user
}: NavLinksProps = this.props;
-
+ const currentUserDonating = user?.isDonating;
+ const currentUserName = user?.username;
+ const currentUserTheme = user?.theme;
const { pending } = fetchState;
return pending ? (
@@ -310,7 +363,7 @@ export class NavLinks extends Component {
isLanguageMenuDisplayed ? ' display-lang-menu' : ''
}`}
>
- {isDonating ? (
+ {currentUserDonating ? (
{t('donate.thanks')}
@@ -338,14 +391,14 @@ export class NavLinks extends Component
{
{t('buttons.curriculum')}
- {username && (
-
+ {currentUserName && (
+ <>
{t('buttons.profile')}
@@ -360,7 +413,7 @@ export class NavLinks extends Component {
{t('buttons.settings')}
-
+ >
)}
{
{
- if (username) {
- this.toggleTheme(String(theme) as Themes, toggleNightMode);
+ if (currentUserName) {
+ this.toggleTheme(currentUserTheme, toggleNightMode);
}
}}
onKeyDown={this.handleMenuKeyDown}
>
- {username ? (
+ {currentUserName ? (
<>
{t('settings.labels.night-mode')}
- {theme === Themes.Night ? (
+ {currentUserTheme === Themes.Night ? (
) : (
@@ -439,6 +493,13 @@ export class NavLinks extends Component {
+ {/*
+ The div existences create edge case in which camper skips the change language,
+ when they press "shift+tab" on signout button whenever signout focus events uses `getPreviousMenuItem`.
+ To fix this we need to remove `div`, but this creates a bug which close the menu when someone interact with it any other way except the keyboard.
+ This is a complexy and footgun that can break the site without notices and we shouldn't carry,
+ to sort this we need to remove the div and make focus events simpler, but that's a ToDo for later.
+ */}
{
- {username && (
-
-
-
- {t('buttons.sign-out')}
-
-
-
+ {currentUserName && (
+
+
+ {t('buttons.sign-out')}
+
+
)}
);
@@ -518,4 +579,7 @@ export class NavLinks extends Component {
NavLinks.displayName = 'NavLinks';
+/* eslint-disable @typescript-eslint/ban-ts-comment */
+//@ts-ignore
+// to please TypeScript, action.js needs to be migrated to TypeScript
export default connect(null, mapDispatchToProps)(withTranslation()(NavLinks));
diff --git a/client/src/components/Header/components/nav-logo.tsx b/client/src/components/Header/components/nav-logo.tsx
index 94111b149c73f5..393b8f32df0fef 100644
--- a/client/src/components/Header/components/nav-logo.tsx
+++ b/client/src/components/Header/components/nav-logo.tsx
@@ -1,6 +1,6 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
-import FreeCodeCampLogo from '../../../assets/icons/FreeCodeCamp-logo';
+import FreeCodeCampLogo from '../../../assets/icons/freecodecamp';
const NavLogo = (): JSX.Element => {
const { t } = useTranslation();
diff --git a/client/src/components/Header/components/universal-nav.css b/client/src/components/Header/components/universal-nav.css
index c8bed3e19d6eaf..83d8dec691c000 100644
--- a/client/src/components/Header/components/universal-nav.css
+++ b/client/src/components/Header/components/universal-nav.css
@@ -21,7 +21,7 @@
.universal-nav-left {
display: flex;
flex: 1 0 33%;
- margin-left: 0;
+ margin-inline-start: 0;
z-index: 2000;
}
@@ -41,6 +41,7 @@
display: flex;
justify-content: flex-end;
align-items: center;
+ gap: 10px;
flex: 1 0 33%;
height: var(--header-height);
}
@@ -82,7 +83,6 @@
justify-content: flex-end;
width: 100vw;
height: auto;
- margin: 0 0 0 -12px;
padding: 0;
list-style: none;
max-width: 15rem;
@@ -313,14 +313,14 @@ button.nav-link[aria-disabled='true'] {
.nav-skeleton {
height: var(--header-height);
- margin-right: 15px;
+ margin-inline-end: 15px;
width: 350px;
}
.nav-list .fcc-loader {
padding: 0 40px;
- margin-left: 35px;
- margin-right: 25px;
+ margin-inline-start: 35px;
+ margin-inline-end: 25px;
}
.toggle-button-nav {
@@ -332,7 +332,6 @@ button.nav-link[aria-disabled='true'] {
background-color: var(--theme-color);
cursor: pointer;
max-height: calc(var(--header-height) - 8px);
- margin-right: 10px;
display: flex;
align-items: center;
}
@@ -436,8 +435,8 @@ button.nav-link[aria-disabled='true'] {
.signup-btn {
max-height: calc(var(--header-height) - 6px);
padding: 4px 12px;
- margin-left: 2px;
- font-family: 'Hack-ZeroSlash', monospace !important;
+ margin-inline-start: 2px;
+ font-family: 'Hack-ZeroSlash', monospace;
display: flex;
align-items: center;
justify-content: center;
@@ -445,16 +444,12 @@ button.nav-link[aria-disabled='true'] {
.universal-nav-right .fcc_searchBar {
position: absolute;
- top: 0;
+ top: var(--header-height);
left: 0;
}
.universal-nav-right .fcc_searchBar .ais-SearchBox-form {
- width: 100vw;
- height: var(--search-box-form);
max-width: unset;
- padding: 0 15px;
- left: 0;
}
/* In mobile layout, prevent search input from hanging around if the
@@ -475,26 +470,24 @@ button.nav-link[aria-disabled='true'] {
display: none;
}
-.universal-nav-right .ais-SearchBox-input {
+.universal-nav-right .ais-SearchBox-form {
width: calc(100vw - 17rem);
- padding-left: 27px;
+ margin-inline-start: 15px;
}
.universal-nav-right .fcc_searchBar .ais-Hits {
width: calc(100vw - 17rem);
}
-.universal-nav-right .fcc_searchBar .ais-SearchBox-submit {
- top: unset;
- margin-top: 19px;
- left: 18px;
-}
-
.ais-SearchBox-input:focus {
+ box-sizing: content-box;
+ margin-inline-start: -30px;
+ padding-inline: 35px;
outline: 3px solid var(--blue-mid);
}
-.ais-SearchBox-submit:focus {
+.ais-SearchBox-submit:focus,
+.ais-SearchBox-reset:focus {
outline: 3px solid var(--blue-mid);
}
@@ -528,10 +521,6 @@ button.nav-link[aria-disabled='true'] {
}
.fcc_searchBar .ais-SearchBox-form {
- display: flex;
- position: absolute;
- top: var(--header-height);
- left: 15px;
max-width: calc(100vw - 350px);
}
@@ -560,17 +549,13 @@ button.nav-link[aria-disabled='true'] {
}
.universal-nav-right .fcc_searchBar .ais-SearchBox-form {
- width: 100%;
+ width: calc(100% - 30px);
}
.display-menu {
max-height: calc(100vh - var(--header-height) * 2);
}
- .universal-nav-right .ais-SearchBox-input {
- width: calc(100vw - 30px);
- }
-
.universal-nav-right .fcc_searchBar .ais-Hits {
width: calc(100% - 30px);
}
diff --git a/client/src/components/Header/components/universal-nav.tsx b/client/src/components/Header/components/universal-nav.tsx
index ea1ce8aec2d6b7..c2eb7da86a9684 100644
--- a/client/src/components/Header/components/universal-nav.tsx
+++ b/client/src/components/Header/components/universal-nav.tsx
@@ -26,7 +26,7 @@ interface UniversalNavProps {
searchBarRef?: React.RefObject;
showMenu: () => void;
hideMenu: () => void;
- showLanguageMenu: (elementToFocus: HTMLButtonElement) => void;
+ showLanguageMenu: (elementToFocus: HTMLButtonElement | null) => void;
hideLanguageMenu: () => void;
user?: User;
}
diff --git a/client/src/components/Header/index.tsx b/client/src/components/Header/index.tsx
index 54a6532bb4cae9..d55e39a397e94b 100644
--- a/client/src/components/Header/index.tsx
+++ b/client/src/components/Header/index.tsx
@@ -13,6 +13,7 @@ import './header.css';
interface HeaderProps {
fetchState: { pending: boolean };
user: User;
+ skipButtonText: string;
}
export class Header extends React.Component<
HeaderProps,
@@ -46,6 +47,8 @@ export class Header extends React.Component<
// the search bar should not toggle the menu
this.searchBarRef.current &&
!this.searchBarRef.current.contains(eventTarget) &&
+ // don't count clicks on searcn bar inputs reset button
+ !eventTarget.closest('.ais-SearchBox-reset') &&
// don't count clicks on language button/menu
!eventTarget.closest('.nav-lang') &&
// don't count clicks on disabled elements
@@ -69,9 +72,9 @@ export class Header extends React.Component<
}
// elementToFocus must be a link in the language menu
- showLanguageMenu(elementToFocus: HTMLButtonElement): void {
+ showLanguageMenu(elementToFocus: HTMLButtonElement | null): void {
this.setState({ isLanguageMenuDisplayed: true }, () =>
- elementToFocus.focus()
+ elementToFocus?.focus()
);
}
@@ -81,7 +84,7 @@ export class Header extends React.Component<
render(): JSX.Element {
const { displayMenu, isLanguageMenuDisplayed } = this.state;
- const { fetchState, user } = this.props;
+ const { fetchState, user, skipButtonText } = this.props;
return (
<>
@@ -93,7 +96,7 @@ export class Header extends React.Component<
- Skip To Content
+ {skipButtonText}
;
-function SolutionViewer({ challengeFiles, solution }: Props) {
+function SolutionViewer({ challengeFiles, solution }: Props): JSX.Element {
const isLegacy = !challengeFiles || !challengeFiles.length;
const solutions = isLegacy
? [
diff --git a/client/src/components/app-mount-notifier.test.tsx b/client/src/components/app-mount-notifier.test.tsx
index 78c83e1ba8b7dd..215d99c94c04b9 100644
--- a/client/src/components/app-mount-notifier.test.tsx
+++ b/client/src/components/app-mount-notifier.test.tsx
@@ -5,10 +5,9 @@ import { Provider } from 'react-redux';
import { i18nextCodes } from '../../../config/i18n';
import i18nTestConfig from '../../i18n/config-for-tests';
-import { createStore } from '../redux/createStore';
+import { createStore } from '../redux/create-store';
import AppMountNotifier from './app-mount-notifier';
-jest.mock('react-ga');
jest.unmock('react-i18next');
type Language = keyof typeof i18nextCodes;
diff --git a/client/src/components/formHelpers/__snapshots__/block-save-wrapper.test.tsx.snap b/client/src/components/formHelpers/__snapshots__/block-save-wrapper.test.tsx.snap
deleted file mode 100644
index b088aec7c3c3ee..00000000000000
--- a/client/src/components/formHelpers/__snapshots__/block-save-wrapper.test.tsx.snap
+++ /dev/null
@@ -1,9 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[` snapshot 1`] = `
-
-`;
diff --git a/client/src/components/formHelpers/block-save-button.tsx b/client/src/components/formHelpers/block-save-button.tsx
deleted file mode 100644
index 2adad66ffd39c1..00000000000000
--- a/client/src/components/formHelpers/block-save-button.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import { Button } from '@freecodecamp/react-bootstrap';
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-
-function BlockSaveButton(props?: Record): JSX.Element {
- const { t } = useTranslation();
- return (
-
- {props?.children || t('buttons.save')}
-
- );
-}
-
-BlockSaveButton.displayName = 'BlockSaveButton';
-
-export default BlockSaveButton;
diff --git a/client/src/components/formHelpers/block-save-wrapper.test.tsx b/client/src/components/formHelpers/block-save-wrapper.test.tsx
deleted file mode 100644
index 25e9acff3bc76c..00000000000000
--- a/client/src/components/formHelpers/block-save-wrapper.test.tsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import { render } from '@testing-library/react';
-import React from 'react';
-
-import BlockSaveWrapper from './block-save-wrapper';
-
-test(' snapshot', () => {
- const { container } = render( );
-
- expect(container).toMatchSnapshot();
-});
diff --git a/client/src/components/formHelpers/block-save-wrapper.tsx b/client/src/components/formHelpers/block-save-wrapper.tsx
deleted file mode 100644
index 79186be5deb97e..00000000000000
--- a/client/src/components/formHelpers/block-save-wrapper.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import React from 'react';
-
-const style = {
- padding: '0 15px'
-};
-
-function BlockSaveWrapper({
- children
-}: {
- children?: React.ReactElement | null;
-}): JSX.Element {
- return {children}
;
-}
-
-BlockSaveWrapper.displayName = 'BlockSaveWrapper';
-
-export default BlockSaveWrapper;
diff --git a/client/src/components/formHelpers/form-fields.tsx b/client/src/components/formHelpers/form-fields.tsx
index 226367262125b9..7c9b0afec05d3d 100644
--- a/client/src/components/formHelpers/form-fields.tsx
+++ b/client/src/components/formHelpers/form-fields.tsx
@@ -14,7 +14,8 @@ import {
localhostValidator,
composeValidators,
fCCValidator,
- httpValidator
+ httpValidator,
+ pathValidator
} from './form-validators';
import './form-field.css';
@@ -65,7 +66,8 @@ function FormFields(props: FormFieldsProps): JSX.Element {
name === 'githubLink' || isEditorLinkAllowed ? null : editorValidator,
fCCValidator,
httpValidator,
- isLocalLinkAllowed ? null : localhostValidator
+ isLocalLinkAllowed ? null : localhostValidator,
+ pathValidator
)(value);
const message: string = (error ||
validationError ||
@@ -102,8 +104,7 @@ function FormFields(props: FormFieldsProps): JSX.Element {
name in placeholders ? placeholders[name] : '';
const isURL = types[name] === 'url';
return (
-
-
+
{type === 'hidden' ? null : (
{label}
@@ -124,15 +125,13 @@ function FormFields(props: FormFieldsProps): JSX.Element {
value={value as string}
onBlur={() => markAsBlured(i)}
/>
-
- {blured[i] &&
- nullOrWarning(
+ {blured[i] && nullOrWarning(
value as string,
!pristine && error,
isURL,
name
)}
-
+
);
}}
diff --git a/client/src/components/formHelpers/form-validators.tsx b/client/src/components/formHelpers/form-validators.tsx
index 99b6058c8fda0c..96ddef7e96c26f 100644
--- a/client/src/components/formHelpers/form-validators.tsx
+++ b/client/src/components/formHelpers/form-validators.tsx
@@ -9,6 +9,14 @@ const fCCRegex =
const localhostRegex = /localhost:/;
const httpRegex = /http(?!s|([^s]+?localhost))/;
+function isPathRoot(urlString: string): boolean {
+ try {
+ return new URL(urlString).pathname !== '/';
+ } catch {
+ return false;
+ }
+}
+
export const editorValidator = (value: string): React.ReactElement | null =>
editorRegex.test(value) ? validation.editor-url : null;
@@ -23,6 +31,9 @@ export const localhostValidator = (value: string): React.ReactElement | null =>
export const httpValidator = (value: string): React.ReactElement | null =>
httpRegex.test(value) ? validation.http-url : null;
+export const pathValidator = (value: string): React.ReactElement | null =>
+ isPathRoot(value) ? validation.path-url : null;
+
type Validator = (value: string) => React.ReactElement | null;
export function composeValidators(...validators: (Validator | null)[]) {
return (value: string): ReturnType | null =>
diff --git a/client/src/components/formHelpers/form.test.tsx b/client/src/components/formHelpers/form.test.tsx
index 6cd7d7ef5b0d10..abed826ca06851 100644
--- a/client/src/components/formHelpers/form.test.tsx
+++ b/client/src/components/formHelpers/form.test.tsx
@@ -1,9 +1,9 @@
import { render, fireEvent, screen } from '@testing-library/react';
import React from 'react';
-import Form, { FormProps } from './form';
+import { StrictSolutionForm, StrictSolutionFormProps } from './form';
-const defaultTestProps: FormProps = {
+const defaultTestProps: StrictSolutionFormProps = {
buttonText: 'Submit',
formFields: [
{ name: 'name', label: 'name Label' },
@@ -21,7 +21,7 @@ const defaultTestProps: FormProps = {
};
test('should render', () => {
- render();
+ render( );
const nameInput = screen.getByLabelText(/name Label/);
expect(nameInput).not.toBeRequired();
@@ -41,7 +41,7 @@ test('should render with default values', () => {
const nameValue = 'John';
render(
- );
+ render( );
const websiteInput = screen.getByLabelText(/WebSite label/);
fireEvent.change(websiteInput, { target: { value: websiteValue } });
diff --git a/client/src/components/formHelpers/form.tsx b/client/src/components/formHelpers/form.tsx
index 4d20f32b8ad3fa..d99a2b14de813c 100644
--- a/client/src/components/formHelpers/form.tsx
+++ b/client/src/components/formHelpers/form.tsx
@@ -3,6 +3,7 @@ import React, { FormEvent } from 'react';
import { Form } from 'react-final-form';
import normalizeUrl from 'normalize-url';
+import BlockSaveButton from '../helpers/form/block-save-button';
import {
localhostValidator,
editorValidator,
@@ -12,9 +13,6 @@ import {
} from './form-validators';
import FormFields, { FormOptions } from './form-fields';
-import { default as BlockSaveButton } from './block-save-button';
-// import { default as BlockSaveWrapper } from './block-save-wrapper';
-
type URLValues = {
[key: string]: string;
};
@@ -71,27 +69,25 @@ function formatUrlValues(
return validatedValues;
}
-export type FormProps = {
+export type StrictSolutionFormProps = {
buttonText?: string;
enableSubmit?: boolean;
formFields: { name: string; label: string }[];
- hideButton?: boolean;
id: string;
initialValues?: Record;
options: FormOptions;
submit: (values: ValidatedValues, ...args: unknown[]) => void;
};
-function DynamicForm({
+export const StrictSolutionForm = ({
id,
formFields,
initialValues,
options,
submit,
buttonText,
- enableSubmit,
- hideButton
-}: FormProps): JSX.Element {
+ enableSubmit
+}: StrictSolutionFormProps): JSX.Element => {
return (
)}
);
-}
-
-DynamicForm.displayName = 'DynamicForm';
-
-export default DynamicForm;
+};
diff --git a/client/src/components/formHelpers/index.tsx b/client/src/components/formHelpers/index.tsx
deleted file mode 100644
index d1f6f04d5e854b..00000000000000
--- a/client/src/components/formHelpers/index.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import { default as Form, ValidatedValues } from './form';
-
-export { default as BlockSaveButton } from './block-save-button';
-export { default as BlockSaveWrapper } from './block-save-wrapper';
-export { Form, ValidatedValues };
diff --git a/client/src/components/helpers/__snapshots__/loader.test.tsx.snap b/client/src/components/helpers/__snapshots__/loader.test.tsx.snap
index 6dab24a5651529..d754d42ea6762d 100644
--- a/client/src/components/helpers/__snapshots__/loader.test.tsx.snap
+++ b/client/src/components/helpers/__snapshots__/loader.test.tsx.snap
@@ -14,6 +14,12 @@ exports[` matches the fullScreen render snapshot 1`] = `
+
+
+ misc.slow-load-msg
+
`;
diff --git a/client/src/components/formHelpers/__snapshots__/block-save-button.test.tsx.snap b/client/src/components/helpers/form/__snapshots__/block-save-button.test.tsx.snap
similarity index 100%
rename from client/src/components/formHelpers/__snapshots__/block-save-button.test.tsx.snap
rename to client/src/components/helpers/form/__snapshots__/block-save-button.test.tsx.snap
diff --git a/client/src/components/formHelpers/block-save-button.test.tsx b/client/src/components/helpers/form/block-save-button.test.tsx
similarity index 100%
rename from client/src/components/formHelpers/block-save-button.test.tsx
rename to client/src/components/helpers/form/block-save-button.test.tsx
diff --git a/client/src/components/helpers/form/block-save-button.tsx b/client/src/components/helpers/form/block-save-button.tsx
index fc26e84fbd8f89..901ff0fcf57427 100644
--- a/client/src/components/helpers/form/block-save-button.tsx
+++ b/client/src/components/helpers/form/block-save-button.tsx
@@ -4,17 +4,20 @@ import { useTranslation } from 'react-i18next';
function BlockSaveButton({
children,
+ bgSize,
...restProps
}: {
children?: React.ReactNode;
disabled?: boolean;
+ bgSize?: string;
}): JSX.Element {
const { t } = useTranslation();
return (
-
- {children}
-
-
- );
}
+const FullWidthRow = ({
+ children,
+ className
+}: FullWidthRowProps): JSX.Element => (
+
+
+ {children}
+
+
+);
+
FullWidthRow.displayName = 'FullWidthRow';
export default FullWidthRow;
diff --git a/client/src/components/helpers/image-loader.tsx b/client/src/components/helpers/image-loader.tsx
deleted file mode 100644
index 8010f7f5456dc5..00000000000000
--- a/client/src/components/helpers/image-loader.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import React, { useState } from 'react';
-
-import './image-loader.css';
-import LazyLoad from 'react-lazy-load';
-
-interface ImageLoaderProps {
- alt?: string;
- className?: string;
- height?: number;
- loadedClassName?: string;
- loadingClassName?: string;
- offsetVertical?: number;
- src?: string;
- style?: React.CSSProperties;
- width?: number;
-}
-
-const ImageLoader = ({
- className = '',
- loadedClassName = 'img-loaded',
- loadingClassName = 'img-loading',
- offsetVertical = 100,
- alt,
- src,
- style,
- width,
- height
-}: ImageLoaderProps): JSX.Element => {
- const [loaded, setLoaded] = useState(false);
- const fullClassName = `${className} ${
- loaded ? loadedClassName : loadingClassName
- }`;
- return (
-
- {/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */}
- setLoaded(true)}
- src={src}
- style={style}
- />
-
- );
-};
-
-export default ImageLoader;
diff --git a/client/src/components/helpers/index.ts b/client/src/components/helpers/index.ts
index d58dd56ae09d7f..a72b27175816cb 100644
--- a/client/src/components/helpers/index.ts
+++ b/client/src/components/helpers/index.ts
@@ -5,5 +5,5 @@ export { default as Loader } from './loader';
export { default as SkeletonSprite } from './skeleton-sprite';
export { default as Spacer } from './spacer';
export { default as Link } from './link';
-export { default as ImageLoader } from './image-loader';
+export { default as LazyImage } from './lazy-image';
export { default as AvatarRenderer } from './avatar-renderer';
diff --git a/client/src/components/helpers/lazy-image.tsx b/client/src/components/helpers/lazy-image.tsx
new file mode 100644
index 00000000000000..75a3555ea97f15
--- /dev/null
+++ b/client/src/components/helpers/lazy-image.tsx
@@ -0,0 +1,41 @@
+import React, { useState } from 'react';
+
+import './image-loader.css';
+
+interface LazyImageProps {
+ alt?: string;
+ className?: string;
+ height?: number;
+ loadedClassName?: string;
+ loadingClassName?: string;
+ offsetVertical?: number;
+ src?: string;
+ style?: React.CSSProperties;
+ width?: number;
+}
+
+const LazyImage = ({
+ className = '',
+ loadedClassName = 'img-loaded',
+ loadingClassName = 'img-loading',
+ alt,
+ src,
+ style
+}: LazyImageProps): JSX.Element => {
+ const [loaded, setLoaded] = useState(false);
+ const fullClassName = `${className} ${
+ loaded ? loadedClassName : loadingClassName
+ }`;
+ return (
+ setLoaded(true)}
+ src={src}
+ style={style}
+ loading='lazy'
+ />
+ );
+};
+
+export default LazyImage;
diff --git a/client/src/components/helpers/loader.css b/client/src/components/helpers/loader.css
index 5acf705bd858ab..2182772d777226 100644
--- a/client/src/components/helpers/loader.css
+++ b/client/src/components/helpers/loader.css
@@ -2,8 +2,10 @@
height: 100%;
width: 100%;
display: flex;
+ flex-direction: column;
justify-content: center;
align-items: center;
+ gap: 1em;
}
.fcc-loader .sk-spinner,
diff --git a/client/src/components/helpers/loader.tsx b/client/src/components/helpers/loader.tsx
index 9e5aa9b2aa4c73..dd265c19e56f8f 100644
--- a/client/src/components/helpers/loader.tsx
+++ b/client/src/components/helpers/loader.tsx
@@ -1,27 +1,49 @@
import React, { useState, useEffect } from 'react';
+import { useTranslation } from 'react-i18next';
import Spinner from 'react-spinkit';
import './loader.css';
interface LoaderProps {
fullScreen?: boolean;
- timeout?: number;
+ loaderDelay?: number;
+ messageDelay?: number;
}
-function Loader({ fullScreen, timeout }: LoaderProps): JSX.Element {
- const [showSpinner, setShowSpinner] = useState(!timeout);
+function Loader({
+ fullScreen,
+ loaderDelay,
+ messageDelay
+}: LoaderProps): JSX.Element {
+ const { t } = useTranslation();
+
+ const [showSpinner, setShowSpinner] = useState(!loaderDelay);
+ const [showMessage, setShowMessage] = useState(!messageDelay);
useEffect(() => {
- let timerId: ReturnType;
- if (!showSpinner) {
- timerId = setTimeout(() => setShowSpinner(true), timeout);
+ if (loaderDelay) {
+ const timerId = setTimeout(() => setShowSpinner(true), loaderDelay);
+ return () => clearTimeout(timerId);
}
- return () => clearTimeout(timerId);
- }, [setShowSpinner, showSpinner, timeout]);
+ }, [loaderDelay]);
+
+ useEffect(() => {
+ if (messageDelay) {
+ const timerId = setTimeout(() => setShowMessage(true), messageDelay);
+ return () => clearTimeout(timerId);
+ }
+ }, [messageDelay]);
+
return (
{showSpinner &&
}
+ {showMessage && fullScreen && (
+ <>
+
+
{t('misc.slow-load-msg')}
+ >
+ )}
);
}
diff --git a/client/src/components/helpers/spacer.tsx b/client/src/components/helpers/spacer.tsx
index a56fb39d9f465d..d63c689fa53b23 100644
--- a/client/src/components/helpers/spacer.tsx
+++ b/client/src/components/helpers/spacer.tsx
@@ -6,9 +6,7 @@ interface SpacerProps {
const styles = { padding: '15px 0', height: '1px' };
-const Comp = ({ ...props }): JSX.Element => (
-
-);
+const Comp = ({ ...props }): JSX.Element =>
;
const Spacer = ({ size = 1 }: SpacerProps): JSX.Element =>
size === 1 ? (
diff --git a/client/src/components/helpers/toggle-button.css b/client/src/components/helpers/toggle-button.css
index cfb9d02cd56d7f..512b308090fec7 100644
--- a/client/src/components/helpers/toggle-button.css
+++ b/client/src/components/helpers/toggle-button.css
@@ -4,6 +4,26 @@
opacity: 1;
}
+:is(
+ .about-settings,
+ .privacy-settings,
+ .email-settings,
+ #usernameSettings,
+ #camper-identity,
+ #internet-presence,
+ #portfolio-items,
+ #honesty-policy
+ )
+ :is(
+ button[aria-disabled='true'],
+ button[aria-disabled='true']:is(:focus, :hover)
+ ) {
+ background-color: var(--quaternary-background);
+ color: var(--secondary-color);
+ opacity: 0.65;
+ cursor: not-allowed;
+}
+
.toggle-not-active {
background-color: var(--quaternary-background);
color: var(--secondary-color);
@@ -20,8 +40,8 @@
.btn-group .btn.toggle-not-active,
.btn-group .btn.toggle-active {
border-color: var(--tertiary-color);
- padding-left: 30px;
- padding-right: 30px;
+ padding-inline: 30px;
+ display: flex;
}
.btn-group .btn-primary,
@@ -29,44 +49,3 @@
.btn-group .btn-primary:hover {
border-color: var(--secondary-color);
}
-
-.btn.toggle-active > .tick,
-.btn.toggle-not-active > .tick {
- position: absolute;
-}
-
-.btn:first-child > .tick {
- left: 9px;
- top: calc(50% - 8pt);
-}
-
-.btn:last-child > .tick {
- right: 6px;
- top: calc(50% - 8pt);
-}
-
-.btn-group .btn + .btn {
- margin-left: -2px;
-}
-
-label.toggle-label {
- display: flex;
- flex-direction: column;
-}
-
-@media (max-width: 550px) {
- .btn:first-child > .tick {
- left: 6px;
- }
-
- .btn:last-child > .tick {
- right: 5px;
- }
-}
-
-@media (max-width: 440px) {
- .btn:first-child > .tick {
- left: auto;
- right: 5px;
- }
-}
diff --git a/client/src/components/landing/components/campers-image.tsx b/client/src/components/landing/components/campers-image.tsx
index fe94b118c0f586..e112bd2936f8be 100644
--- a/client/src/components/landing/components/campers-image.tsx
+++ b/client/src/components/landing/components/campers-image.tsx
@@ -2,7 +2,7 @@ import React from 'react';
import { useTranslation } from 'react-i18next';
import Media from 'react-responsive';
import wideImg from '../../../assets/images/landing/wide-image.png';
-import { Spacer, ImageLoader } from '../../helpers';
+import { LazyImage } from '../../helpers';
const LARGE_SCREEN_SIZE = 1200;
@@ -11,33 +11,32 @@ interface CampersImageProps {
}
const donateImageSize = {
- spacerSize: 0,
height: 345,
width: 585
};
const landingImageSize = {
- spacerSize: 2,
+ marginTop: '60px',
height: 442,
width: 750
};
function CampersImage({ pageName }: CampersImageProps): JSX.Element {
const { t } = useTranslation();
- const { spacerSize, height, width } =
- pageName === 'donate' ? donateImageSize : landingImageSize;
+ const figureSize = pageName === 'donate' ? donateImageSize : landingImageSize;
return (
-
-
- {t('landing.hero-img-description')}
+
+
+
+ {t('landing.hero-img-description')}
+
+
);
}
diff --git a/client/src/components/landing/components/testimonials.tsx b/client/src/components/landing/components/testimonials.tsx
index 01cdbfbf614a7c..bcf7294219bdd8 100644
--- a/client/src/components/landing/components/testimonials.tsx
+++ b/client/src/components/landing/components/testimonials.tsx
@@ -4,7 +4,7 @@ import { Trans, useTranslation } from 'react-i18next';
import emmaImg from '../../../assets/images/landing/Emma.png';
import sarahImg from '../../../assets/images/landing/Sarah.png';
import shawnImg from '../../../assets/images/landing/Shawn.png';
-import { ImageLoader } from '../../helpers';
+import { LazyImage } from '../../helpers';
const Testimonials = (): JSX.Element => {
const { t } = useTranslation();
@@ -17,7 +17,7 @@ const Testimonials = (): JSX.Element => {
-
{
-
{
-
void;
fetchUser: () => void;
isSignedIn?: boolean;
pathname: string;
@@ -18,18 +17,15 @@ const mapStateToProps = createSelector(isSignedInSelector, isSignedIn => ({
isSignedIn
}));
-const mapDispatchToProps = { fetchUser, executeGA };
+const mapDispatchToProps = { fetchUser };
class CertificationLayout extends Component {
static displayName = 'CertificationLayout';
componentDidMount() {
- const { isSignedIn, fetchUser, pathname } = this.props;
+ const { isSignedIn, fetchUser } = this.props;
if (!isSignedIn) {
fetchUser();
}
- if (this.props.executeGA) {
- this.props.executeGA({ type: 'page', data: pathname });
- }
}
render(): JSX.Element {
diff --git a/client/src/components/layouts/default.tsx b/client/src/components/layouts/default.tsx
index f0e7b4ec673861..ca3c5c37094318 100644
--- a/client/src/components/layouts/default.tsx
+++ b/client/src/components/layouts/default.tsx
@@ -1,9 +1,10 @@
-import React, { Component, ReactNode } from 'react';
+import React, { ReactNode, useEffect } from 'react';
import Helmet from 'react-helmet';
import { TFunction, withTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import { bindActionCreators, Dispatch } from 'redux';
import { createSelector } from 'reselect';
+import { useStaticQuery, graphql } from 'gatsby';
import latoBoldURL from '../../../static/fonts/lato/Lato-Bold.woff';
import latoLightURL from '../../../static/fonts/lato/Lato-Light.woff';
@@ -17,16 +18,23 @@ import {
fetchUser,
onlineStatusChange,
serverStatusChange,
- executeGA
+ updateAllChallengesInfo
} from '../../redux/actions';
import {
isSignedInSelector,
userSelector,
isOnlineSelector,
isServerOnlineSelector,
+ showCodeAllySelector,
userFetchStateSelector
} from '../../redux/selectors';
-import { UserFetchState, User } from '../../redux/prop-types';
+
+import {
+ UserFetchState,
+ User,
+ AllChallengeNode,
+ CertificateNode
+} from '../../redux/prop-types';
import BreadCrumb from '../../templates/Challenges/components/bread-crumb';
import Flash from '../Flash';
import { flashMessageSelector, removeFlashMessage } from '../Flash/redux';
@@ -34,11 +42,14 @@ import SignoutModal from '../signout-modal';
import Footer from '../Footer';
import Header from '../Header';
import OfflineWarning from '../OfflineWarning';
+import { Loader } from '../helpers';
// preload common fonts
import './fonts.css';
import './global.css';
import './variables.css';
+import './rtl-layout.css';
+import { Themes } from '../settings/theme';
const mapStateToProps = createSelector(
isSignedInSelector,
@@ -46,6 +57,7 @@ const mapStateToProps = createSelector(
isOnlineSelector,
isServerOnlineSelector,
userFetchStateSelector,
+ showCodeAllySelector,
userSelector,
(
isSignedIn,
@@ -53,6 +65,7 @@ const mapStateToProps = createSelector(
isOnline: boolean,
isServerOnline: boolean,
fetchState: UserFetchState,
+ showCodeAlly: boolean,
user: User
) => ({
isSignedIn,
@@ -62,6 +75,7 @@ const mapStateToProps = createSelector(
isServerOnline,
fetchState,
theme: user.theme,
+ showCodeAlly,
user
})
);
@@ -75,7 +89,7 @@ const mapDispatchToProps = (dispatch: Dispatch) =>
removeFlashMessage,
onlineStatusChange,
serverStatusChange,
- executeGA
+ updateAllChallengesInfo
},
dispatch
);
@@ -88,72 +102,74 @@ interface DefaultLayoutProps extends StateProps, DispatchProps {
showFooter?: boolean;
isChallenge?: boolean;
block?: string;
+ showCodeAlly: boolean;
superBlock?: string;
t: TFunction;
- useTheme?: boolean;
}
-class DefaultLayout extends Component {
- static displayName = 'DefaultLayout';
+const getSystemTheme = () =>
+ `${
+ window.matchMedia('(prefers-color-scheme: dark)').matches === true
+ ? 'dark-palette'
+ : 'light-palette'
+ }`;
- componentDidMount() {
- const { isSignedIn, fetchUser, pathname, executeGA } = this.props;
+function DefaultLayout({
+ children,
+ hasMessage,
+ fetchState,
+ flashMessage,
+ isOnline,
+ isServerOnline,
+ isSignedIn,
+ removeFlashMessage,
+ showFooter = true,
+ isChallenge = false,
+ block,
+ superBlock,
+ t,
+ theme = Themes.Default,
+ showCodeAlly,
+ user,
+ fetchUser,
+ updateAllChallengesInfo
+}: DefaultLayoutProps): JSX.Element {
+ const { challengeEdges, certificateNodes } = useGetAllBlockIds();
+ useEffect(() => {
+ // componentDidMount
+ updateAllChallengesInfo({ challengeEdges, certificateNodes });
if (!isSignedIn) {
fetchUser();
}
- executeGA({ type: 'page', data: pathname });
-
- window.addEventListener('online', this.updateOnlineStatus);
- window.addEventListener('offline', this.updateOnlineStatus);
- }
+ window.addEventListener('online', updateOnlineStatus);
+ window.addEventListener('offline', updateOnlineStatus);
- componentDidUpdate(prevProps: DefaultLayoutProps) {
- const { pathname, executeGA } = this.props;
- const { pathname: prevPathname } = prevProps;
- if (pathname !== prevPathname) {
- executeGA({ type: 'page', data: pathname });
- }
- }
+ return () => {
+ // componentWillUnmount.
+ window.removeEventListener('online', updateOnlineStatus);
+ window.removeEventListener('offline', updateOnlineStatus);
+ };
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
- componentWillUnmount() {
- window.removeEventListener('online', this.updateOnlineStatus);
- window.removeEventListener('offline', this.updateOnlineStatus);
- }
-
- updateOnlineStatus = () => {
- const { onlineStatusChange } = this.props;
+ const updateOnlineStatus = () => {
const isOnline =
isBrowser() && 'navigator' in window ? window.navigator.onLine : null;
return typeof isOnline === 'boolean' ? onlineStatusChange(isOnline) : null;
};
- render() {
- const {
- children,
- hasMessage,
- fetchState,
- flashMessage,
- isOnline,
- isServerOnline,
- isSignedIn,
- removeFlashMessage,
- showFooter = true,
- isChallenge = false,
- block,
- superBlock,
- t,
- theme = 'default',
- user,
- useTheme = true
- } = this.props;
+ const useSystemTheme = fetchState.complete && isSignedIn === false;
+ if (fetchState.pending) {
+ return ;
+ } else {
return (
{
/>
-
+
{
/>
) : null}
- {isChallenge && (
+ {isChallenge && !showCodeAlly && (
{
}
}
+// TODO: get challenge nodes directly rather than wrapped in edges
+const useGetAllBlockIds = () => {
+ const {
+ allChallengeNode: { edges: challengeEdges },
+ allCertificateNode: { nodes: certificateNodes }
+ }: {
+ allChallengeNode: AllChallengeNode;
+ allCertificateNode: { nodes: CertificateNode[] };
+ } = useStaticQuery(graphql`
+ query getBlockNode {
+ allChallengeNode(
+ sort: {
+ fields: [
+ challenge___superOrder
+ challenge___order
+ challenge___challengeOrder
+ ]
+ }
+ ) {
+ edges {
+ node {
+ challenge {
+ block
+ id
+ }
+ }
+ }
+ }
+ allCertificateNode {
+ nodes {
+ challenge {
+ certification
+ tests {
+ id
+ }
+ }
+ }
+ }
+ }
+ `);
+
+ return { challengeEdges, certificateNodes };
+};
+
+DefaultLayout.displayName = 'DefaultLayout';
+
export default connect(
mapStateToProps,
mapDispatchToProps
diff --git a/client/src/components/layouts/fonts.css b/client/src/components/layouts/fonts.css
index e2df93ea561307..b1d689eb76978a 100644
--- a/client/src/components/layouts/fonts.css
+++ b/client/src/components/layouts/fonts.css
@@ -38,6 +38,44 @@
font-display: fallback;
}
+/* NotoSansArabic */
+
+@font-face {
+ font-family: 'NotoSansArabic';
+ src: url('../../../static/fonts/noto-sans-arabic/NotoSansArabic-Light.woff')
+ format('woff');
+ font-weight: 300;
+ font-style: normal;
+ font-display: fallback;
+}
+
+@font-face {
+ font-family: 'NotoSansArabic';
+ src: url('../../../static/fonts/noto-sans-arabic/NotoSansArabic-Regular.woff')
+ format('woff');
+ font-weight: normal;
+ font-style: normal;
+ font-display: fallback;
+}
+
+@font-face {
+ font-family: 'NotoSansArabic';
+ src: url('../../../static/fonts/noto-sans-arabic/NotoSansArabic-Bold.woff')
+ format('woff');
+ font-weight: bold;
+ font-style: normal;
+ font-display: fallback;
+}
+
+@font-face {
+ font-family: 'NotoSansArabic';
+ src: url('../../../static/fonts/noto-sans-arabic/NotoSansArabic-Black.woff')
+ format('woff');
+ font-weight: 900;
+ font-style: normal;
+ font-display: fallback;
+}
+
/* hack zeroslash */
@font-face {
diff --git a/client/src/components/layouts/global.css b/client/src/components/layouts/global.css
index 7b245fc660df5c..6b990c7137c9c6 100644
--- a/client/src/components/layouts/global.css
+++ b/client/src/components/layouts/global.css
@@ -49,8 +49,7 @@ body {
for those pages.
*/
.overflow-fix {
- margin-right: 0;
- margin-left: 0;
+ margin-inline: 0;
}
.default-layout {
@@ -436,7 +435,7 @@ fieldset[disabled] .btn-primary.focus {
height: 100%;
min-height: 20px;
min-width: 16px;
- margin-left: 5px;
+ margin-inline-start: 5px;
}
.link-btn:active {
@@ -603,10 +602,6 @@ hr {
margin: 32px 0;
}
-.panel-default {
- background: var(--secondary-background);
-}
-
.btn-primary:active,
.btn-primary.active,
.open > .dropdown-toggle.btn-primary,
@@ -623,6 +618,11 @@ hr {
background-color: var(--secondary-color);
}
+.dropdown,
+.dropdown > .dropdown-menu {
+ width: 100%;
+}
+
.dropdown-menu > li > a {
color: var(--secondary-background);
}
@@ -711,10 +711,6 @@ pre {
margin-bottom: 0;
}
-.solution-viewer {
- border-color: var(--primary-color);
-}
-
.has-success .help-block,
.has-success .control-label,
.has-success .radio,
@@ -792,6 +788,10 @@ blockquote .small {
border-color: #31708f;
}
+.alert-dismissable .close {
+ top: 0;
+}
+
.annual-donation-alert {
background: linear-gradient(
-10deg,
diff --git a/client/src/components/layouts/rtl-layout.css b/client/src/components/layouts/rtl-layout.css
new file mode 100644
index 00000000000000..89d5ee6fbdf605
--- /dev/null
+++ b/client/src/components/layouts/rtl-layout.css
@@ -0,0 +1,182 @@
+/*
+Increase the spacing in paragraphs
+*/
+
+[dir='rtl'] p {
+ line-height: 2rem;
+}
+
+/*
+Intro project buttons and headings
+*/
+
+[dir='rtl'] .monaco-editor-tabs {
+ /* need to remove the margin because the editor is reversed */
+ margin-inline-end: 0;
+}
+
+[dir='rtl'] .map-ui .superblock-link > svg {
+ transform: rotate(180deg);
+}
+
+/*
+ intro to courses section
+*/
+
+[dir='rtl'] .link-btn.btn-lg > svg {
+ transform: rotate(180deg);
+}
+
+/*
+this is used to rotate arrow mark in certification block and donation
+the "not" and "is" selector is used to stop it from affecting other section and pages
+*/
+
+/* arrow icon */
+[dir='rtl']
+ :is(.block:is(:not(.open)), .faq-item:is(:not(.open)))
+ .map-title:not(.title-wrapper, .block-header-button-text)
+ > svg:first-child {
+ transform: rotate(180deg);
+}
+
+/*
+external fontawesome link icon
+*/
+
+[dir='rtl'] .nav-link > .fa-up-right-from-square,
+[dir='rtl'] td a[target='_blank'] > svg {
+ transform: rotate(270deg);
+}
+
+/*
+universal-nav-bar
+and menu secion
+*/
+
+@media (min-width: 601px) {
+ [dir='rtl'] .nav-list {
+ right: auto;
+ left: 0;
+ }
+}
+
+@media (max-width: 980px) {
+ [dir='rtl'] #universal-nav-logo {
+ left: inherit;
+ right: 17px;
+ }
+
+ [dir='rtl'] .fcc_searchBar .ais-Hits {
+ left: auto;
+ right: 15px;
+ }
+
+ [dir='rtl'] .universal-nav-right .fcc_searchBar {
+ left: auto;
+ right: 0;
+ }
+}
+
+/* had to change overflow, because it clips the first words of the english articles */
+[dir='rtl'] .footer-container {
+ overflow-x: inherit;
+}
+
+/*
+dropdown links
+*/
+
+[dir='rtl'] .dropdown-menu {
+ text-decoration-skip-ink: all;
+}
+
+/*
+New RWD project challenge
+*/
+
+[dir='rtl'] .tabs-row {
+ gap: 10px;
+}
+
+[dir='rtl'] .monaco-editor-tabs button:not(:first-child) {
+ border-left: 2px solid;
+ border-right: none;
+}
+
+/* Align the the Arabic head with the corresponding English word */
+
+[dir='rtl'] .table thead:first-child tr:first-child th {
+ text-align: right;
+}
+
+/*
+sections that need to stay left to right
+*/
+
+/* special cases in steps */
+[dir='rtl'] :has(#learn-app-wrapper) table,
+[dir='rtl'] :has(#learn-app-wrapper) pre,
+/* Code snippet*/
+[dir='rtl'] code,
+/* trending articles */
+[dir='rtl'] .trending-guides .trending-guides-row div a,
+[dir='rtl'] .overflow-guard,
+[dir='rtl'] .challenge-preview,
+/* timeline*/
+[dir='rtl'] .timeline-pagination_list {
+ direction: ltr;
+}
+
+[dir='rtl'] code {
+ word-break: normal;
+ unicode-bidi: isolate;
+}
+
+/* bootstrap display block breaks the code elements when they are stacked on top of each other to sort this, we remove it for display: grid */
+
+[dir='rtl'] pre[class*='language-']:has(code) {
+ display: grid;
+}
+
+[dir='rtl'] .description-container,
+[dir='rtl'] .action-row-container,
+[dir='rtl']
+ .timeline-pagination_list
+ .timeline-pagination_list_item:not(:has(button)) {
+ direction: rtl;
+}
+
+/* Revert the editor layout to account for reverted splitter */
+
+[dir='rtl'] .desktop-layout .tabs-row,
+[dir='rtl'] .desktop-layout .reflex-container:not(.horizontal) {
+ flex-direction: row-reverse;
+}
+
+/* new Font Family because 'Hack-ZeroSlash' add letter spacing in Arabic letter which is extermely bad */
+
+[dir='rtl'] body,
+[dir='rtl'] .signup-btn,
+[dir='rtl'] h1,
+[dir='rtl'] h2,
+[dir='rtl'] h3,
+[dir='rtl'] h4,
+[dir='rtl'] h5,
+[dir='rtl'] h6,
+[dir='rtl'] p,
+[dir='rtl'] td,
+[dir='rtl'] th,
+[dir='rtl'] .donate-page-wrapper,
+[dir='rtl'] .donate-page-wrapper b,
+[dir='rtl'] .donate-page-wrapper h3,
+[dir='rtl'] .donate-page-wrapper p,
+[dir='rtl'] [name='payment-method'] {
+ font-family: 'NotoSansArabic';
+}
+
+@media (min-width: 980px) {
+ [dir='rtl'] .donate-page-wrapper > .row {
+ display: flex;
+ }
+}
diff --git a/client/src/components/profile/__snapshots__/profile.test.tsx.snap b/client/src/components/profile/__snapshots__/profile.test.tsx.snap
index bcb90fcb3d525f..72486eec310111 100644
--- a/client/src/components/profile/__snapshots__/profile.test.tsx.snap
+++ b/client/src/components/profile/__snapshots__/profile.test.tsx.snap
@@ -3,14 +3,12 @@
exports[` renders correctly 1`] = `
@@ -232,7 +230,7 @@ exports[`
renders correctly 1`] = `
xmlns="http://www.w3.org/2000/svg"
>
@@ -275,7 +273,6 @@ exports[`
renders correctly 1`] = `
renders correctly 1`] = `
diff --git a/client/src/components/profile/components/__snapshots__/timeline-buttons.test.js.snap b/client/src/components/profile/components/__snapshots__/timeline-buttons.test.js.snap
new file mode 100644
index 00000000000000..5aa81e4dab2706
--- /dev/null
+++ b/client/src/components/profile/components/__snapshots__/timeline-buttons.test.js.snap
@@ -0,0 +1,447 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should check certification page consistency 1`] = `
+
+
+
+ profile.timeline
+
+
+
+
+
+ profile.challenge
+
+
+ settings.labels.solution
+
+
+ profile.completed
+
+
+
+
+
+
+
+ Learn Accessibility by Building a Quiz - Step 41
+
+
+
+
+
+ Dec 29, 2022
+
+
+
+
+
+
+ Build a Number Guessing Game
+
+
+
+
+
+ Dec 29, 2022
+
+
+
+
+
+
+ Build a Periodic Table Database
+
+
+
+
+
+ Dec 29, 2022
+
+
+
+
+
+
+ Build an SQL Reference Object
+
+
+
+
+
+ Dec 29, 2022
+
+
+
+
+
+
+ Build a Castle
+
+
+
+
+
+ Dec 29, 2022
+
+
+
+
+
+
+ Build a Salon Appointment Scheduler
+
+
+
+
+
+ Dec 29, 2022
+
+
+
+
+
+
+ Build a Bike Rental Shop
+
+
+
+
+
+ Dec 29, 2022
+
+
+
+
+
+
+ Build a Kitty Ipsum Translator
+
+
+
+
+
+ Dec 29, 2022
+
+
+
+
+
+
+ Build a World Cup Database
+
+
+
+
+
+ Dec 29, 2022
+
+
+
+
+
+
+ Build a Student Database: Part 2
+
+
+
+
+
+ Dec 29, 2022
+
+
+
+
+
+
+ Build a Student Database: Part 1
+
+
+
+
+
+ Dec 29, 2022
+
+
+
+
+
+
+ Build Five Programs
+
+
+
+
+
+ Dec 29, 2022
+
+
+
+
+
+
+ Build a Celestial Bodies Database
+
+
+
+
+
+ Dec 29, 2022
+
+
+
+
+
+
+ Build a Mario Database
+
+
+
+
+
+ Dec 29, 2022
+
+
+
+
+
+
+ Build a Boilerplate
+
+
+
+
+
+ Dec 29, 2022
+
+
+
+
+
+
+
+
+
+ <<
+
+
+
+
+ <
+
+
+
+ profile.page-number
+
+
+
+ >
+
+
+
+
+ >>
+
+
+
+
+
+
+`;
diff --git a/client/src/components/profile/components/certifications.tsx b/client/src/components/profile/components/certifications.tsx
index 0fe7ddef26cfd7..2f92efa040469b 100644
--- a/client/src/components/profile/components/certifications.tsx
+++ b/client/src/components/profile/components/certifications.tsx
@@ -1,5 +1,4 @@
import { Col, Row } from '@freecodecamp/react-bootstrap';
-import { curry } from 'lodash-es';
import React, { Fragment } from 'react';
import { useTranslation } from 'react-i18next';
import { connect } from 'react-redux';
@@ -40,9 +39,15 @@ interface CertificationProps {
username: string;
}
-function renderCertShow(username: string, cert: CurrentCert): React.ReactNode {
- return cert.show ? (
-
+interface CertButtonProps {
+ cert: CurrentCert;
+ username: string;
+}
+
+function CertButton({ username, cert }: CertButtonProps): JSX.Element {
+ const { t } = useTranslation();
+ return (
+ <>
- View {cert.title}
+ {t('buttons.view-cert-title', {
+ certTitle: t(`certification.title.${cert.certSlug}`)
+ })}
-
- ) : null;
+ >
+ );
}
function Certificates({
@@ -67,13 +74,16 @@ function Certificates({
username
}: CertificationProps): JSX.Element {
const { t } = useTranslation();
- const renderCertShowWithUsername = curry(renderCertShow)(username);
return (
{t('profile.fcc-certs')}
{hasModernCert && currentCerts ? (
- currentCerts.map(renderCertShowWithUsername)
+ currentCerts
+ .filter(({ show }) => show)
+ .map(cert => (
+
+ ))
) : (
{t('profile.no-certs')}
)}
@@ -82,7 +92,16 @@ function Certificates({
{t('settings.headings.legacy-certs')}
- {legacyCerts && legacyCerts.map(renderCertShowWithUsername)}
+ {legacyCerts &&
+ legacyCerts
+ .filter(({ show }) => show)
+ .map(cert => (
+
+ ))}
) : null}
diff --git a/client/src/components/profile/components/portfolio.css b/client/src/components/profile/components/portfolio.css
index 86b3a30871d175..14f2b245488e13 100644
--- a/client/src/components/profile/components/portfolio.css
+++ b/client/src/components/profile/components/portfolio.css
@@ -1,10 +1,113 @@
-.portfolio-heading.media-heading {
- border-bottom: 1px solid var(--quaternary-background);
- padding-bottom: 10px;
+.portfolio-container {
+ display: grid;
+ position: relative;
+ border: 1px solid var(--secondary-color);
+ gap: 1rem 1rem;
+ grid-template-columns: repeat(3, 1fr);
+ margin-top: 1em;
+ margin-bottom: 3em;
}
+
.portfolio-screen-shot {
- width: 150px;
- min-width: 150px;
+ display: block;
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ grid-column: 1/-1;
+ grid-row: 1;
+}
+
+.portfolio-container h3 {
+ grid-column: 1/ -1;
+ grid-row: 2;
+ margin-block: 1em;
+}
+
+#link-icon {
+ margin-inline-start: 1em;
+}
+
+.portfolio-container a {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ grid-column: 1/ -1;
+ grid-row: 4;
+ font-size: unset;
+ justify-self: end;
+ width: 40%;
+ background-color: var(--primary-color);
+ color: var(--primary-background);
+ padding: 0.5rem;
+ border-radius: 15px;
+ padding-inline: 4rem;
+ margin: 1em;
+ text-decoration: none;
+ /* prevent line breaks in Chinese/Japanese/Korean */
+ word-break: keep-all;
+}
+
+.portfolio-container a::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 1;
+}
+
+.portfolio-container a:is(:hover, :focus, :focus-visible) {
+ outline: 2px solid var(--blue-mid);
+ outline-offset: 2px;
+}
+
+.portfolio-container p {
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+ grid-column: 1/ -1;
+ grid-row: 3;
+}
+
+@media (max-width: 994px) {
+ .portfolio-screen-shot {
+ max-height: 300px;
+ }
+
+ .portfolio-container h3 {
+ margin: 0.5rem;
+ }
+
+ .portfolio-container p {
+ margin: 1rem;
+ }
+}
+
+@media (min-width: 995px) {
+ .portfolio-container {
+ grid-template-rows: minmax(75px, 1fr) minmax(125px, 1fr) 75px;
+ grid-template-columns: 300px 1.2fr;
+ }
+
+ .portfolio-screen-shot {
+ grid-column: 1;
+ grid-row: 1 / -1;
+ }
+
+ .portfolio-container h3 {
+ grid-column: 2;
+ grid-row: 1;
+ }
+
+ .portfolio-container p {
+ grid-column: 2;
+ grid-row: 2;
+ }
+
+ .portfolio-container a {
+ grid-column: 2;
+ grid-row: 3;
+ }
}
/* Timeline pagination */
@@ -34,13 +137,13 @@
}
.timeline-cert-link {
- margin-right: 20px;
+ margin-inline-end: 20px;
}
.timeline-cert-link > svg {
display: inline-block;
height: 25px;
width: auto;
- margin-left: 10px;
+ margin-inline-start: 10px;
position: absolute;
}
diff --git a/client/src/components/profile/components/portfolio.tsx b/client/src/components/profile/components/portfolio.tsx
index 4e361dcadfa57a..f5edd7ae43a6b8 100644
--- a/client/src/components/profile/components/portfolio.tsx
+++ b/client/src/components/profile/components/portfolio.tsx
@@ -1,7 +1,7 @@
-import { Media } from '@freecodecamp/react-bootstrap';
import React from 'react';
import { useTranslation } from 'react-i18next';
-
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faArrowUpRightFromSquare } from '@fortawesome/free-solid-svg-icons';
import type { Portfolio as PortfolioData } from '../../../redux/prop-types';
import { FullWidthRow } from '../../helpers';
@@ -20,25 +20,21 @@ function Portfolio({ portfolio = [] }: PortfolioProps): JSX.Element | null {
{t('profile.portfolio')}
{portfolio.map(({ title, url, image, description, id }) => (
-
-
- {image && (
-
- )}
-
-
-
-
- {title}
-
-
- {description}
-
-
+
))}
diff --git a/client/src/components/profile/components/time-line.test.tsx b/client/src/components/profile/components/time-line.test.tsx
index 6256c9e731425b..2fb3e4c866944e 100644
--- a/client/src/components/profile/components/time-line.test.tsx
+++ b/client/src/components/profile/components/time-line.test.tsx
@@ -4,10 +4,9 @@ import { useStaticQuery } from 'gatsby';
import React from 'react';
import { render, screen } from '../../../../utils/test-utils';
-import { createStore } from '../../../redux/createStore';
+import { createStore } from '../../../redux/create-store';
import TimeLine from './time-line';
-jest.mock('react-ga');
const store = createStore();
beforeEach(() => {
@@ -57,7 +56,9 @@ describe(' ', () => {
it('Render button when only solution is present', () => {
// @ts-expect-error
render( , store);
- const showViewButton = screen.getByRole('link', { name: 'buttons.view' });
+ const showViewButton = screen.getByRole('link', {
+ name: 'buttons.view settings.labels.solution-for (aria.opens-new-window)'
+ });
expect(showViewButton).toHaveAttribute(
'href',
'https://github.com/freeCodeCamp/freeCodeCamp'
@@ -84,7 +85,9 @@ describe(' ', () => {
// @ts-expect-error
render( , store);
- const viewButtons = screen.getAllByRole('button', { name: 'buttons.view' });
+ const viewButtons = screen.getAllByRole('button', {
+ name: 'buttons.view settings.labels.solution-for'
+ });
viewButtons.forEach(button => {
expect(button).toBeInTheDocument();
});
diff --git a/client/src/components/profile/components/time-line.tsx b/client/src/components/profile/components/time-line.tsx
index 3efef9267ccaa7..38f65146227d93 100644
--- a/client/src/components/profile/components/time-line.tsx
+++ b/client/src/components/profile/components/time-line.tsx
@@ -1,6 +1,6 @@
import { Button, Modal, Table } from '@freecodecamp/react-bootstrap';
import Loadable from '@loadable/component';
-import { useStaticQuery, graphql } from 'gatsby';
+import { graphql, useStaticQuery } from 'gatsby';
import { reverse, sortBy } from 'lodash-es';
import React, { useMemo, useState } from 'react';
import { TFunction, withTranslation } from 'react-i18next';
@@ -14,16 +14,14 @@ import {
getTitleFromId
} from '../../../../../utils';
import { regeneratePathAndHistory } from '../../../../../utils/polyvinyl';
-import CertificationIcon from '../../../assets/icons/certification-icon';
+import CertificationIcon from '../../../assets/icons/certification';
import { CompletedChallenge } from '../../../redux/prop-types';
import ProjectPreviewModal from '../../../templates/Challenges/components/project-preview-modal';
import { openModal } from '../../../templates/Challenges/redux/actions';
-import { FullWidthRow, Link } from '../../helpers';
+import { Link, FullWidthRow } from '../../helpers';
import { SolutionDisplayWidget } from '../../solution-display-widget';
import TimelinePagination from './timeline-pagination';
-import './timeline.css';
-
const SolutionViewer = Loadable(
() => import('../../SolutionViewer/SolutionViewer')
);
@@ -105,12 +103,15 @@ function TimelineInner({
function renderViewButton(
completedChallenge: CompletedChallenge
): React.ReactNode {
+ const { id } = completedChallenge;
+ const projectTitle = idToNameMap.get(id)?.challengeTitle || '';
return (
viewSolution(completedChallenge)}
showProjectPreview={() => viewProject(completedChallenge)}
- displayContext={'timeline'}
+ displayContext='timeline'
>
);
}
@@ -164,75 +165,73 @@ function TimelineInner({
const endIndex = pageNo * ITEMS_PER_PAGE;
return (
- <>
-
- {t('profile.timeline')}
- {completedMap.length === 0 ? (
-
- {t('profile.none-completed')}
- {t('profile.get-started')}
-
- ) : (
-
-
-
- {t('profile.challenge')}
- {t('settings.labels.solution')}
- {t('profile.completed')}
-
-
-
- {sortedTimeline.slice(startIndex, endIndex).map(renderCompletion)}
-
-
- )}
- {id && (
-
-
-
- {`${username}'s Solution to ${
- idToNameMap.get(id)?.challengeTitle ?? ''
- }`}
-
-
-
-
-
-
- {t('buttons.close')}
-
-
- )}
- {totalPages > 1 && (
-
- )}
-
+
+ {t('profile.timeline')}
+ {completedMap.length === 0 ? (
+
+ {t('profile.none-completed')}
+ {t('profile.get-started')}
+
+ ) : (
+
+
+
+ {t('profile.challenge')}
+ {t('settings.labels.solution')}
+ {t('profile.completed')}
+
+
+
+ {sortedTimeline.slice(startIndex, endIndex).map(renderCompletion)}
+
+
+ )}
+ {id && (
+
+
+
+ {`${username}'s Solution to ${
+ idToNameMap.get(id)?.challengeTitle ?? ''
+ }`}
+
+
+
+
+
+
+ {t('buttons.close')}
+
+
+ )}
+ {totalPages > 1 && (
+
+ )}
- >
+
);
}
/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call*/
-function useIdToNameMap(): Map {
+function useIdToNameMap(t: TFunction): Map {
const {
allChallengeNode: { edges }
} = useStaticQuery(graphql`
@@ -255,8 +254,12 @@ function useIdToNameMap(): Map {
`);
const idToNameMap = new Map();
for (const id of getCertIds()) {
+ const challengeTitle = getTitleFromId(id);
idToNameMap.set(id, {
- challengeTitle: `${getTitleFromId(id)} Certification`,
+ challengeTitle: `${t(
+ `certification.title.${challengeTitle}`,
+ challengeTitle
+ )} Certification`,
certPath: getPathFromID(id)
});
}
@@ -286,8 +289,8 @@ function useIdToNameMap(): Map {
}
const Timeline = (props: TimelineProps): JSX.Element => {
- const idToNameMap = useIdToNameMap();
- const { completedMap } = props;
+ const { completedMap, t } = props;
+ const idToNameMap = useIdToNameMap(t);
// Get the sorted timeline along with total page count.
const { sortedTimeline, totalPages } = useMemo(() => {
const sortedTimeline = reverse(
diff --git a/client/src/components/profile/components/timeline-buttons.test.js b/client/src/components/profile/components/timeline-buttons.test.js
new file mode 100644
index 00000000000000..6a4b619bb1b458
--- /dev/null
+++ b/client/src/components/profile/components/timeline-buttons.test.js
@@ -0,0 +1,64 @@
+/* eslint-disable @typescript-eslint/no-unused-vars */
+import React from 'react';
+import renderer from 'react-test-renderer';
+import { Provider } from 'react-redux';
+
+import { createStore } from '../../../redux/create-store';
+import completedChallenges from '../../../__mocks__/completed-challenges.json';
+import Timeline from './time-line';
+
+Date.prototype.toLocaleString = jest.fn(() => 'Dec 29, 2022');
+Date.prototype.toISOString = jest.fn(() => '2016-09-28T20:31:56.730Z');
+
+jest.mock('../../../analytics');
+
+jest.mock('gatsby', () => {
+ const edges = require('../../../__mocks__/edges.json');
+ const React = require('react');
+ const gatsby = jest.requireActual('gatsby');
+ return {
+ ...gatsby,
+ useStaticQuery: jest.fn().mockReturnValue({
+ allChallengeNode: {
+ edges: edges
+ }
+ }),
+ graphql: jest.fn(),
+ Link: jest
+ .fn()
+ .mockImplementation(
+ ({
+ activeClassName,
+ activeStyle,
+ getProps,
+ innerRef,
+ partiallyActive,
+ ref,
+ replace,
+ to,
+ ...rest
+ }) =>
+ React.createElement('a', {
+ ...rest,
+ href: to,
+ gatsby: 'true'
+ })
+ )
+ };
+});
+
+it('should check certification page consistency', () => {
+ const tree = renderer
+ .create(
+
+ {}}
+ />
+
+ )
+ .toJSON();
+
+ expect(tree).toMatchSnapshot();
+});
diff --git a/client/src/components/profile/components/timeline.css b/client/src/components/profile/components/timeline.css
deleted file mode 100644
index 475089a5d1c2b9..00000000000000
--- a/client/src/components/profile/components/timeline.css
+++ /dev/null
@@ -1,3 +0,0 @@
-.timeline-row .solutions-dropdown .dropdown {
- width: 100%;
-}
diff --git a/client/src/components/search/searchBar/search-bar-optimized.tsx b/client/src/components/search/searchBar/search-bar-optimized.tsx
index cea824cfec0b98..68be861c9408ca 100644
--- a/client/src/components/search/searchBar/search-bar-optimized.tsx
+++ b/client/src/components/search/searchBar/search-bar-optimized.tsx
@@ -1,6 +1,7 @@
-import React, { useState } from 'react';
+import React, { useState, useRef } from 'react';
import { useTranslation } from 'react-i18next';
-import Magnifier from '../../../assets/icons/Magnifier';
+import Magnifier from '../../../assets/icons/magnifier';
+import InputReset from '../../../assets/icons/input-reset';
import { searchPageUrl } from '../../../utils/algolia-locale-setup';
type Props = {
@@ -12,6 +13,7 @@ const SearchBarOptimized = ({ innerRef }: Props): JSX.Element => {
const placeholder = t('search.placeholder');
const searchUrl = searchPageUrl;
const [value, setValue] = useState('');
+ const inputElementRef = useRef(null);
const onChange = (event: React.ChangeEvent) =>
setValue(event.target.value);
const onSubmit = (event: React.FormEvent) => {
@@ -20,6 +22,10 @@ const SearchBarOptimized = ({ innerRef }: Props): JSX.Element => {
window.open(`${searchUrl}?query=${encodeURIComponent(value)}`, '_blank');
}
};
+ const onClick = () => {
+ setValue('');
+ inputElementRef.current?.focus();
+ };
return (
@@ -32,11 +38,14 @@ const SearchBarOptimized = ({ innerRef }: Props): JSX.Element => {
onSubmit={onSubmit}
role='search'
>
+
+ {t ? t('search.label') : ''}
+
{
spellCheck='false'
type='search'
value={value}
+ ref={inputElementRef}
/>
-
+
+ {value && (
+
+
+
+ )}
diff --git a/client/src/components/search/searchBar/search-bar.tsx b/client/src/components/search/searchBar/search-bar.tsx
index bb614287e74b25..f244b99d8dbe11 100644
--- a/client/src/components/search/searchBar/search-bar.tsx
+++ b/client/src/components/search/searchBar/search-bar.tsx
@@ -187,6 +187,8 @@ export class SearchBar extends Component
{
render(): JSX.Element {
const { isDropdownEnabled, isSearchFocused, innerRef, t } = this.props;
const { index } = this.state;
+ const submitTitle = t ? t('icons.magnifier') : '';
+ const resetTitle = t ? t('icons.input-reset') : '';
const placeholder = t ? t('search.placeholder') : '';
return (
@@ -210,7 +212,11 @@ export class SearchBar extends Component {
this.handleSearch(e);
}}
showLoadingIndicator={false}
- translations={{ placeholder }}
+ translations={{
+ submitTitle: submitTitle,
+ resetTitle: resetTitle,
+ placeholder: placeholder
+ }}
/>
diff --git a/client/src/components/search/searchBar/searchbar-base.css b/client/src/components/search/searchBar/searchbar-base.css
index d72a6c1076b6e0..cda535b090ca93 100644
--- a/client/src/components/search/searchBar/searchbar-base.css
+++ b/client/src/components/search/searchBar/searchbar-base.css
@@ -80,7 +80,7 @@
align-items: center;
}
.ais-HierarchicalMenu-list .ais-HierarchicalMenu-list {
- margin-left: 1em;
+ margin-inline-start: 1em;
}
.ais-PoweredBy-logo {
display: block;
@@ -115,7 +115,7 @@
width: 100%;
}
.ais-RangeSlider .rheostat-handle {
- margin-left: -12px;
+ margin-inline-start: -12px;
top: -7px;
}
.ais-RangeSlider .rheostat-background {
@@ -141,7 +141,7 @@
cursor: grab;
}
.rheostat-marker {
- margin-left: -1px;
+ margin-inline-start: -1px;
position: absolute;
width: 1px;
height: 5px;
@@ -151,7 +151,7 @@
height: 9px;
}
.rheostat-value {
- margin-left: 50%;
+ margin-inline-start: 50%;
padding-top: 15px;
position: absolute;
text-align: center;
@@ -159,7 +159,7 @@
transform: translateX(-50%);
}
.rheostat-tooltip {
- margin-left: 50%;
+ margin-inline-start: 50%;
position: absolute;
top: -22px;
text-align: center;
@@ -302,7 +302,7 @@ a[class^='ais-'] {
flex-wrap: wrap;
}
.ais-CurrentRefinements-item {
- margin-right: 0.3rem;
+ margin-inline-end: 0.3rem;
margin-top: 0.3rem;
padding: 0.3rem 0.5rem;
display: -webkit-box;
@@ -312,13 +312,13 @@ a[class^='ais-'] {
border-radius: 0px;
}
.ais-CurrentRefinements-category {
- margin-left: 0.3em;
+ margin-inline-start: 0.3em;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
}
.ais-CurrentRefinements-delete {
- margin-left: 0.3rem;
+ margin-inline-start: 0.3rem;
}
.ais-CurrentRefinements-label,
.ais-CurrentRefinements-categoryLabel,
@@ -332,7 +332,7 @@ a[class^='ais-'] {
white-space: nowrap;
}
.ais-CurrentRefinements-reset + .ais-CurrentRefinements-list {
- margin-left: 0.3rem;
+ margin-inline-start: 0.3rem;
}
.ais-HierarchicalMenu-link,
.ais-Menu-link {
@@ -348,7 +348,7 @@ a[class^='ais-'] {
line-height: 1.5;
}
.ais-HierarchicalMenu-link:after {
- margin-left: 0.3em;
+ margin-inline-start: 0.3em;
content: '';
width: 10px;
height: 10px;
@@ -399,7 +399,7 @@ a[class^='ais-'] {
.ais-Hits-list,
.ais-Results-list {
margin-top: -1rem;
- margin-left: -1rem;
+ margin-inline-start: -1rem;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
@@ -417,7 +417,7 @@ a[class^='ais-'] {
.ais-Hits-item,
.ais-Results-item {
margin-top: 1rem;
- margin-left: 1rem;
+ margin-inline-start: 1rem;
padding: 1rem;
width: calc(25% - 1rem);
}
@@ -439,7 +439,8 @@ a[class^='ais-'] {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
- padding: 0.3rem 2rem 0.3rem 0.3rem;
+ padding-block: 0.3rem;
+ padding-inline: 0.3rem 2rem;
background-color: #fff;
background-image: url('data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 24 24%27%3E%3Cpath d=%27M0 7.33l2.829-2.83 9.175 9.339 9.167-9.339 2.829 2.83-11.996 12.17z%27 fill%3D%22%233A4570%22 /%3E%3C/svg%3E');
background-repeat: no-repeat;
@@ -470,7 +471,7 @@ a[class^='ais-'] {
margin: 0 0.3rem;
}
.ais-RangeInput-submit {
- margin-left: 0.3rem;
+ margin-inline-start: 0.3rem;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
@@ -499,7 +500,7 @@ a[class^='ais-'] {
justify-content: center;
}
.ais-Pagination-item + .ais-Pagination-item {
- margin-left: 0.3rem;
+ margin-inline-start: 0.3rem;
}
.ais-Pagination-link {
padding: 0.3rem 0.6rem;
@@ -539,7 +540,7 @@ a[class^='ais-'] {
font-size: 0.8rem;
}
.ais-PoweredBy-logo {
- margin-left: 0.3rem;
+ margin-inline-start: 0.3rem;
}
.ais-RangeSlider .rheostat-progress {
background-color: #495588;
@@ -569,7 +570,7 @@ a[class^='ais-'] {
line-height: 1.5;
}
.ais-RatingMenu-link > * + * {
- margin-left: 0.3rem;
+ margin-inline-start: 0.3rem;
}
.ais-RatingMenu-starIcon {
position: relative;
@@ -612,35 +613,19 @@ a[class^='ais-'] {
color: var(--gray-15);
}
.ais-SearchBox-submit,
-.ais-SearchBox-reset,
-.ais-SearchBox-loadingIndicator {
+.ais-SearchBox-reset {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
- position: absolute;
z-index: 100;
width: 20px;
height: 20px;
- top: 50%;
- right: 0.3rem;
- -webkit-transform: translateY(-50%);
- transform: translateY(-50%);
}
.ais-SearchBox-reset {
- right: 0.3rem;
-}
-.ais-SearchBox-submitIcon,
-.ais-SearchBox-resetIcon,
-.ais-SearchBox-loadingIcon {
- position: absolute;
- top: 50%;
- left: 50%;
- -webkit-transform: translateX(-50%) translateY(-50%);
- transform: translateX(-50%) translateY(-50%);
+ margin-inline-start: 10px;
}
.ais-SearchBox-submitIcon path,
-.ais-SearchBox-resetIcon path,
-.ais-SearchBox-loadingIndicator {
+.ais-SearchBox-resetIcon path {
fill: var(--gray-15);
}
.ais-SearchBox-submitIcon {
diff --git a/client/src/components/search/searchBar/searchbar.css b/client/src/components/search/searchBar/searchbar.css
index 24dd7653adea98..f4ac394d740316 100644
--- a/client/src/components/search/searchBar/searchbar.css
+++ b/client/src/components/search/searchBar/searchbar.css
@@ -1,6 +1,5 @@
.fcc_searchBar {
flex-grow: 1;
- padding: 0 10px;
max-height: 33px;
font-family: 'Lato', sans-serif;
}
@@ -10,21 +9,31 @@
color: var(--gray-00);
}
-.ais-SearchBox-reset {
+.ais-SearchBox-loadingIndicator {
display: none;
}
.ais-SearchBox-input {
- padding: 0 10px 0 30px;
+ padding-block: 0;
+ padding-inline-start: 5px;
font-size: 18px;
display: inline-block;
- margin-top: 6px;
height: 26px;
}
+.ais-SearchBox-submit,
+.ais-SearchBox-reset {
+ height: 26px;
+ width: 26px;
+ background-color: var(--gray-75);
+}
+
.ais-SearchBox-submit {
- left: 0.3rem;
- top: 59.5%;
+ padding-inline: 3px;
+}
+
+.ais-SearchBox-reset {
+ padding-block: 0 2px;
}
.fcc_searchBar .ais-SearchBox-input,
@@ -35,19 +44,9 @@
}
.fcc_searchBar .ais-Hits {
- top: 70px;
- width: calc(100vw - 350px);
left: 15px;
}
-.fcc_searchBar .ais-SearchBox-form {
- margin-bottom: 0;
- display: flex;
- position: absolute;
- top: var(--header-height);
- right: 5px;
-}
-
/* hits */
.fcc_searchBar .ais-Highlight-highlighted {
background-color: transparent;
@@ -125,39 +124,44 @@ and arrow keys */
font-weight: 300;
}
+.fcc_searchBar .ais-SearchBox-form {
+ display: grid;
+ grid-template-columns: 26px auto 36px;
+ grid-template-areas: 'submit input reset';
+ margin-bottom: 0;
+ gap: 0.25em;
+ margin-top: 6px;
+ background-color: var(--gray-75);
+}
+
.ais-SearchBox-input {
- width: calc(100vw - 350px);
+ grid-area: input;
}
-.fcc_searchBar .ais-SearchBox-form {
- display: flex;
- position: absolute;
- top: var(--header-height);
- right: 15px;
+.ais-SearchBox-submit {
+ grid-area: submit;
}
-@media (min-width: 980px) {
+.ais-SearchBox-reset {
+ grid-area: reset;
+}
+
+@media (min-width: 981px) {
.ais-SearchBox-input {
width: 100%;
- max-width: 500px;
+ max-width: 100%;
}
.fcc_searchBar {
position: relative;
- max-width: 520px;
+ max-width: 500px;
}
.fcc_searchBar .ais-Hits {
top: auto;
- width: calc(100% - 20px);
- max-width: 500px;
- left: 10px;
+ width: 100%;
+ max-width: 100%;
+ left: 0px;
}
.fcc_searchBar .ais-SearchBox-form {
- display: flex;
- position: static;
top: auto;
- right: 15px;
- }
- .ais-SearchBox-submit {
- left: 0.85rem;
}
}
diff --git a/client/src/components/search/searchPage/search-page-hits.css b/client/src/components/search/searchPage/search-page-hits.css
index 49203b77478db6..8524f416705253 100644
--- a/client/src/components/search/searchPage/search-page-hits.css
+++ b/client/src/components/search/searchPage/search-page-hits.css
@@ -8,7 +8,7 @@
display: flex;
flex-direction: column;
align-items: center;
- margin-left: 0;
+ margin-inline-start: 0;
border: 1px solid #efefef;
}
diff --git a/client/src/components/seo/index.tsx b/client/src/components/seo/index.tsx
index 9abb02284cfff8..25b40ca884ad4b 100644
--- a/client/src/components/seo/index.tsx
+++ b/client/src/components/seo/index.tsx
@@ -17,10 +17,23 @@ interface SiteData {
};
}
+interface Item {
+ '@type': 'Course';
+ url: string;
+ name: string;
+ description?: string;
+ provider: {
+ '@type': 'Organization';
+ name: string;
+ sameAs: string;
+ nonprofitStatus: string;
+ };
+}
+
interface ListItem {
'@type': 'ListItem';
position: number;
- item: object;
+ item: Item;
}
interface StructuredData {
diff --git a/client/src/components/settings/__snapshots__/Honesty.test.tsx.snap b/client/src/components/settings/__snapshots__/Honesty.test.tsx.snap
index 9e6d5accbde998..86dcb3e0089989 100644
--- a/client/src/components/settings/__snapshots__/Honesty.test.tsx.snap
+++ b/client/src/components/settings/__snapshots__/Honesty.test.tsx.snap
@@ -2,7 +2,6 @@
exports[` snapshot when isHonest is false: Honesty 1`] = `
@@ -14,16 +13,16 @@ exports[` snapshot when isHonest is false: Honesty 1`] =
>
-
- buttons.agree
+ buttons.agree-honesty
@@ -31,7 +30,6 @@ exports[` snapshot when isHonest is false: Honesty 1`] =
exports[` snapshot when isHonest is true: HonestyAccepted 1`] = `
@@ -43,18 +41,16 @@ exports[` snapshot when isHonest is true: HonestyAccepted
>
-
-
- buttons.accepted-honesty
-
+ buttons.accepted-honesty
diff --git a/client/src/components/settings/__snapshots__/settings-button.test.js.snap b/client/src/components/settings/__snapshots__/settings-button.test.js.snap
new file mode 100644
index 00000000000000..078295f084bc52
--- /dev/null
+++ b/client/src/components/settings/__snapshots__/settings-button.test.js.snap
@@ -0,0 +1,2336 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should check certification button consistency 1`] = `
+Array [
+
+
+
+
+ certification.title.Responsive Web Design
+
+
+
+
,
+
+
+
+
+ certification.title.JavaScript Algorithms and Data Structures
+
+
+
+
,
+
+
+
+
+ certification.title.Front End Development Libraries
+
+
+
+
,
+
+
+
+
+ certification.title.Data Visualization
+
+
+
+
,
+
+
+
+
+ certification.title.Relational Database
+
+
+
+
,
+
+
+
+
+ certification.title.Back End Development and APIs
+
+
+
+
,
+
+
+
+
+ certification.title.Quality Assurance
+
+
+
+
,
+
+
+
+
+ certification.title.Scientific Computing with Python
+
+
+
+
,
+
+
+
+
+ certification.title.Data Analysis with Python
+
+
+
+
,
+ ,
+
+
+
+
+ certification.title.Machine Learning with Python
+
+
+
+
,
+]
+`;
+
+exports[`should check legacy certification button consistency 1`] = `
+Array [
+
+
+
+
+ certification.title.Legacy Front End
+
+
+
+
,
+
+
+
+
+ certification.title.Legacy Back End
+
+
+
+
,
+
+
+
+
+ certification.title.Legacy Data Visualization
+
+
+
+
,
+ ,
+]
+`;
diff --git a/client/src/components/settings/about.tsx b/client/src/components/settings/about.tsx
index 61f5ff7d96cc7f..6653fcbb57c20d 100644
--- a/client/src/components/settings/about.tsx
+++ b/client/src/components/settings/about.tsx
@@ -15,6 +15,7 @@ import SoundSettings from './sound';
import ThemeSettings, { Themes } from './theme';
import UsernameSettings from './username';
import KeyboardShortcutsSettings from './keyboard-shortcuts';
+import SectionHeader from './section-header';
type FormValues = {
name: string;
@@ -47,6 +48,18 @@ type AboutState = {
isPictureUrlValid: boolean;
};
+const ShowImageValidationWarning = ({
+ alertContent
+}: {
+ alertContent: string;
+}) => {
+ return (
+
+ {alertContent}
+
+ );
+};
+
class AboutSettings extends Component {
validationImage: HTMLImageElement;
static displayName: string;
@@ -78,7 +91,6 @@ class AboutSettings extends Component {
picture === formValues.picture &&
about === formValues.about
) {
- // eslint-disable-next-line react/no-did-update-set-state
return this.setState({
originalValues: {
name,
@@ -106,7 +118,7 @@ class AboutSettings extends Component {
e.preventDefault();
const { formValues } = this.state;
const { submitNewAbout } = this.props;
- if (this.state.isPictureUrlValid === true) {
+ if (this.state.isPictureUrlValid === true && !this.isFormPristine()) {
return this.setState({ formClicked: true }, () =>
submitNewAbout(formValues)
);
@@ -169,21 +181,6 @@ class AboutSettings extends Component {
}));
};
- showImageValidationWarning = () => {
- const { t } = this.props;
- if (this.state.isPictureUrlValid === false) {
- return (
-
-
- {t('validation.url-not-image')}
-
-
- );
- } else {
- return true;
- }
- };
-
handleAboutChange = (e: React.FormEvent) => {
const value = (e.target as HTMLInputElement).value.slice(0);
return this.setState(state => ({
@@ -209,53 +206,69 @@ class AboutSettings extends Component {
toggleKeyboardShortcuts
} = this.props;
return (
-
+ <>
-
+
+
{t('settings.headings.personal-info')}
@@ -270,7 +283,7 @@ class AboutSettings extends Component
{
toggleKeyboardShortcuts={toggleKeyboardShortcuts}
/>
-
+ >
);
}
}
diff --git a/client/src/components/settings/certification.css b/client/src/components/settings/certification.css
index 421d2fc376a270..428cfc95f03756 100644
--- a/client/src/components/settings/certification.css
+++ b/client/src/components/settings/certification.css
@@ -1,9 +1,3 @@
-.certification-settings .solutions-dropdown,
-.certification-settings .solutions-dropdown .dropdown-menu,
-.certification-settings .solutions-dropdown .dropdown {
- width: 100%;
-}
-
.certification-settings tr {
height: 57px;
}
diff --git a/client/src/components/settings/certification.js b/client/src/components/settings/certification.js
index 4d970cc195ae36..7a59a882df3b26 100644
--- a/client/src/components/settings/certification.js
+++ b/client/src/components/settings/certification.js
@@ -213,9 +213,10 @@ export class CertificationSettings extends Component {
);
};
@@ -227,7 +228,7 @@ export class CertificationSettings extends Component {
- {certName}
+ {t(`certification.title.${certName}`, certName)}
@@ -265,7 +266,9 @@ export class CertificationSettings extends Component {
.map(({ link, title, id }) => (
- {title}
+
+ {t(`certification.project.title.${title}`, title)}
+
{this.getProjectSolution(id, title)}
@@ -283,7 +286,8 @@ export class CertificationSettings extends Component {
data-cy={`btn-for-${certSlug}`}
onClick={createClickHandler(certSlug)}
>
- {isCert ? t('buttons.show-cert') : t('buttons.claim-cert')}
+ {isCert ? t('buttons.show-cert') : t('buttons.claim-cert')}{' '}
+ {certName}
@@ -337,20 +341,30 @@ export class CertificationSettings extends Component {
return (
- Legacy Full Stack Certification
+
+ {t('certification.title.Legacy Full Stack Certification')}
+
{t('settings.claim-legacy', {
- cert: 'Legacy Full Stack Certification'
+ cert: t('certification.title.Legacy Full Stack Certification')
})}
- Responsive Web Design
- JavaScript Algorithms and Data Structures
- Front End Development Libraries
- Data Visualization
- Back End Development and APIs
- Legacy Information Security and Quality Assurance
+ {t('certification.title.Responsive Web Design')}
+
+ {t(
+ 'certification.title.JavaScript Algorithms and Data Structures'
+ )}
+
+ {t('certification.title.Front End Development Libraries')}
+ {t('certification.title.Data Visualization')}
+ {t('certification.title.Back End Development and APIs')}
+
+ {t(
+ 'certification.title.Legacy Information Security and Quality Assurance'
+ )}
+
diff --git a/client/src/components/settings/certification.test.tsx b/client/src/components/settings/certification.test.tsx
index de7969d34a6e81..2c6e033ace133d 100644
--- a/client/src/components/settings/certification.test.tsx
+++ b/client/src/components/settings/certification.test.tsx
@@ -2,7 +2,7 @@
import { render, screen } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
-import { createStore } from '../../redux/createStore';
+import { createStore } from '../../redux/create-store';
import { CertificationSettings } from './certification';
@@ -20,7 +20,7 @@ describe(' ', () => {
expect(
screen.getByRole('link', {
- name: 'buttons.show-cert'
+ name: /^buttons.show-cert\s+\S+/
})
).toHaveAttribute(
'href',
@@ -33,7 +33,7 @@ describe(' ', () => {
renderWithRedux( );
const allClaimedCerts = screen.getAllByRole('link', {
- name: 'buttons.show-cert'
+ name: /^buttons.show-cert\s+\S+/
});
allClaimedCerts.forEach(cert => {
@@ -49,7 +49,7 @@ describe(' ', () => {
renderWithRedux( );
const allClaimedCerts = screen.getAllByRole('link', {
- name: 'buttons.show-cert'
+ name: /^buttons.show-cert\s+\S+/
});
allClaimedCerts.forEach(cert => {
@@ -65,7 +65,7 @@ describe(' ', () => {
expect(
screen.getByRole('link', {
- name: 'buttons.view'
+ name: 'buttons.view settings.labels.solution-for (aria.opens-new-window)'
})
).toHaveAttribute('href', 'https://github.com/freeCodeCamp/freeCodeCamp');
});
diff --git a/client/src/components/settings/danger-zone.tsx b/client/src/components/settings/danger-zone.tsx
index 3ca233acb02690..c795c269e9c272 100644
--- a/client/src/components/settings/danger-zone.tsx
+++ b/client/src/components/settings/danger-zone.tsx
@@ -12,11 +12,11 @@ import ResetModal from './reset-modal';
import './danger-zone.css';
-type DangerZoneProps = {
+interface DangerZoneProps {
deleteAccount: () => void;
resetProgress: () => void;
t: TFunction;
-};
+}
const mapStateToProps = () => ({});
const mapDispatchToProps = (dispatch: Dispatch) =>
@@ -42,50 +42,48 @@ function DangerZone({ deleteAccount, resetProgress, t }: DangerZoneProps) {
}
return (
-
-
-
- {t('settings.danger.heading')}
+
+
+ {t('settings.danger.heading')}
+
+ {t('settings.danger.be-careful')}
+
+
+ {t('settings.danger.reset')}
+
+
+
+ {t('settings.danger.delete')}
+
- {t('settings.danger.be-careful')}
-
-
- {t('settings.danger.reset')}
-
-
-
- {t('settings.danger.delete')}
-
-
-
-
+
+
-
-
-
-
+
+
+
);
}
diff --git a/client/src/components/settings/delete-modal.tsx b/client/src/components/settings/delete-modal.tsx
index 06899ff6cebfd6..74a6a8b4229ac8 100644
--- a/client/src/components/settings/delete-modal.tsx
+++ b/client/src/components/settings/delete-modal.tsx
@@ -14,7 +14,7 @@ type DeleteModalProps = {
function DeleteModal(props: DeleteModalProps): JSX.Element {
const { show, onHide } = props;
- const email = 'team@freecodecamp.org';
+ const email = 'support@freecodecamp.org';
const { t } = useTranslation();
return (
@@ -170,43 +173,54 @@ function EmailSettings({
)}
-
diff --git a/client/src/components/settings/honesty.css b/client/src/components/settings/honesty.css
index 0e2c7b36d4e166..dd0d550b49fcf9 100644
--- a/client/src/components/settings/honesty.css
+++ b/client/src/components/settings/honesty.css
@@ -1,6 +1,5 @@
.honesty-panel p {
- margin-left: 10px;
- margin-right: 10px;
+ margin-inline: 10px;
font-family: 'Lato', sans-serif;
}
@@ -8,11 +7,6 @@
padding-top: 15px;
}
-.honesty-policy .disabled-agreed p {
- margin-top: 0;
- margin-bottom: 0;
-}
-
.honesty-panel .btn-invert {
color: var(--primary-background);
}
diff --git a/client/src/components/settings/honesty.tsx b/client/src/components/settings/honesty.tsx
index c8db8c62c9dac4..b8c54e31d969f5 100644
--- a/client/src/components/settings/honesty.tsx
+++ b/client/src/components/settings/honesty.tsx
@@ -15,33 +15,25 @@ type HonestyProps = {
const Honesty = ({ isHonest, updateIsHonest }: HonestyProps): JSX.Element => {
const { t } = useTranslation();
- const button = isHonest ? (
-
- {t('buttons.accepted-honesty')}
-
- ) : (
- updateIsHonest({ isHonest: true })}
- >
- {t('buttons.agree')}
-
- );
+ const buttonText = isHonest
+ ? t('buttons.accepted-honesty')
+ : t('buttons.agree-honesty');
+
return (
-
+
{t('settings.headings.honesty')}
-
- {button}
+ !isHonest && updateIsHonest({ isHonest: true })}
+ >
+ {buttonText}
+
);
diff --git a/client/src/components/settings/internet.tsx b/client/src/components/settings/internet.tsx
index 06d9c52fc9fcca..9b12a90c8e21a6 100644
--- a/client/src/components/settings/internet.tsx
+++ b/client/src/components/settings/internet.tsx
@@ -66,7 +66,6 @@ class InternetSettings extends Component {
twitter !== originalValues.twitter ||
website !== originalValues.website
) {
- // eslint-disable-next-line react/no-did-update-set-state
return this.setState({
originalValues: { githubProfile, linkedin, twitter, website }
});
@@ -179,71 +178,78 @@ class InternetSettings extends Component {
const { state: websiteValidation, message: websiteValidationMessage } =
this.getValidationStateFor(website);
-
+ const isDisabled = this.isFormPristine() || !this.isFormValid();
return (
<>
{t('settings.headings.internet')}
>
diff --git a/client/src/components/settings/portfolio.tsx b/client/src/components/settings/portfolio.tsx
index 370277f1975526..f339c0237fc62a 100644
--- a/client/src/components/settings/portfolio.tsx
+++ b/client/src/components/settings/portfolio.tsx
@@ -84,11 +84,6 @@ class PortfolioSettings extends Component {
});
};
- handleSubmit = (e: React.FormEvent, id: string) => {
- e.preventDefault();
- this.updateItem(id);
- };
-
updateItem = (id: string) => {
const { portfolio, unsavedItemId } = this.state;
if (unsavedItemId === id) {
@@ -218,101 +213,107 @@ class PortfolioSettings extends Component {
);
const { state: descriptionState, message: descriptionMessage } =
this.getDescriptionValidation(description);
+
+ const isDisabled =
+ pristine ||
+ !title ||
+ !isURL(url, {
+ protocols: ['http', 'https'],
+ /* eslint-disable camelcase, @typescript-eslint/naming-convention */
+ require_tld: true,
+ require_protocol: true
+ /* eslint-enable camelcase, @typescript-eslint/naming-convention */
+ });
+
+ const handleSubmit = (e: React.FormEvent, id: string) => {
+ e.preventDefault();
+ if (isDisabled) return null;
+ return this.updateItem(id);
+ };
+
return (
-
-
-
- {index + 1 !== arr.length && (
- <>
-
-
-
- >
- )}
-
-
+
+
+ {index + 1 !== arr.length && (
+ <>
+
+
+
+ >
+ )}
+
);
};
diff --git a/client/src/components/settings/privacy.tsx b/client/src/components/settings/privacy.tsx
index 2bc13252fda99e..ccb6ea49b2725c 100644
--- a/client/src/components/settings/privacy.tsx
+++ b/client/src/components/settings/privacy.tsx
@@ -60,99 +60,103 @@ function PrivacySettings({
{t('settings.privacy')}
diff --git a/client/src/components/settings/settings-button.test.js b/client/src/components/settings/settings-button.test.js
new file mode 100644
index 00000000000000..8cc9778688a0d5
--- /dev/null
+++ b/client/src/components/settings/settings-button.test.js
@@ -0,0 +1,48 @@
+import renderer from 'react-test-renderer';
+
+import {
+ legacyProjectMap,
+ projectMap
+} from '../../resources/cert-and-project-map';
+import { CertificationSettings } from './certification';
+
+const props = { t: val => val };
+
+const certificationSettings = new CertificationSettings(props);
+
+const { renderCertifications } = certificationSettings;
+
+beforeAll(() => {
+ projectMap['JavaScript Algorithms and Data Structures'] = projectMap[
+ 'JavaScript Algorithms and Data Structures'
+ ].map(v => ({
+ ...v,
+ link: 'javascript'
+ }));
+});
+
+it('should check legacy certification button consistency', () => {
+ const legacyCertifications = Object.keys(legacyProjectMap);
+
+ const tree = renderer
+ .create(
+ legacyCertifications.map(certName =>
+ renderCertifications(certName, legacyProjectMap)
+ )
+ )
+ .toJSON();
+
+ expect(tree).toMatchSnapshot();
+});
+
+it('should check certification button consistency', () => {
+ const certifications = Object.keys(projectMap);
+
+ const tree = renderer
+ .create(
+ certifications.map(certName => renderCertifications(certName, projectMap))
+ )
+ .toJSON();
+
+ expect(tree).toMatchSnapshot();
+});
diff --git a/client/src/components/settings/toggle-setting.css b/client/src/components/settings/toggle-setting.css
index c2c0677ffe028e..e7ba31526ea25a 100644
--- a/client/src/components/settings/toggle-setting.css
+++ b/client/src/components/settings/toggle-setting.css
@@ -11,7 +11,7 @@
}
.toggle-setting-container .btn-group {
- padding-left: 5px;
+ padding-inline: 5px;
}
.toggle-setting-container > .form-group > * {
diff --git a/client/src/components/settings/username.tsx b/client/src/components/settings/username.tsx
index 5c146c20b7d678..59755e71ef407c 100644
--- a/client/src/components/settings/username.tsx
+++ b/client/src/components/settings/username.tsx
@@ -96,7 +96,6 @@ class UsernameSettings extends Component {
const { username } = this.props;
const { formValue } = this.state;
if (prevUsername !== username && prevFormValue === formValue) {
- // eslint-disable-next-line react/no-did-update-set-state
return this.setState({
isFormPristine: username === formValue,
submitClicked: false,
@@ -210,7 +209,8 @@ class UsernameSettings extends Component {
submitClicked
} = this.state;
const { isValidUsername, t, validating } = this.props;
-
+ const isDisabled =
+ !(isValidUsername && valid && !isFormPristine) || submitClicked;
return (
);
diff --git a/client/src/components/solution-display-widget/index.tsx b/client/src/components/solution-display-widget/index.tsx
index 13ba1de6dfdce6..b720163ae25165 100644
--- a/client/src/components/solution-display-widget/index.tsx
+++ b/client/src/components/solution-display-widget/index.tsx
@@ -1,18 +1,15 @@
import { faExternalLinkAlt } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import {
- Button,
- DropdownButton,
- MenuItem
-} from '@freecodecamp/react-bootstrap';
+import { Button, Dropdown, MenuItem } from '@freecodecamp/react-bootstrap';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { CompletedChallenge } from '../../redux/prop-types';
import { getSolutionDisplayType } from '../../utils/solution-display-type';
-
+import './solution-display-widget.css';
interface Props {
completedChallenge: CompletedChallenge;
dataCy?: string;
+ projectTitle: string;
showUserCode: () => void;
showProjectPreview?: () => void;
displayContext: 'timeline' | 'settings' | 'certification';
@@ -21,45 +18,74 @@ interface Props {
export function SolutionDisplayWidget({
completedChallenge,
dataCy,
+ projectTitle,
showUserCode,
showProjectPreview,
displayContext
-}: Props) {
+}: Props): JSX.Element | null {
const { id, solution, githubLink } = completedChallenge;
const { t } = useTranslation();
const viewText = t('buttons.view');
const viewCode = t('buttons.view-code');
const viewProject = t('buttons.view-project');
-
+ // We need to add a random number for dropdown button id's since there may be
+ // two dropdowns for the same project on the page.
+ const randomIdSuffix = Math.floor(Math.random() * 1_000_000);
const ShowFilesSolutionForCertification = (
-
- {t('certification.project.solution')}
-
+
+ {viewText}{' '}
+
+ {t('settings.labels.solution-for', { projectTitle })}
+
+
);
const ShowProjectAndGithubLinkForCertification = (
- <>
-
- {t('certification.project.solution')}
-
- ,{' '}
-
- {t('certification.project.source')}
-
- >
+
+
+ {viewText}{' '}
+
+ {t('settings.labels.solution-for', { projectTitle })}
+
+
+
+
+ {t('certification.project.solution')}
+ ({t('aria.opens-new-window')})
+
+
+
+ {t('certification.project.source')}
+ ({t('aria.opens-new-window')})
+
+
+
+
);
const ShowProjectLinkForCertification = (
-
- {t('certification.project.solution')}
-
+ {viewText}{' '}
+
+ {t('settings.labels.solution-for', { projectTitle })} (
+ {t('aria.opens-new-window')})
+
+
+
);
const MissingSolutionComponentForCertification = (
<>{t('certification.project.no-solution')}>
@@ -70,57 +96,67 @@ export function SolutionDisplayWidget({
bsStyle='primary'
className='btn-invert'
data-cy={dataCy}
- id={`btn-for-${id}`}
onClick={showUserCode}
>
- {viewText}
+ {viewText}{' '}
+
+ {t('settings.labels.solution-for', { projectTitle })}
+
);
const ShowMultifileProjectSolution = (
-
-
- {viewCode}
-
-
- {viewProject}
-
-
+
+
+ {viewText}{' '}
+
+ {t('settings.labels.solution-for', { projectTitle })}
+
+
+
+
+ {viewCode}
+
+
+ {viewProject}
+
+
+
);
const ShowProjectAndGithubLinks = (
-
-
- {t('buttons.frontend')}
-
-
- {t('buttons.backend')}
-
-
+
+
+ {viewText}{' '}
+
+ {t('settings.labels.solution-for', { projectTitle })}
+
+
+
+
+ {t('buttons.frontend')}{' '}
+ ({t('aria.opens-new-window')})
+
+
+
+ {t('buttons.backend')}{' '}
+ ({t('aria.opens-new-window')})
+
+
+
+
);
const ShowProjectLink = (
@@ -129,11 +165,15 @@ export function SolutionDisplayWidget({
bsStyle='primary'
className='btn-invert'
href={solution}
- id={`btn-for-${id}`}
rel='noopener noreferrer'
target='_blank'
>
- {viewText}
+ {viewText}{' '}
+
+ {t('settings.labels.solution-for', { projectTitle })} (
+ {t('aria.opens-new-window')})
+
+
);
const MissingSolutionComponent =
diff --git a/client/src/components/solution-display-widget/solution-display-widget.css b/client/src/components/solution-display-widget/solution-display-widget.css
new file mode 100644
index 00000000000000..4bff674e52343d
--- /dev/null
+++ b/client/src/components/solution-display-widget/solution-display-widget.css
@@ -0,0 +1,3 @@
+.solutions-dropdown a[role='menuitem'] {
+ text-decoration: none;
+}
diff --git a/client/src/declarations.d.ts b/client/src/declarations.d.ts
index 5591e3a3edc2f9..f56ab2a3e99385 100644
--- a/client/src/declarations.d.ts
+++ b/client/src/declarations.d.ts
@@ -38,3 +38,5 @@ declare var MathJax: {
Queue: (attributes: unknown[]) => void;
};
};
+
+declare module 'monaco-editor/esm/vs/base/common/platform.js';
diff --git a/client/src/pages/__snapshots__/email-sign-up.test.js.snap b/client/src/pages/__snapshots__/email-sign-up.test.js.snap
index 1931f92d7b40b7..c6fc3a404dc5a2 100644
--- a/client/src/pages/__snapshots__/email-sign-up.test.js.snap
+++ b/client/src/pages/__snapshots__/email-sign-up.test.js.snap
@@ -13,7 +13,6 @@ exports[` Non-Authenticated user "not accepted terms and conditio
className="col-md-8 col-md-offset-2 col-sm-10 col-sm-offset-1 col-xs-12"
>
Non-Authenticated user "not accepted terms and conditio
learn.read-this.heading
Non-Authenticated user "not accepted terms and conditio
misc.quincy
Non-Authenticated user "not accepted terms and conditio
misc.email-blast
Non-Authenticated user "not accepted terms and conditio
className="col-xs-12"
>
void;
@@ -58,28 +55,12 @@ function DonatePage({
}: DonatePageProps) {
useEffect(() => {
executeGA({
- type: 'event',
- data: {
- category: 'Donation View',
- action: `Displayed donate page`,
- nonInteraction: true
- }
+ event: 'donationview',
+ action: `Displayed Donate Page`
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
- function handleProcessing(duration: string, amount: number, action: string) {
- executeGA({
- type: 'event',
- data: {
- category: 'Donation',
- action: `donate page ${action}`,
- label: duration,
- value: amount
- }
- });
- }
-
return showLoading ? (
) : (
@@ -110,7 +91,7 @@ function DonatePage({
-
+
diff --git a/client/src/pages/learn.tsx b/client/src/pages/learn.tsx
index b534563989170f..0ae210ae9fddda 100644
--- a/client/src/pages/learn.tsx
+++ b/client/src/pages/learn.tsx
@@ -11,6 +11,7 @@ import Intro from '../components/Intro';
import Map from '../components/Map';
import { Spacer } from '../components/helpers';
import LearnLayout from '../components/layouts/learn';
+import { defaultDonation } from '../../../config/donation-settings';
import {
isSignedInSelector,
userSelector,
@@ -82,11 +83,10 @@ function LearnPage({
const onDonationAlertClick = () => {
executeGA({
- type: 'event',
- data: {
- category: 'Donation Related',
- action: `learn donation alert click`
- }
+ event: 'donationrelated',
+ action: `Learn Donation Alert Click`,
+ duration: defaultDonation.donationDuration,
+ amount: defaultDonation.donationAmount
});
};
return (
diff --git a/client/src/pages/learn/2022/javascript-algorithms-and-data-structures/learn-advanced-array-methods-by-building-a-statistics-calculator/index.md b/client/src/pages/learn/2022/javascript-algorithms-and-data-structures/learn-advanced-array-methods-by-building-a-statistics-calculator/index.md
new file mode 100644
index 00000000000000..608a7a57643363
--- /dev/null
+++ b/client/src/pages/learn/2022/javascript-algorithms-and-data-structures/learn-advanced-array-methods-by-building-a-statistics-calculator/index.md
@@ -0,0 +1,10 @@
+---
+title: Introduction to the Learn Advanced Array Methods by Building a Statistics Calculator
+block: learn-advanced-array-methods-by-building-a-statistics-calculator
+superBlock: JavaScript Algorithms and Data Structures
+isBeta: true
+---
+
+## Introduction to the Learn Advanced Array Methods by Building a Statistics Calculator
+
+This is a test for the new project-based curriculum.
diff --git a/client/src/pages/learn/the-odin-project/index.md b/client/src/pages/learn/the-odin-project/index.md
new file mode 100644
index 00000000000000..e600d4a733413d
--- /dev/null
+++ b/client/src/pages/learn/the-odin-project/index.md
@@ -0,0 +1,9 @@
+---
+title: The Odin Project
+superBlock: the-odin-project
+certification: the-odin-project
+---
+
+## The Odin project
+
+The Odin Project is one of those "What I wish I had when I was learning" resources. Not everyone has access to a computer science education or the funds to attend an intensive coding school and neither of those is right for everyone anyway. This project is designed to fill in the gap for people who are trying to hack it on their own but still want a high quality education.
diff --git a/client/src/pages/learn/the-odin-project/top-build-a-recipe-page-project/index.md b/client/src/pages/learn/the-odin-project/top-build-a-recipe-page-project/index.md
new file mode 100644
index 00000000000000..39bc4dc70b8006
--- /dev/null
+++ b/client/src/pages/learn/the-odin-project/top-build-a-recipe-page-project/index.md
@@ -0,0 +1,9 @@
+---
+title: The Odin Project
+superBlock: the-odin-project
+certification: the-odin-project
+---
+
+## The Odin project
+
+Description is to be determined
diff --git a/client/src/pages/learn/the-odin-project/top-learn-html-foundations/index.md b/client/src/pages/learn/the-odin-project/top-learn-html-foundations/index.md
new file mode 100644
index 00000000000000..39bc4dc70b8006
--- /dev/null
+++ b/client/src/pages/learn/the-odin-project/top-learn-html-foundations/index.md
@@ -0,0 +1,9 @@
+---
+title: The Odin Project
+superBlock: the-odin-project
+certification: the-odin-project
+---
+
+## The Odin project
+
+Description is to be determined
diff --git a/client/src/redux/action-types.js b/client/src/redux/action-types.js
index 22465beb90f397..4053c80dab9a76 100644
--- a/client/src/redux/action-types.js
+++ b/client/src/redux/action-types.js
@@ -23,19 +23,17 @@ export const actionTypes = createTypes(
'showCodeAlly',
'submitComplete',
'updateComplete',
- 'updateCurrentChallengeId',
'updateFailed',
'updateDonationFormState',
'updateUserToken',
+ 'postChargeProcessing',
+ 'updateAllChallengesInfo',
...createAsyncTypes('fetchUser'),
- ...createAsyncTypes('addDonation'),
- ...createAsyncTypes('createStripeSession'),
- ...createAsyncTypes('postChargeStripe'),
+ ...createAsyncTypes('postCharge'),
...createAsyncTypes('fetchProfileForUser'),
...createAsyncTypes('acceptTerms'),
...createAsyncTypes('showCert'),
...createAsyncTypes('reportUser'),
- ...createAsyncTypes('postChargeStripeCard'),
...createAsyncTypes('deleteUserToken'),
...createAsyncTypes('saveChallenge')
],
diff --git a/client/src/redux/actions.js b/client/src/redux/actions.js
index a540a71d58cd76..38608a046bc411 100644
--- a/client/src/redux/actions.js
+++ b/client/src/redux/actions.js
@@ -53,28 +53,16 @@ export const fetchUser = createAction(actionTypes.fetchUser);
export const fetchUserComplete = createAction(actionTypes.fetchUserComplete);
export const fetchUserError = createAction(actionTypes.fetchUserError);
-export const addDonation = createAction(actionTypes.addDonation);
-export const addDonationComplete = createAction(
- actionTypes.addDonationComplete
+export const updateAllChallengesInfo = createAction(
+ actionTypes.updateAllChallengesInfo
);
-export const addDonationError = createAction(actionTypes.addDonationError);
-export const postChargeStripe = createAction(actionTypes.postChargeStripe);
-export const postChargeStripeComplete = createAction(
- actionTypes.postChargeStripeComplete
-);
-export const postChargeStripeError = createAction(
- actionTypes.postChargeStripeError
-);
-export const postChargeStripeCard = createAction(
- actionTypes.postChargeStripeCard
-);
-export const postChargeStripeCardComplete = createAction(
- actionTypes.postChargeStripeCardComplete
-);
-export const postChargeStripeCardError = createAction(
- actionTypes.postChargeStripeCardError
+export const postCharge = createAction(actionTypes.postCharge);
+export const postChargeProcessing = createAction(
+ actionTypes.postChargeProcessing
);
+export const postChargeComplete = createAction(actionTypes.postChargeComplete);
+export const postChargeError = createAction(actionTypes.postChargeError);
export const fetchProfileForUser = createAction(
actionTypes.fetchProfileForUser
@@ -106,9 +94,5 @@ export const hideCodeAlly = createAction(actionTypes.hideCodeAlly);
export const showCodeAlly = createAction(actionTypes.showCodeAlly);
export const tryToShowCodeAlly = createAction(actionTypes.tryToShowCodeAlly);
-export const updateCurrentChallengeId = createAction(
- actionTypes.updateCurrentChallengeId
-);
-
export const closeSignoutModal = createAction(actionTypes.closeSignoutModal);
export const openSignoutModal = createAction(actionTypes.openSignoutModal);
diff --git a/client/src/redux/cookieValues.js b/client/src/redux/cookie-values.js
similarity index 100%
rename from client/src/redux/cookieValues.js
rename to client/src/redux/cookie-values.js
diff --git a/client/src/redux/createStore.js b/client/src/redux/create-store.js
similarity index 86%
rename from client/src/redux/createStore.js
rename to client/src/redux/create-store.js
index 75e19ea50174a1..93918f35dea3ca 100644
--- a/client/src/redux/createStore.js
+++ b/client/src/redux/create-store.js
@@ -5,9 +5,9 @@ import createSagaMiddleware from 'redux-saga';
import envData from '../../../config/env.json';
import { isBrowser } from '../../utils';
-import rootEpic from './rootEpic';
-import rootReducer from './rootReducer';
-import rootSaga from './rootSaga';
+import rootEpic from './root-epic';
+import rootReducer from './root-reducer';
+import rootSaga from './root-saga';
const { environment } = envData;
@@ -47,8 +47,8 @@ export const createStore = () => {
epicMiddleware.run(rootEpic);
if (module.hot) {
// Enable Webpack hot module replacement for reducers
- module.hot.accept('./rootReducer', () => {
- const nextRootReducer = require('./rootReducer');
+ module.hot.accept('./root-reducer', () => {
+ const nextRootReducer = require('./root-reducer');
store.replaceReducer(nextRootReducer);
});
}
diff --git a/client/src/redux/donation-saga.js b/client/src/redux/donation-saga.js
index 73f0a9f5822fbb..245f3cf7940518 100644
--- a/client/src/redux/donation-saga.js
+++ b/client/src/redux/donation-saga.js
@@ -14,22 +14,23 @@ import {
postChargeStripe,
postChargeStripeCard
} from '../utils/ajax';
+import { stringifyDonationEvents } from '../utils/analyticsStrings';
+import { PaymentProvider } from '../../../config/donation-settings';
import { actionTypes as appTypes } from './action-types';
import {
- addDonationComplete,
- addDonationError,
openDonationModal,
- postChargeStripeCardComplete,
- postChargeStripeCardError,
- postChargeStripeComplete,
- postChargeStripeError,
+ postChargeComplete,
+ postChargeProcessing,
+ postChargeError,
preventBlockDonationRequests,
- preventProgressDonationRequests
+ preventProgressDonationRequests,
+ executeGA
} from './actions';
import {
isDonatingSelector,
recentlyClaimedBlockSelector,
- shouldRequestDonationSelector
+ shouldRequestDonationSelector,
+ isSignedInSelector
} from './selectors';
const defaultDonationErrorMessage = i18next.t('donate.error-2');
@@ -49,33 +50,74 @@ function* showDonateModalSaga() {
}
}
-function* addDonationSaga({ payload }) {
- try {
- yield call(addDonation, payload);
- yield put(addDonationComplete());
- yield call(setDonationCookie);
- } catch (error) {
- const data =
- error.response && error.response.data
- ? error.response.data
- : {
- message: defaultDonationErrorMessage
- };
- yield put(addDonationError(data.message));
+export function* postChargeSaga({
+ payload,
+ payload: {
+ paymentProvider,
+ paymentContext,
+ amount,
+ duration,
+ handleAuthentication,
+ paymentMethodId
}
-}
-
-function* postChargeStripeSaga({ payload }) {
+}) {
try {
- yield call(postChargeStripe, payload);
- yield put(postChargeStripeComplete());
- yield call(setDonationCookie);
+ if (paymentProvider !== PaymentProvider.Patreon) {
+ yield put(postChargeProcessing());
+ }
+
+ if (paymentProvider === PaymentProvider.Stripe) {
+ yield call(postChargeStripe, payload);
+ } else if (paymentProvider === PaymentProvider.StripeCard) {
+ const optimizedPayload = { paymentMethodId, amount, duration };
+ const response = yield call(postChargeStripeCard, optimizedPayload);
+ const error = response?.data?.error;
+ if (error) {
+ yield stripeCardErrorHandler(
+ error,
+ handleAuthentication,
+ error.client_secret,
+ response.paymentMethodId,
+ optimizedPayload
+ );
+
+ //if the authentication does not throw an error, add a donation
+ yield call(addDonation, { amount, duration });
+ }
+ } else if (paymentProvider === PaymentProvider.Paypal) {
+ // If the user is signed in and the payment goes through call api
+ let isSignedIn = yield select(isSignedInSelector);
+ // look into skip add donation
+ // what to do with "data" that comes throug
+ if (isSignedIn) yield call(addDonation, { amount, duration });
+ }
+ if (
+ [
+ PaymentProvider.Paypal,
+ PaymentProvider.Stripe,
+ PaymentProvider.StripeCard
+ ].includes(paymentProvider)
+ ) {
+ yield put(postChargeComplete());
+ yield call(setDonationCookie);
+ }
+ yield put(
+ executeGA({
+ event:
+ paymentProvider === PaymentProvider.Patreon
+ ? 'donationrelated'
+ : 'donation',
+ action: stringifyDonationEvents(paymentContext, paymentProvider),
+ duration,
+ amount
+ })
+ );
} catch (error) {
const err =
error.response && error.response.data
? error.response.data.error
: defaultDonationErrorMessage;
- yield put(postChargeStripeError(err));
+ yield put(postChargeError(err));
}
}
@@ -99,40 +141,16 @@ function* stripeCardErrorHandler(
}
}
-function* postChargeStripeCardSaga({
- payload: { paymentMethodId, amount, duration, handleAuthentication }
-}) {
- try {
- const optimizedPayload = { paymentMethodId, amount, duration };
- const {
- data: { error }
- } = yield call(postChargeStripeCard, optimizedPayload);
- if (error) {
- yield stripeCardErrorHandler(
- error,
- handleAuthentication,
- error.client_secret,
- paymentMethodId,
- optimizedPayload
- );
- }
- yield call(addDonation, optimizedPayload);
- yield put(postChargeStripeCardComplete());
- yield call(setDonationCookie);
- } catch (error) {
- const errorMessage = error.message || defaultDonationErrorMessage;
- yield put(postChargeStripeCardError(errorMessage));
- }
-}
-
-function* setDonationCookie() {
- const isDonating = yield select(isDonatingSelector);
- const isDonorCookieSet = document.cookie
- .split(';')
- .some(item => item.trim().startsWith('isDonor=true'));
- if (isDonating) {
- if (!isDonorCookieSet) {
- document.cookie = 'isDonor=true';
+export function* setDonationCookie() {
+ if (document?.cookie) {
+ const isDonating = yield select(isDonatingSelector);
+ const isDonorCookieSet = document.cookie
+ .split(';')
+ .some(item => item.trim().startsWith('isDonor=true'));
+ if (isDonating) {
+ if (!isDonorCookieSet) {
+ document.cookie = 'isDonor=true';
+ }
}
}
}
@@ -140,9 +158,7 @@ function* setDonationCookie() {
export function createDonationSaga(types) {
return [
takeEvery(types.tryToShowDonationModal, showDonateModalSaga),
- takeEvery(types.addDonation, addDonationSaga),
- takeLeading(types.postChargeStripe, postChargeStripeSaga),
- takeLeading(types.postChargeStripeCard, postChargeStripeCardSaga),
+ takeLeading(types.postCharge, postChargeSaga),
takeEvery(types.fetchUserComplete, setDonationCookie)
];
}
diff --git a/client/src/redux/donation-saga.test.js b/client/src/redux/donation-saga.test.js
new file mode 100644
index 00000000000000..d7fa3de10a6ce5
--- /dev/null
+++ b/client/src/redux/donation-saga.test.js
@@ -0,0 +1,124 @@
+import { expectSaga } from 'redux-saga-test-plan';
+import {
+ postChargeStripe,
+ postChargeStripeCard,
+ addDonation
+} from '../utils/ajax';
+import { postChargeSaga, setDonationCookie } from './donation-saga.js';
+import { postChargeComplete, postChargeProcessing, executeGA } from './actions';
+
+jest.mock('../utils/ajax');
+jest.mock('../analytics');
+
+const postChargeDataMock = {
+ payload: {
+ paymentProvider: 'stripe',
+ paymentContext: 'donate page',
+ amount: '500',
+ duration: 'monthly',
+ handleAuthentication: jest.fn(),
+ paymentMethodId: '123456'
+ }
+};
+
+const analyticsDataMock = {
+ event: 'donation',
+ action: 'Donate Page Stripe Payment Submission',
+ duration: 'monthly',
+ amount: '500'
+};
+
+describe('donation-saga', () => {
+ it('calls postChargeStrip for Stripe', () => {
+ return expectSaga(postChargeSaga, postChargeDataMock)
+ .put(postChargeProcessing())
+ .call(postChargeStripe, postChargeDataMock.payload)
+ .put(postChargeComplete())
+ .call(setDonationCookie)
+ .put(executeGA(analyticsDataMock))
+ .run();
+ });
+
+ it('calls postChargeStripCard for Stripe Card', () => {
+ const stripeCardDataMock = {
+ payload: { ...postChargeDataMock.payload, paymentProvider: 'stripe card' }
+ };
+
+ const stripeCardAnalyticsDataMock = analyticsDataMock;
+ stripeCardAnalyticsDataMock.action =
+ 'Donate Page Stripe Card Payment Submission';
+
+ const { paymentMethodId, amount, duration } = stripeCardDataMock.payload;
+ const optimizedPayload = { paymentMethodId, amount, duration };
+ return expectSaga(postChargeSaga, stripeCardDataMock)
+ .put(postChargeProcessing())
+ .call(postChargeStripeCard, optimizedPayload)
+ .put(postChargeComplete())
+ .call(setDonationCookie)
+ .put(executeGA(stripeCardAnalyticsDataMock))
+ .run();
+ });
+
+ it('calls addDonate for Paypal if user signed in', () => {
+ const paypalDataMock = {
+ payload: { ...postChargeDataMock.payload, paymentProvider: 'paypal' }
+ };
+
+ const paypalAnalyticsDataMock = analyticsDataMock;
+ paypalAnalyticsDataMock.action = 'Donate Page Paypal Payment Submission';
+
+ const storeMock = {
+ app: {
+ appUsername: 'devuser'
+ }
+ };
+
+ const { amount, duration } = paypalDataMock.payload;
+ return expectSaga(postChargeSaga, paypalDataMock)
+ .withState(storeMock)
+ .put(postChargeProcessing())
+ .call(addDonation, { amount, duration })
+ .put(postChargeComplete())
+ .call(setDonationCookie)
+ .put(executeGA(paypalAnalyticsDataMock))
+ .run();
+ });
+
+ it('does not call addDonate for Paypal if user not signed in', () => {
+ const paypalDataMock = {
+ payload: { ...postChargeDataMock.payload, paymentProvider: 'paypal' }
+ };
+
+ const paypalAnalyticsDataMock = analyticsDataMock;
+ paypalAnalyticsDataMock.action = 'Donate Page Paypal Payment Submission';
+
+ const storeMock = {
+ app: {}
+ };
+
+ return expectSaga(postChargeSaga, paypalDataMock)
+ .withState(storeMock)
+ .put(postChargeProcessing())
+ .not.call.fn(addDonation)
+ .put(postChargeComplete())
+ .call(setDonationCookie)
+ .put(executeGA(paypalAnalyticsDataMock))
+ .run();
+ });
+
+ it('does not call api for Patreon', () => {
+ const patreonDataMock = {
+ payload: { ...postChargeDataMock.payload, paymentProvider: 'patreon' }
+ };
+
+ const patreonAnalyticsDataMock = analyticsDataMock;
+ patreonAnalyticsDataMock.action = 'Donate Page Patreon Payment Redirection';
+ patreonAnalyticsDataMock.event = 'donationrelated';
+ return expectSaga(postChargeSaga, patreonDataMock)
+ .not.call.fn(addDonation)
+ .not.call.fn(postChargeStripeCard)
+ .not.call.fn(postChargeStripe)
+ .put(executeGA(patreonAnalyticsDataMock))
+ .run();
+ });
+});
diff --git a/client/src/redux/fetch-user-saga.js b/client/src/redux/fetch-user-saga.js
index 6e9dadac818f31..826cccc06978ff 100644
--- a/client/src/redux/fetch-user-saga.js
+++ b/client/src/redux/fetch-user-saga.js
@@ -1,5 +1,5 @@
import { call, put, takeEvery } from 'redux-saga/effects';
-
+import store from 'store';
import { getSessionUser, getUserProfile } from '../utils/ajax';
import {
fetchProfileForUserComplete,
@@ -7,7 +7,7 @@ import {
fetchUserComplete,
fetchUserError
} from './actions';
-import { jwt } from './cookieValues';
+import { jwt } from './cookie-values';
function* fetchSessionUser() {
if (!jwt) {
@@ -19,6 +19,13 @@ function* fetchSessionUser() {
data: { user = {}, result = '', sessionMeta = {} }
} = yield call(getSessionUser);
const appUser = user[result] || {};
+
+ const [userId] = Object.keys(user);
+
+ const sound = user[userId].sound;
+
+ store.set('fcc-sound', sound);
+
yield put(
fetchUserComplete({ user: appUser, username: result, sessionMeta })
);
diff --git a/client/src/redux/ga-saga.js b/client/src/redux/ga-saga.js
index 9b94094a5168c2..98ef478479ef16 100644
--- a/client/src/redux/ga-saga.js
+++ b/client/src/redux/ga-saga.js
@@ -1,57 +1,34 @@
-/* eslint-disable camelcase */
-import { all, call, select, takeEvery } from 'redux-saga/effects';
-
-import { aBTestConfig } from '../../../config/donation-settings';
-import ga from '../analytics';
-import { emailToABVariant } from '../utils/A-B-tester';
-import {
- completedChallengesSelector,
- completionCountSelector,
- emailSelector,
- recentlyClaimedBlockSelector
-} from './selectors';
-
-const GaTypes = { event: ga.event, page: ga.pageview, modal: ga.modalview };
-
-function* callGaType({ payload: { type, data } }) {
- if (
- type === 'event' &&
- data.category.toLowerCase().includes('donation') &&
- aBTestConfig.isTesting
- ) {
- const email = yield select(emailSelector);
-
- // a b test results are only reported when user is signed in and has email
- if (email) {
- const completedChallengeTotal = yield select(completedChallengesSelector);
- const completedChallengeSession = yield select(completionCountSelector);
- let viewType = null;
-
- // set the modal type
- if (data.action.toLowerCase().includes('modal')) {
- const recentlyClaimedBlock = yield select(recentlyClaimedBlockSelector);
- viewType = recentlyClaimedBlock ? 'block' : 'progress';
+import { all, call, takeEvery } from 'redux-saga/effects';
+import TagManager from '../analytics';
+
+function* callGaType({
+ payload: { action, duration, amount, event, pagePath }
+}) {
+ if (event === 'pageview') {
+ yield call(TagManager.dataLayer, {
+ dataLayer: {
+ event,
+ pagePath
}
-
- const customDimensions = {
- // URL;
- dimension1: window.location.href,
- // Challenges_Completed_Session
- dimension2: completedChallengeSession,
- // Challenges_Completed_Total
- dimension3: completedChallengeTotal.length,
- // Test_Type
- dimension4: aBTestConfig.type,
- // Test_Variation
- dimension5: emailToABVariant(email).isVariantA ? 'A' : 'B',
- // View_Type
- dimension6: viewType
- };
- ga.set(customDimensions);
- }
+ });
+ } else if (event === 'donationview') {
+ yield call(TagManager.dataLayer, {
+ dataLayer: {
+ event,
+ action
+ }
+ });
+ } else {
+ // donation and donationrelated
+ yield call(TagManager.dataLayer, {
+ dataLayer: {
+ event,
+ action,
+ duration,
+ amount
+ }
+ });
}
-
- yield call(GaTypes[type], data);
}
export function* createGaSaga(types) {
diff --git a/client/src/redux/ga-saga.test.js b/client/src/redux/ga-saga.test.js
index 47c7026caa13d0..7911349727e04e 100644
--- a/client/src/redux/ga-saga.test.js
+++ b/client/src/redux/ga-saga.test.js
@@ -1,24 +1,21 @@
import { expectSaga } from 'redux-saga-test-plan';
-import ga from '../analytics';
+import TagManager from '../analytics';
import { actionTypes } from './action-types';
import { createGaSaga } from './ga-saga';
-
jest.mock('../analytics');
describe('ga-saga', () => {
it('calls GA after executeGA action', () => {
- const GaTypes = { event: ga.event, page: ga.pageview, modal: ga.modalview };
const mockEventPayload = {
- type: 'event',
- data: {
- category: 'Map Challenge Click',
- action: '/learn'
- }
+ action: 'Learn Donation Alert Click',
+ amount: 500,
+ duration: 'month',
+ event: 'donationrelated'
};
return (
expectSaga(createGaSaga, actionTypes)
// Assert that the `call` with expected paramater will eventually happen.
- .call(GaTypes.event, mockEventPayload.data)
+ .call(TagManager.dataLayer, { dataLayer: mockEventPayload })
// Dispatch any actions that the saga will `take`.
.dispatch({ type: actionTypes.executeGA, payload: mockEventPayload })
diff --git a/client/src/redux/index.js b/client/src/redux/index.js
index a87e06c2ce0180..a8679853f167ee 100644
--- a/client/src/redux/index.js
+++ b/client/src/redux/index.js
@@ -22,7 +22,7 @@ import { createShowCertSaga } from './show-cert-saga';
import updateCompleteEpic from './update-complete-epic';
import { createUserTokenSaga } from './user-token-saga';
-export const defaultFetchState = {
+const defaultFetchState = {
pending: true,
complete: false,
errored: false,
@@ -40,7 +40,7 @@ export const defaultDonationFormState = {
}
};
-export const initialState = {
+const initialState = {
appUsername: '',
recentlyClaimedBlock: null,
canRequestProgressDonation: true,
@@ -55,6 +55,10 @@ export const initialState = {
userFetchState: {
...defaultFetchState
},
+ allChallengesInfo: {
+ challengeEdges: [],
+ certificateNodes: []
+ },
userProfileFetchState: {
...defaultFetchState
},
@@ -122,11 +126,11 @@ export const reducer = handleActions(
...state,
donationFormState: { ...state.donationFormState, ...payload }
}),
- [actionTypes.addDonation]: state => ({
+ [actionTypes.postChargeProcessing]: state => ({
...state,
donationFormState: { ...defaultDonationFormState, processing: true }
}),
- [actionTypes.addDonationComplete]: state => {
+ [actionTypes.postChargeComplete]: state => {
const { appUsername } = state;
return {
...state,
@@ -141,55 +145,13 @@ export const reducer = handleActions(
donationFormState: { ...defaultDonationFormState, success: true }
};
},
- [actionTypes.addDonationError]: (state, { payload }) => ({
+ [actionTypes.postChargeError]: (state, { payload }) => ({
...state,
donationFormState: { ...defaultDonationFormState, error: payload }
}),
- [actionTypes.postChargeStripe]: state => ({
- ...state,
- donationFormState: { ...defaultDonationFormState, processing: true }
- }),
- [actionTypes.postChargeStripeComplete]: state => {
- const { appUsername } = state;
- return {
- ...state,
- user: {
- ...state.user,
- [appUsername]: {
- ...state.user[appUsername],
- isDonating: true
- }
- },
-
- donationFormState: { ...defaultDonationFormState, success: true }
- };
- },
- [actionTypes.postChargeStripeError]: (state, { payload }) => ({
+ [actionTypes.updateAllChallengesInfo]: (state, { payload }) => ({
...state,
- donationFormState: { ...defaultDonationFormState, error: payload }
- }),
- [actionTypes.postChargeStripeCard]: state => ({
- ...state,
- donationFormState: { ...defaultDonationFormState, processing: true }
- }),
- [actionTypes.postChargeStripeCardComplete]: state => {
- const { appUsername } = state;
- return {
- ...state,
- user: {
- ...state.user,
- [appUsername]: {
- ...state.user[appUsername],
- isDonating: true
- }
- },
-
- donationFormState: { ...defaultDonationFormState, success: true }
- };
- },
- [actionTypes.postChargeStripeCardError]: (state, { payload }) => ({
- ...state,
- donationFormState: { ...defaultDonationFormState, error: payload }
+ allChallengesInfo: { ...payload }
}),
[actionTypes.fetchUser]: state => ({
...state,
diff --git a/client/src/redux/prop-types.ts b/client/src/redux/prop-types.ts
index aed72b85469a71..062b201a3ebfe5 100644
--- a/client/src/redux/prop-types.ts
+++ b/client/src/redux/prop-types.ts
@@ -1,78 +1,8 @@
-import PropTypes from 'prop-types';
import { HandlerProps } from 'react-reflex';
import { SuperBlocks } from '../../../config/certification-settings';
import { Themes } from '../components/settings/theme';
import { certMap } from '../resources/cert-and-project-map';
-export const UserPropType = PropTypes.shape({
- about: PropTypes.string,
- completedChallenges: PropTypes.arrayOf(
- PropTypes.shape({
- id: PropTypes.string,
- solution: PropTypes.string,
- githubLink: PropTypes.string,
- challengeType: PropTypes.number,
- completedDate: PropTypes.number,
- challengeFiles: PropTypes.array
- })
- ),
- email: PropTypes.string,
- githubProfile: PropTypes.string,
- is2018DataVisCert: PropTypes.bool,
- isApisMicroservicesCert: PropTypes.bool,
- isBackEndCert: PropTypes.bool,
- isDataVisCert: PropTypes.bool,
- isEmailVerified: PropTypes.bool,
- isFrontEndCert: PropTypes.bool,
- isFrontEndLibsCert: PropTypes.bool,
- isFullStackCert: PropTypes.bool,
- isHonest: PropTypes.bool,
- isInfosecQaCert: PropTypes.bool,
- isQaCertV7: PropTypes.bool,
- isInfosecCertV7: PropTypes.bool,
- isJsAlgoDataStructCert: PropTypes.bool,
- isRelationalDatabaseCertV8: PropTypes.bool,
- isRespWebDesignCert: PropTypes.bool,
- isSciCompPyCertV7: PropTypes.bool,
- isDataAnalysisPyCertV7: PropTypes.bool,
- isMachineLearningPyCertV7: PropTypes.bool,
- linkedin: PropTypes.string,
- location: PropTypes.string,
- name: PropTypes.string,
- picture: PropTypes.string,
- points: PropTypes.number,
- portfolio: PropTypes.arrayOf(
- PropTypes.shape({
- id: PropTypes.string.isRequired,
- title: PropTypes.string,
- url: PropTypes.string,
- image: PropTypes.string,
- description: PropTypes.string
- })
- ),
- savedChallenges: PropTypes.arrayOf(
- PropTypes.shape({
- id: PropTypes.string,
- challengeFiles: PropTypes.array
- })
- ),
- sendQuincyEmail: PropTypes.bool,
- sound: PropTypes.bool,
- theme: PropTypes.string,
- keyboardShortcuts: PropTypes.bool,
- twitter: PropTypes.string,
- username: PropTypes.string,
- website: PropTypes.string
-});
-
-export const CurrentCertsPropType = PropTypes.arrayOf(
- PropTypes.shape({
- show: PropTypes.bool,
- title: PropTypes.string,
- certSlug: PropTypes.string
- })
-);
-
export type Steps = {
isHonest?: boolean;
currentCerts?: Array
;
@@ -96,7 +26,7 @@ export type MarkdownRemark = {
superBlock: SuperBlocks;
// TODO: make enum like superBlock
certification: string;
- title: typeof certMap[number]['title'];
+ title: (typeof certMap)[number]['title'];
};
headings: [
{
@@ -117,7 +47,11 @@ export type MarkdownRemark = {
};
};
-type Question = { text: string; answers: string[]; solution: number };
+type Question = {
+ text: string;
+ answers: string[];
+ solution: number;
+};
type Fields = { slug: string; blockName: string; tests: Test[] };
type Required = {
link: string;
@@ -185,6 +119,7 @@ export type ChallengeNode = {
isPrivate: boolean;
order: number;
question: Question;
+ assignments: string[];
required: Required[];
solutions: {
[T in FileKey]: FileKeyChallenge;
@@ -207,6 +142,19 @@ export type ChallengeNode = {
};
};
+export type CertificateNode = {
+ challenge: {
+ // TODO: use enum
+ certification: string;
+ tests: { id: string }[];
+ };
+};
+
+export type AllChallengesInfo = {
+ challengeEdges: { node: ChallengeNode }[];
+ certificateNodes: CertificateNode[];
+};
+
export type AllChallengeNode = {
edges: [
{
@@ -342,6 +290,7 @@ export type ChallengeMeta = {
block: string;
id: string;
introPath: string;
+ isFirstStep: boolean;
nextChallengePath: string;
prevChallengePath: string;
removeComments: boolean;
diff --git a/client/src/redux/rootEpic.js b/client/src/redux/root-epic.js
similarity index 84%
rename from client/src/redux/rootEpic.js
rename to client/src/redux/root-epic.js
index dd956348596234..81a0a6d771268e 100644
--- a/client/src/redux/rootEpic.js
+++ b/client/src/redux/root-epic.js
@@ -1,7 +1,7 @@
import { combineEpics } from 'redux-observable';
import { epics as challengeEpics } from '../templates/Challenges/redux';
-import { epics as appEpics } from './';
+import { epics as appEpics } from '.';
const rootEpic = combineEpics(...appEpics, ...challengeEpics);
diff --git a/client/src/redux/rootReducer.js b/client/src/redux/root-reducer.js
similarity index 95%
rename from client/src/redux/rootReducer.js
rename to client/src/redux/root-reducer.js
index 6c20a0672dd7d5..056083926f15b1 100644
--- a/client/src/redux/rootReducer.js
+++ b/client/src/redux/root-reducer.js
@@ -16,7 +16,7 @@ import {
import { ns as appNameSpace } from './action-types';
import { ns as settingsNameSpace, reducer as settings } from './settings';
import { FlashApp as flashNameSpace } from './types';
-import { reducer as app } from './';
+import { reducer as app } from '.';
export default combineReducers({
[appNameSpace]: app,
diff --git a/client/src/redux/rootSaga.js b/client/src/redux/root-saga.js
similarity index 89%
rename from client/src/redux/rootSaga.js
rename to client/src/redux/root-saga.js
index ec83d4a5b6ee1f..f2d293bebd311a 100644
--- a/client/src/redux/rootSaga.js
+++ b/client/src/redux/root-saga.js
@@ -3,7 +3,7 @@ import { all } from 'redux-saga/effects';
import { sagas as challengeSagas } from '../templates/Challenges/redux';
import errorSagas from './error-saga';
import { sagas as settingsSagas } from './settings';
-import { sagas as appSagas } from './';
+import { sagas as appSagas } from '.';
export default function* rootSaga() {
yield all([...errorSagas, ...appSagas, ...challengeSagas, ...settingsSagas]);
diff --git a/client/src/redux/save-challenge-saga.js b/client/src/redux/save-challenge-saga.js
index be0ad140992ff0..4c109abe4e7b0a 100644
--- a/client/src/redux/save-challenge-saga.js
+++ b/client/src/redux/save-challenge-saga.js
@@ -17,7 +17,7 @@ import {
import { saveChallengeComplete } from './actions';
import { savedChallengesSelector } from './selectors';
-export function* saveChallengeSaga() {
+function* saveChallengeSaga() {
const { id, challengeType } = yield select(challengeMetaSelector);
const { challengeFiles } = yield select(challengeDataSelector);
const savedChallenges = yield select(savedChallengesSelector);
diff --git a/client/src/redux/selectors.js b/client/src/redux/selectors.js
index e9a561d6067527..eb6c71697c5f22 100644
--- a/client/src/redux/selectors.js
+++ b/client/src/redux/selectors.js
@@ -1,5 +1,4 @@
import { SuperBlocks } from '../../../config/certification-settings';
-import { emailToABVariant } from '../utils/A-B-tester';
import { ns as MainApp } from './action-types';
export const savedChallengesSelector = state =>
@@ -13,13 +12,7 @@ export const currentChallengeIdSelector = state =>
state[MainApp].currentChallengeId;
export const emailSelector = state => userSelector(state).email;
-export const isVariantASelector = state => {
- const email = emailSelector(state);
- // if the user is not signed in and the user info is not available.
- // always return A the control variant
- if (!email) return true;
- return emailToABVariant(email).isVariantA;
-};
+
export const isDonatingSelector = state => userSelector(state).isDonating;
export const isOnlineSelector = state => state[MainApp].isOnline;
export const isServerOnlineSelector = state => state[MainApp].isServerOnline;
@@ -209,6 +202,8 @@ export const certificatesByNameSelector = username => state => {
};
export const userFetchStateSelector = state => state[MainApp].userFetchState;
+export const allChallengesInfoSelector = state =>
+ state[MainApp].allChallengesInfo;
export const userProfileFetchStateSelector = state =>
state[MainApp].userProfileFetchState;
export const usernameSelector = state => state[MainApp].appUsername;
@@ -217,5 +212,3 @@ export const userSelector = state => {
return state[MainApp].user[username] || {};
};
-
-export const sessionMetaSelector = state => state[MainApp].sessionMeta;
diff --git a/client/src/redux/types.ts b/client/src/redux/types.ts
index 0c56a1c4bd0735..0288b1363b56d0 100644
--- a/client/src/redux/types.ts
+++ b/client/src/redux/types.ts
@@ -49,17 +49,3 @@ interface DefaultDonationFormState {
success: boolean;
error: null | string;
}
-
-export const defaultFetchState = {
- pending: true,
- complete: false,
- errored: false,
- error: null
-};
-
-export const defaultDonationFormState = {
- redirecting: false,
- processing: false,
- success: false,
- error: ''
-};
diff --git a/client/src/resources/cert-and-project-map.ts b/client/src/resources/cert-and-project-map.ts
index 198d658fa35d6e..06b34efbe58f99 100644
--- a/client/src/resources/cert-and-project-map.ts
+++ b/client/src/resources/cert-and-project-map.ts
@@ -747,7 +747,7 @@ function getJavaScriptAlgoPath(project: string) {
}
const titles = certMap.map(({ title }) => title);
-type Title = typeof titles[number];
+type Title = (typeof titles)[number];
const legacyProjectMap: Partial> = {};
const projectMap: Partial> = {};
diff --git a/client/src/resources/honesty-policy.tsx b/client/src/resources/honesty-policy.tsx
index dea6b82c460441..2a3a3f489ed651 100644
--- a/client/src/resources/honesty-policy.tsx
+++ b/client/src/resources/honesty-policy.tsx
@@ -3,7 +3,7 @@ import { Trans, useTranslation } from 'react-i18next';
const HonestyPolicy = (): JSX.Element => {
const { t } = useTranslation();
- const email = 'team@freecodecamp.org';
+ const email = 'support@freecodecamp.org';
return (
<>
diff --git a/client/src/templates/Challenges/classic/classic.css b/client/src/templates/Challenges/classic/classic.css
index 62a31f1bfb17d3..77dd98535192d8 100644
--- a/client/src/templates/Challenges/classic/classic.css
+++ b/client/src/templates/Challenges/classic/classic.css
@@ -45,6 +45,11 @@
background-color: var(--tc-white) !important;
}
+.monaco-editor-tabs {
+ display: flex;
+ margin: 0;
+}
+
.monaco-editor .view-overlays .current-line {
width: auto !important;
right: 15px;
@@ -67,7 +72,7 @@
}
#mobile-layout .nav-tabs {
- margin-left: 2px;
+ margin-inline-start: 2px;
display: flex;
}
@@ -112,6 +117,27 @@
display: flex;
}
+#mobile-layout #mobile-layout-pane-instructions {
+ overflow-y: auto;
+}
+
+#mobile-layout-pane-instructions:focus-visible {
+ outline: 3px solid var(--blue-mid);
+ outline-offset: -2px;
+}
+
+@supports not selector(:focus-visible) {
+ #mobile-layout-pane-instructions:focus {
+ outline: 3px solid var(--blue-mid);
+ outline-offset: -2px;
+ }
+}
+
+#mobile-layout .nav-tabs > li.active > a {
+ color: var(--quaternary-color);
+ background-color: var(--quaternary-background);
+}
+
#mobile-layout .monaco-editor-tabs {
padding: 10px;
width: 100%;
diff --git a/client/src/templates/Challenges/classic/desktop-layout.tsx b/client/src/templates/Challenges/classic/desktop-layout.tsx
index 197ba8251006de..4db35ed76194a9 100644
--- a/client/src/templates/Challenges/classic/desktop-layout.tsx
+++ b/client/src/templates/Challenges/classic/desktop-layout.tsx
@@ -1,6 +1,8 @@
import { first } from 'lodash-es';
-import React, { ReactElement } from 'react';
+import React, { useState, useEffect, ReactElement } from 'react';
import { ReflexContainer, ReflexSplitter, ReflexElement } from 'react-reflex';
+import { createSelector } from 'reselect';
+import { connect } from 'react-redux';
import { sortChallengeFiles } from '../../../../../utils/sort-challengefiles';
import { GoogleTagManager } from '../../../analytics/google-tag-manater';
import { Segment } from '../../../analytics/segment';
@@ -9,6 +11,13 @@ import {
ChallengeFiles,
ResizeProps
} from '../../../redux/prop-types';
+import { setShowPreviewPortal, setShowPreviewPane } from '../redux/actions';
+import {
+ portalWindowSelector,
+ showPreviewPortalSelector,
+ showPreviewPaneSelector,
+ isAdvancingToChallengeSelector
+} from '../redux/selectors';
import PreviewPortal from '../components/preview-portal';
import ActionRow from './action-row';
import {
@@ -26,6 +35,8 @@ interface DesktopLayoutProps {
hasNotes: boolean;
hasPreview: boolean;
instructions: ReactElement;
+ isAdvancing: boolean;
+ isFirstStep: boolean;
layoutState: {
codePane: Pane;
editorPane: Pane;
@@ -40,23 +51,83 @@ interface DesktopLayoutProps {
testOutput: ReactElement;
visibleEditors: { [key: string]: boolean };
windowTitle: string;
+ showPreviewPortal: boolean;
+ showPreviewPane: boolean;
+ setShowPreviewPortal: (arg: boolean) => void;
+ setShowPreviewPane: (arg: boolean) => void;
+ portalWindow: null | Window;
}
const reflexProps = {
propagateDimensions: true
};
+const mapDispatchToProps = {
+ setShowPreviewPortal,
+ setShowPreviewPane
+};
+
+const mapStateToProps = createSelector(
+ isAdvancingToChallengeSelector,
+ showPreviewPortalSelector,
+ showPreviewPaneSelector,
+ portalWindowSelector,
+
+ (
+ isAdvancing: boolean,
+ showPreviewPortal: boolean,
+ showPreviewPane: boolean,
+ portalWindow: null | Window
+ ) => ({
+ isAdvancing,
+ showPreviewPortal,
+ showPreviewPane,
+ portalWindow
+ })
+);
+
const DesktopLayout = (props: DesktopLayoutProps): JSX.Element => {
const {
- layoutState: {
- showInstructions,
- showNotes,
- showPreviewPane,
- showPreviewPortal,
- showConsole
- },
- togglePane
- } = useDesktopLayoutState();
+ showPreviewPane,
+ showPreviewPortal,
+ setShowPreviewPane,
+ setShowPreviewPortal,
+ portalWindow
+ } = props;
+
+ const [showNotes, setShowNotes] = useState(false);
+ const [showConsole, setShowConsole] = useState(false);
+ const [showInstructions, setShowInstuctions] = useState(true);
+
+ const togglePane = (pane: string): void => {
+ switch (pane) {
+ case 'showPreviewPane':
+ if (!showPreviewPane && showPreviewPortal) setShowPreviewPortal(false);
+ setShowPreviewPane(!showPreviewPane);
+ portalWindow?.close();
+ break;
+ case 'showPreviewPortal':
+ if (!showPreviewPortal && showPreviewPane) setShowPreviewPane(false);
+ setShowPreviewPortal(!showPreviewPortal);
+ if (showPreviewPortal) portalWindow?.close();
+ break;
+ case 'showConsole':
+ setShowConsole(!showConsole);
+ break;
+ case 'showNotes':
+ setShowNotes(!showNotes);
+ break;
+ case 'showInstructions':
+ setShowInstuctions(!showInstructions);
+ break;
+ default:
+ setShowInstuctions(true);
+ setShowConsole(false);
+ setShowPreviewPane(true);
+ setShowPreviewPortal(false);
+ setShowNotes(false);
+ }
+ };
const getChallengeFile = () => {
const { challengeFiles } = props;
@@ -70,6 +141,8 @@ const DesktopLayout = (props: DesktopLayoutProps): JSX.Element => {
testOutput,
hasNotes,
hasPreview,
+ isAdvancing,
+ isFirstStep,
layoutState,
notes,
preview,
@@ -78,6 +151,18 @@ const DesktopLayout = (props: DesktopLayoutProps): JSX.Element => {
windowTitle
} = props;
+ // on mount
+ useEffect(() => {
+ if (isFirstStep) {
+ setShowPreviewPortal(false);
+ portalWindow?.close();
+ setShowPreviewPane(true);
+ } else if (!isAdvancing && !showPreviewPane && !showPreviewPortal) {
+ togglePane('showPreviewPane');
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
const challengeFile = getChallengeFile();
const projectBasedChallenge = hasEditableBoundaries;
const displayPreviewPane = hasPreview && showPreviewPane;
@@ -181,12 +266,12 @@ const DesktopLayout = (props: DesktopLayoutProps): JSX.Element => {
{displayPreviewPortal && (
{
- togglePane({
- panel: DesktopLayoutPanels.PreviewPortal,
- setVisible: false
- });
- }}
+ // togglePane={() => {
+ // togglePane({
+ // panel: DesktopLayoutPanels.PreviewPortal,
+ // setVisible: false
+ // });
+ // }}
windowTitle={windowTitle}
>
{preview}
@@ -198,4 +283,4 @@ const DesktopLayout = (props: DesktopLayoutProps): JSX.Element => {
DesktopLayout.displayName = 'DesktopLayout';
-export default DesktopLayout;
+export default connect(mapStateToProps, mapDispatchToProps)(DesktopLayout);
diff --git a/client/src/templates/Challenges/classic/editor.css b/client/src/templates/Challenges/classic/editor.css
index 0288f12dbf2269..7e70bab2ae72a7 100644
--- a/client/src/templates/Challenges/classic/editor.css
+++ b/client/src/templates/Challenges/classic/editor.css
@@ -66,7 +66,7 @@ textarea.inputarea {
}
.editor-lower-jaw {
- padding: 0 15px 15px 0px;
+ padding: 0 15px 15px 0;
}
.editor-upper-jaw {
@@ -81,14 +81,15 @@ textarea.inputarea {
.challenge-description-header {
display: flex;
+ gap: 7px;
}
.description-container h1 {
font-family: 'Hack-ZeroSlash', monospace;
font-size: 0.889rem;
font-weight: 700;
- line-height: 1;
- margin: 0 0 0.6rem;
+ line-height: 1.1;
+ margin: 0.1em 0 0.6rem;
display: flex;
align-items: center;
@@ -129,8 +130,7 @@ textarea.inputarea {
.myEditableLineDecoration {
background-color: var(--tc-blue-140);
width: 15px !important;
- margin-left: 5px !important;
- margin-right: 5px !important;
+ margin-inline: 5px !important;
}
.myEditableLineDecoration.tests-passed {
@@ -233,5 +233,5 @@ textarea.inputarea {
}
.lower-jaw-icon-bar > button:last-child {
- margin-right: 0;
+ margin-inline-end: 0;
}
diff --git a/client/src/templates/Challenges/classic/editor.tsx b/client/src/templates/Challenges/classic/editor.tsx
index 49b49cf851de73..590ddc4ccc1bbe 100644
--- a/client/src/templates/Challenges/classic/editor.tsx
+++ b/client/src/templates/Challenges/classic/editor.tsx
@@ -7,6 +7,7 @@ import type {
editor
// eslint-disable-next-line import/no-duplicates
} from 'monaco-editor/esm/vs/editor/editor.api';
+import { OS } from 'monaco-editor/esm/vs/base/common/platform.js';
import Prism from 'prismjs';
import React, {
useEffect,
@@ -74,7 +75,6 @@ import LowerJaw from './lower-jaw';
import './editor.css';
-// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
const MonacoEditor = Loadable(() => import('react-monaco-editor'));
const currentYear = new Date().getFullYear();
@@ -275,7 +275,6 @@ const Editor = (props: EditorProps): JSX.Element => {
noteIndex: number;
shouldPlay: boolean | undefined;
}>({
- // eslint-disable-next-line no-undefined
sampler: undefined,
noteIndex: 0,
shouldPlay: store.get('fcc-sound') as boolean | undefined
@@ -384,6 +383,14 @@ const Editor = (props: EditorProps): JSX.Element => {
}
};
+ const isTabTrapped = () => !!(store.get('monacoTabTrapped') ?? true);
+
+ // Monaco uses the contextKey 'editorTabMovesFocus' to control how it
+ // reacts to the Tab key. Setting it to true allows the user to tab
+ // out of the editor. False keeps it inside the editor and creates a tab.
+ const setMonacoTabTrapped = (trapped: boolean) =>
+ dataRef.current.editor?.createContextKey('editorTabMovesFocus', !trapped);
+
const editorDidMount = (
editor: editor.IStandaloneCodeEditor,
monaco: typeof monacoEditor
@@ -417,6 +424,24 @@ const Editor = (props: EditorProps): JSX.Element => {
return accessibility;
};
+ const setTabTrapped = (trapped: boolean) => {
+ setMonacoTabTrapped(trapped);
+ store.set('monacoTabTrapped', trapped);
+ ariaAlert(
+ `${
+ trapped
+ ? t('learn.editor-alerts.tab-trapped')
+ : t('learn.editor-alerts.tab-free')
+ }`
+ );
+ };
+
+ // By default, Tab will be trapped in the monaco editor, so we only need to
+ // check if the user has turned this off.
+ if (!isTabTrapped()) {
+ setTabTrapped(false);
+ }
+
const accessibilityMode = storedAccessibilityMode();
editor.updateOptions({
accessibilitySupport: accessibilityMode ? 'on' : 'auto'
@@ -462,11 +487,23 @@ const Editor = (props: EditorProps): JSX.Element => {
null,
() => {}
);
+ // Make toggle tab setting in editor permanent
+ const tabFocusHotkeys =
+ OS === 2 /* Macintosh/iOS */
+ ? monaco.KeyMod.WinCtrl | monaco.KeyMod.Shift | monaco.KeyCode.KEY_M
+ : monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_M;
+ // @ts-ignore
+ editor._standaloneKeybindingService.addDynamicKeybinding(
+ 'editor.action.toggleTabFocusMode',
+ tabFocusHotkeys,
+ () => {
+ setTabTrapped(!isTabTrapped());
+ }
+ );
/* eslint-enable */
editor.addAction({
id: 'execute-challenge',
label: 'Run tests',
- /* eslint-disable no-bitwise */
keybindings: [
monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter,
monaco.KeyMod.WinCtrl | monaco.KeyCode.Enter
@@ -709,14 +746,7 @@ const Editor = (props: EditorProps): JSX.Element => {
)}`;
jawHeading.appendChild(challengeTitle);
const checkmark = ReactDOMServer.renderToStaticMarkup(
-
+
);
const completedChallengeHeader = document.createElement('div');
completedChallengeHeader.innerHTML = checkmark;
@@ -803,12 +833,9 @@ const Editor = (props: EditorProps): JSX.Element => {
// has changed or if content is dragged between regions)
const coveringRange = getLinesCoveringEditableRegion();
- const editableRegionBoundaries =
- (coveringRange && [
- coveringRange.startLineNumber - 1,
- coveringRange.endLineNumber + 1
- ]) ??
- undefined;
+ const editableRegionBoundaries = coveringRange
+ ? [coveringRange.startLineNumber - 1, coveringRange.endLineNumber + 1]
+ : [];
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
if (player.current.sampler?.loaded && player.current.shouldPlay) {
@@ -1051,7 +1078,6 @@ const Editor = (props: EditorProps): JSX.Element => {
updateEditableRegion(coveringRange, { model });
}
};
-
// If the content has changed, the zones may need moving. Rather than
// working out if they have to for a particular content change, we simply
// ask monaco to update regardless.
@@ -1184,6 +1210,11 @@ const Editor = (props: EditorProps): JSX.Element => {
useEffect(() => {
const editor = dataRef.current.editor;
editor?.layout();
+ // layout() resets the monaco tab trapping back to default (true), so we
+ // need to untrap it if the user had it set to false.
+ if (!isTabTrapped()) {
+ setMonacoTabTrapped(false);
+ }
if (hasEditableRegion()) {
updateDescriptionZone();
updateOutputZone();
@@ -1199,10 +1230,15 @@ const Editor = (props: EditorProps): JSX.Element => {
});
}
- const { theme } = props;
- const editorTheme = theme === Themes.Night ? 'vs-dark-custom' : 'vs-custom';
+ const { isSignedIn, theme } = props;
+ const preferDarkScheme = window.matchMedia(
+ '(prefers-color-scheme: dark)'
+ ).matches;
+ const isDarkTheme =
+ theme === Themes.Night || (preferDarkScheme && !isSignedIn);
+ const editorTheme = isDarkTheme ? 'vs-dark-custom' : 'vs-custom';
return (
- }>
+ }>
{
currentTab: this.props.hasEditableBoundaries ? Tab.Editor : Tab.Instructions
};
- switchTab = (tab: Tab) => {
+ switchTab = (tab: Tab): void => {
this.setState({
currentTab: tab
});
};
- handleKeyDown = () => this.props.updateUsingKeyboardInTablist(true);
+ handleKeyDown = (): void => this.props.updateUsingKeyboardInTablist(true);
- handleClick = () => this.props.updateUsingKeyboardInTablist(false);
+ handleClick = (): void => this.props.updateUsingKeyboardInTablist(false);
- render() {
+ render(): JSX.Element {
const { currentTab } = this.state;
const {
hasEditableBoundaries,
diff --git a/client/src/templates/Challenges/classic/show.tsx b/client/src/templates/Challenges/classic/show.tsx
index 5acbb1cc6c9924..06b9292c862ee7 100644
--- a/client/src/templates/Challenges/classic/show.tsx
+++ b/client/src/templates/Challenges/classic/show.tsx
@@ -43,7 +43,8 @@ import {
previewMounted,
updateChallengeMeta,
openModal,
- setEditorFocusability
+ setEditorFocusability,
+ setIsAdvancing
} from '../redux/actions';
import {
visibleEditorsSelector,
@@ -89,7 +90,8 @@ const mapDispatchToProps = (dispatch: Dispatch) =>
cancelTests,
previewMounted,
openModal,
- setEditorFocusability
+ setEditorFocusability,
+ setIsAdvancing
},
dispatch
);
@@ -119,6 +121,7 @@ interface ShowClassicProps {
updateChallengeMeta: (arg0: ChallengeMeta) => void;
openModal: (modal: string) => void;
setEditorFocusability: (canFocus: boolean) => void;
+ setIsAdvancing: (arg: boolean) => void;
previewMounted: () => void;
savedChallenges: CompletedChallenge[];
visibleEditors: VisibleEditors;
@@ -300,6 +303,7 @@ class ShowClassic extends Component {
initTests,
updateChallengeMeta,
openModal,
+ setIsAdvancing,
savedChallenges,
data: {
challengeNode: {
@@ -335,6 +339,7 @@ class ShowClassic extends Component {
helpCategory
});
challengeMounted(challengeMeta.id);
+ setIsAdvancing(false);
}
componentWillUnmount() {
@@ -481,7 +486,8 @@ class ShowClassic extends Component {
const {
executeChallenge,
pageContext: {
- challengeMeta: { nextChallengePath, prevChallengePath }
+ challengeMeta: { isFirstStep, nextChallengePath, prevChallengePath },
+ projectPreview: { challengeData, showProjectPreview }
},
challengeFiles,
visibleEditors,
@@ -543,6 +549,7 @@ class ShowClassic extends Component {
instructions={this.renderInstructionsPanel({
showToolPanel: true
})}
+ isFirstStep={isFirstStep}
layoutState={this.state.layout}
notes={this.renderNotes(notes)}
preview={this.renderPreview()}
diff --git a/client/src/templates/Challenges/codeally/codeally.css b/client/src/templates/Challenges/codeally/codeally.css
index 87db255121618e..37cebb6822b0f8 100644
--- a/client/src/templates/Challenges/codeally/codeally.css
+++ b/client/src/templates/Challenges/codeally/codeally.css
@@ -2,14 +2,6 @@
font-family: 'Lato', sans-serif;
}
-.ca-btn-padding {
- padding: 0 15px;
-}
-
-.ca-btn-padding button {
+button[aria-described-by='codeally-cookie-warning'] {
font-size: 1.1rem;
}
-
-.ca-btn-margin {
- margin-bottom: 5px;
-}
diff --git a/client/src/templates/Challenges/codeally/show.tsx b/client/src/templates/Challenges/codeally/show.tsx
index 8b27e8cab2d1e4..bfa95dab6ab152 100644
--- a/client/src/templates/Challenges/codeally/show.tsx
+++ b/client/src/templates/Challenges/codeally/show.tsx
@@ -229,9 +229,6 @@ class ShowCodeAlly extends Component {
challenge => challenge.id === challengeId
);
- const breadcrumbs = document.querySelector('.breadcrumbs-demo');
- showCodeAlly && breadcrumbs?.remove();
-
return showCodeAlly ? (
@@ -239,7 +236,6 @@ class ShowCodeAlly extends Component {
className='codeally-frame'
data-cy='codeally-frame'
name={`codeAlly${Date.now()}`}
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
sandbox='allow-modals allow-forms allow-popups allow-scripts allow-same-origin'
src={`https://codeally.io/embed/?repoUrl=${url}&${goBackTo}&${envVariables}&${tempToken}&${date}`}
title='Editor'
@@ -293,7 +289,7 @@ class ShowCodeAlly extends Component {
style={{
height: '15px',
width: '15px',
- marginLeft: '7px'
+ marginInlineEnd: '7px'
}}
/>
)}
@@ -306,29 +302,20 @@ class ShowCodeAlly extends Component {
>
)}
-
+
{t(`intro:misc-text.enable-cookies`)}
+
+
-
- {t(`intro:misc-text.enable-cookies`)}
-
-
- {challengeType === challengeTypes.codeAllyCert
- ? t('buttons.click-start-project')
- : t('buttons.click-start-course')}
-
-
+ {challengeType === challengeTypes.codeAllyCert
+ ? t('buttons.click-start-project')
+ : t('buttons.click-start-course')}
+
{isSignedIn &&
challengeType === challengeTypes.codeAllyCert && (
<>
@@ -340,7 +327,7 @@ class ShowCodeAlly extends Component {
style={{
height: '15px',
width: '15px',
- marginLeft: '7px'
+ marginInlineStart: '7px'
}}
/>
)}
diff --git a/client/src/templates/Challenges/components/Hotkeys.tsx b/client/src/templates/Challenges/components/Hotkeys.tsx
index 5bc514b96e7f70..761ba839af557b 100644
--- a/client/src/templates/Challenges/components/Hotkeys.tsx
+++ b/client/src/templates/Challenges/components/Hotkeys.tsx
@@ -4,12 +4,14 @@ import { HotKeys, GlobalHotKeys } from 'react-hotkeys';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { ChallengeFiles, Test, User } from '../../../redux/prop-types';
+import { isChallenge } from '../../../utils/path-parsers';
import { userSelector } from '../../../redux/selectors';
import {
setEditorFocusability,
submitChallenge,
- openModal
+ openModal,
+ setIsAdvancing
} from '../redux/actions';
import {
canFocusEditorSelector,
@@ -40,7 +42,8 @@ const mapStateToProps = createSelector(
const mapDispatchToProps = {
setEditorFocusability,
submitChallenge,
- openShortcutsModal: () => openModal('shortcuts')
+ openShortcutsModal: () => openModal('shortcuts'),
+ setIsAdvancing
};
const keyMap = {
@@ -66,6 +69,7 @@ interface HotkeysProps {
nextChallengePath: string;
prevChallengePath: string;
setEditorFocusability: (arg0: boolean) => void;
+ setIsAdvancing: (arg0: boolean) => void;
tests: Test[];
usesMultifileEditor?: boolean;
openShortcutsModal: () => void;
@@ -83,6 +87,7 @@ function Hotkeys({
nextChallengePath,
prevChallengePath,
setEditorFocusability,
+ setIsAdvancing,
submitChallenge,
tests,
usesMultifileEditor,
@@ -130,10 +135,16 @@ function Hotkeys({
},
navigationMode: () => setEditorFocusability(false),
navigatePrev: () => {
- if (!canFocusEditor) void navigate(prevChallengePath);
+ if (!canFocusEditor) {
+ if (isChallenge(prevChallengePath)) setIsAdvancing(true);
+ void navigate(prevChallengePath);
+ }
},
navigateNext: () => {
- if (!canFocusEditor) void navigate(nextChallengePath);
+ if (!canFocusEditor) {
+ if (isChallenge(nextChallengePath)) setIsAdvancing(true);
+ void navigate(nextChallengePath);
+ }
},
showShortcuts: (e: React.KeyboardEvent) => {
if (!canFocusEditor && e.shiftKey && e.key === '?') {
diff --git a/client/src/templates/Challenges/components/ResetModal.tsx b/client/src/templates/Challenges/components/ResetModal.tsx
index 80db75daeb71cc..c0ec30d9223c85 100644
--- a/client/src/templates/Challenges/components/ResetModal.tsx
+++ b/client/src/templates/Challenges/components/ResetModal.tsx
@@ -48,7 +48,7 @@ function withActions(...fns: Array<() => void>) {
function ResetModal({ reset, close, isOpen }: ResetModalProps): JSX.Element {
const { t } = useTranslation();
if (isOpen) {
- executeGA({ type: 'modal', data: '/reset-modal' });
+ executeGA({ event: 'pageview', pagePath: '/reset-modal' });
}
return (
project.id === currentChallengeId
);
});
+
return (
<>
@@ -130,7 +131,7 @@ export class CompletionModalBody extends PureComponent<
- {isCertificationProject && (
+ {isCertificationProject && totalChallengesInBlock > 0 && (
{t('learn.project-complete', {
completedChallengesInBlock,
diff --git a/client/src/templates/Challenges/components/completion-modal.css b/client/src/templates/Challenges/components/completion-modal.css
index bd4ee5bda34f89..b62125c860b6df 100644
--- a/client/src/templates/Challenges/components/completion-modal.css
+++ b/client/src/templates/Challenges/components/completion-modal.css
@@ -16,7 +16,7 @@
display: flex;
flex-direction: column;
justify-content: space-evenly;
- padding-left: 30px;
+ padding-inline-start: 30px;
}
.completion-challenge-details {
diff --git a/client/src/templates/Challenges/components/completion-modal.test.tsx b/client/src/templates/Challenges/components/completion-modal.test.tsx
index 19aeb5efdccd7e..7d151bd0588dbe 100644
--- a/client/src/templates/Challenges/components/completion-modal.test.tsx
+++ b/client/src/templates/Challenges/components/completion-modal.test.tsx
@@ -1,4 +1,4 @@
-import { getCompletedPercent } from './completion-modal';
+import { getCompletedPercentage } from '../../../utils/get-completion-percentage';
jest.mock('../../../analytics');
@@ -8,16 +8,16 @@ const completedChallengesIds = ['1', '3', '5'],
fakeCompletedChallengesIds = ['1', '3', '5', '7', '8'];
describe(' ', () => {
- describe('getCompletedPercent', () => {
+ describe('getCompletedPercentage', () => {
it('returns 25 if one out of four challenges are complete', () => {
- expect(getCompletedPercent([], currentBlockIds, currentBlockIds[1])).toBe(
- 25
- );
+ expect(
+ getCompletedPercentage([], currentBlockIds, currentBlockIds[1])
+ ).toBe(25);
});
it('returns 75 if three out of four challenges are complete', () => {
expect(
- getCompletedPercent(
+ getCompletedPercentage(
completedChallengesIds,
currentBlockIds,
completedChallengesIds[0]
@@ -27,13 +27,13 @@ describe(' ', () => {
it('returns 100 if all challenges have been completed', () => {
expect(
- getCompletedPercent(completedChallengesIds, currentBlockIds, id)
+ getCompletedPercentage(completedChallengesIds, currentBlockIds, id)
).toBe(100);
});
it('returns 100 if more challenges have been complete than exist', () => {
expect(
- getCompletedPercent(fakeCompletedChallengesIds, currentBlockIds, id)
+ getCompletedPercentage(fakeCompletedChallengesIds, currentBlockIds, id)
).toBe(100);
});
});
diff --git a/client/src/templates/Challenges/components/completion-modal.tsx b/client/src/templates/Challenges/components/completion-modal.tsx
index 589863317fccca..dcf5ae24650431 100644
--- a/client/src/templates/Challenges/components/completion-modal.tsx
+++ b/client/src/templates/Challenges/components/completion-modal.tsx
@@ -1,7 +1,6 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/restrict-template-expressions */
import { Button, Modal } from '@freecodecamp/react-bootstrap';
-import { useStaticQuery, graphql } from 'gatsby';
import { noop } from 'lodash-es';
import React, { Component } from 'react';
import { TFunction, withTranslation } from 'react-i18next';
@@ -10,19 +9,23 @@ import { Dispatch } from 'redux';
import { createSelector } from 'reselect';
import { dasherize } from '../../../../../utils/slugs';
-import { isFinalProject } from '../../../../utils/challenge-types';
import Login from '../../../components/Header/components/Login';
import { executeGA } from '../../../redux/actions';
-import { isSignedInSelector } from '../../../redux/selectors';
-import { AllChallengeNode, ChallengeFiles } from '../../../redux/prop-types';
-
+import {
+ isSignedInSelector,
+ allChallengesInfoSelector
+} from '../../../redux/selectors';
+import { AllChallengesInfo, ChallengeFiles } from '../../../redux/prop-types';
import { closeModal, submitChallenge } from '../redux/actions';
import {
- completedChallengesIds,
+ completedChallengesIdsSelector,
isCompletionModalOpenSelector,
successMessageSelector,
challengeFilesSelector,
- challengeMetaSelector
+ challengeMetaSelector,
+ completedPercentageSelector,
+ completedChallengesInBlockSelector,
+ currentBlockIdsSelector
} from '../redux/selectors';
import CompletionModalBody from './completion-modal-body';
@@ -31,10 +34,14 @@ import './completion-modal.css';
const mapStateToProps = createSelector(
challengeFilesSelector,
challengeMetaSelector,
- completedChallengesIds,
+ completedChallengesIdsSelector,
isCompletionModalOpenSelector,
isSignedInSelector,
+ allChallengesInfoSelector,
successMessageSelector,
+ completedPercentageSelector,
+ completedChallengesInBlockSelector,
+ currentBlockIdsSelector,
(
challengeFiles: ChallengeFiles,
{
@@ -45,7 +52,11 @@ const mapStateToProps = createSelector(
completedChallengesIds: string[],
isOpen: boolean,
isSignedIn: boolean,
- message: string
+ allChallengesInfo: AllChallengesInfo,
+ message: string,
+ completedPercent: number,
+ completedChallengesInBlock: number,
+ currentBlockIds: string[]
) => ({
challengeFiles,
title,
@@ -54,7 +65,11 @@ const mapStateToProps = createSelector(
completedChallengesIds,
isOpen,
isSignedIn,
- message
+ allChallengesInfo,
+ message,
+ completedPercent,
+ completedChallengesInBlock,
+ currentBlockIds
})
);
@@ -69,38 +84,6 @@ const mapDispatchToProps = function (dispatch: Dispatch) {
return () => dispatchers;
};
-export function getCompletedPercent(
- completedChallengesIds: string[] = [],
- currentBlockIds: string[] = [],
- currentChallengeId: string
-): number {
- const completedChallengesInBlock = getCompletedChallengesInBlock(
- completedChallengesIds,
- currentBlockIds,
- currentChallengeId
- );
- const completedPercent = Math.round(
- (completedChallengesInBlock / currentBlockIds.length) * 100
- );
-
- return completedPercent > 100 ? 100 : completedPercent;
-}
-
-function getCompletedChallengesInBlock(
- completedChallengesIds: string[],
- currentBlockChallengeIds: string[],
- currentChallengeId: string
-) {
- const oldCompletionCount = completedChallengesIds.filter(challengeId =>
- currentBlockChallengeIds.includes(challengeId)
- ).length;
-
- const isAlreadyCompleted =
- completedChallengesIds.includes(currentChallengeId);
-
- return isAlreadyCompleted ? oldCompletionCount : oldCompletionCount + 1;
-}
-
interface CompletionModalsProps {
block: string;
blockName: string;
@@ -108,51 +91,47 @@ interface CompletionModalsProps {
challengeType: number;
close: () => void;
completedChallengesIds: string[];
- currentBlockIds?: string[];
executeGA: () => void;
challengeFiles: ChallengeFiles;
id: string;
isOpen: boolean;
isSignedIn: boolean;
+ allChallengesInfo: AllChallengesInfo;
message: string;
+ completedPercent: number;
+ completedChallengesInBlock: number;
+ currentBlockIds: string[];
submitChallenge: () => void;
superBlock: string;
t: TFunction;
title: string;
}
-interface CompletionModalInnerState {
+interface CompletionModalState {
downloadURL: null | string;
- completedPercent: number;
- completedChallengesInBlock: number;
}
-export class CompletionModalInner extends Component<
+class CompletionModal extends Component<
CompletionModalsProps,
- CompletionModalInnerState
+ CompletionModalState
> {
+ static displayName: string;
constructor(props: CompletionModalsProps) {
super(props);
- this.handleSubmit = this.handleSubmit.bind(this);
this.handleKeypress = this.handleKeypress.bind(this);
-
this.state = {
- downloadURL: null,
- completedPercent: 0,
- completedChallengesInBlock: 0
+ downloadURL: null
};
}
static getDerivedStateFromProps(
- props: CompletionModalsProps,
- state: CompletionModalInnerState
- ): CompletionModalInnerState {
+ props: Readonly,
+ state: CompletionModalState
+ ): CompletionModalState {
const { challengeFiles, isOpen } = props;
if (!isOpen) {
return {
- downloadURL: null,
- completedPercent: 0,
- completedChallengesInBlock: 0
+ downloadURL: null
};
}
const { downloadURL } = state;
@@ -177,25 +156,8 @@ export class CompletionModalInner extends Component<
});
newURL = URL.createObjectURL(blob);
}
-
- const { completedChallengesIds, currentBlockIds, id, isSignedIn } = props;
- const completedPercent = isSignedIn
- ? getCompletedPercent(completedChallengesIds, currentBlockIds, id)
- : 0;
-
- let completedChallengesInBlock = 0;
- if (currentBlockIds) {
- completedChallengesInBlock = getCompletedChallengesInBlock(
- completedChallengesIds,
- currentBlockIds,
- id
- );
- }
-
return {
- downloadURL: newURL,
- completedPercent,
- completedChallengesInBlock
+ downloadURL: newURL
};
}
@@ -205,14 +167,10 @@ export class CompletionModalInner extends Component<
// Since Hotkeys also listens to Ctrl + Enter we have to stop this event
// getting to it.
e.stopPropagation();
- this.handleSubmit();
+ this.props.submitChallenge();
}
}
- handleSubmit(): void {
- this.props.submitChallenge();
- }
-
componentWillUnmount(): void {
if (this.state.downloadURL) {
URL.revokeObjectURL(this.state.downloadURL);
@@ -224,22 +182,23 @@ export class CompletionModalInner extends Component<
const {
block,
close,
- currentBlockIds,
id,
isOpen,
isSignedIn,
message,
superBlock = '',
t,
- title
+ title,
+ completedPercent,
+ completedChallengesInBlock,
+ currentBlockIds,
+ submitChallenge
} = this.props;
- const { completedPercent, completedChallengesInBlock } = this.state;
-
- const totalChallengesInBlock = currentBlockIds?.length ?? 0;
+ const totalChallengesInBlock = currentBlockIds.length;
if (isOpen) {
- executeGA({ type: 'modal', data: '/completion-modal' });
+ executeGA({ event: 'pageview', pagePath: '/completion-modal' });
}
// normally dashedName should be graphQL queried and then passed around,
// but it's only used to make a nice filename for downloading, so dasherize
@@ -282,7 +241,7 @@ export class CompletionModalInner extends Component<
block={true}
bsSize='large'
bsStyle='primary'
- onClick={() => this.handleSubmit()}
+ onClick={() => submitChallenge()}
>
{isSignedIn ? t('buttons.submit-and-go') : t('buttons.go-to-next')}
(Ctrl + Enter)
@@ -305,84 +264,6 @@ export class CompletionModalInner extends Component<
}
}
-interface Options {
- isFinalProjectBlock: boolean;
-}
-
-interface CertificateNode {
- challenge: {
- // TODO: use enum
- certification: string;
- tests: { id: string }[];
- };
-}
-
-const useCurrentBlockIds = (
- block: string,
- certification: string,
- options?: Options
-) => {
- const {
- allChallengeNode: { edges: challengeEdges },
- allCertificateNode: { nodes: certificateNodes }
- }: {
- allChallengeNode: AllChallengeNode;
- allCertificateNode: { nodes: CertificateNode[] };
- } = useStaticQuery(graphql`
- query getCurrentBlockNodes {
- allChallengeNode(
- sort: {
- fields: [
- challenge___superOrder
- challenge___order
- challenge___challengeOrder
- ]
- }
- ) {
- edges {
- node {
- challenge {
- block
- id
- }
- }
- }
- }
- allCertificateNode {
- nodes {
- challenge {
- certification
- tests {
- id
- }
- }
- }
- }
- }
- `);
-
- const currentCertificateIds = certificateNodes
- .filter(
- node => dasherize(node.challenge.certification) === certification
- )[0]
- ?.challenge.tests.map(test => test.id);
- const currentBlockIds = challengeEdges
- .filter(edge => edge.node.challenge.block === block)
- .map(edge => edge.node.challenge.id);
-
- return options?.isFinalProjectBlock ? currentCertificateIds : currentBlockIds;
-};
-
-const CompletionModal = (props: CompletionModalsProps) => {
- const currentBlockIds = useCurrentBlockIds(
- props.block || '',
- props.certification || '',
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call
- { isFinalProjectBlock: isFinalProject(props.challengeType) }
- );
- return ;
-};
-
CompletionModal.displayName = 'CompletionModal';
export default connect(
diff --git a/client/src/templates/Challenges/components/help-modal.tsx b/client/src/templates/Challenges/components/help-modal.tsx
index 66ed57101aa088..15cd27ea7ff1b9 100644
--- a/client/src/templates/Challenges/components/help-modal.tsx
+++ b/client/src/templates/Challenges/components/help-modal.tsx
@@ -16,7 +16,7 @@ import './help-modal.css';
interface HelpModalProps {
closeHelpModal: () => void;
createQuestion: () => void;
- executeGA: (attributes: { type: string; data: string }) => void;
+ executeGA: (attributes: { event: string; pagePath: string }) => void;
isOpen?: boolean;
t: (text: string) => string;
challengeTitle: string;
@@ -44,7 +44,7 @@ const generateSearchLink = (title: string, block: string) => {
return search;
};
-export function HelpModal({
+function HelpModal({
closeHelpModal,
createQuestion,
executeGA,
@@ -54,7 +54,7 @@ export function HelpModal({
challengeTitle
}: HelpModalProps): JSX.Element {
if (isOpen) {
- executeGA({ type: 'modal', data: '/help-modal' });
+ executeGA({ event: 'pageview', pagePath: '/help-modal' });
}
return (
diff --git a/client/src/templates/Challenges/components/preview-portal.tsx b/client/src/templates/Challenges/components/preview-portal.tsx
index 4710cf0dc8e16e..366fa68cff28bb 100644
--- a/client/src/templates/Challenges/components/preview-portal.tsx
+++ b/client/src/templates/Challenges/components/preview-portal.tsx
@@ -2,35 +2,60 @@ import { Component, ReactElement } from 'react';
import ReactDOM from 'react-dom';
import { TFunction, withTranslation } from 'react-i18next';
import { connect } from 'react-redux';
-import { storePortalDocument, removePortalDocument } from '../redux/actions';
+import { createSelector } from 'reselect';
+import {
+ storePortalWindow,
+ removePortalWindow,
+ setShowPreviewPortal,
+ setIsAdvancing
+} from '../redux/actions';
+import {
+ portalWindowSelector,
+ isAdvancingToChallengeSelector
+} from '../redux/selectors';
interface PreviewPortalProps {
children: ReactElement | null;
- togglePane: (pane: string) => void;
windowTitle: string;
t: TFunction;
- storePortalDocument: (document: Document | undefined) => void;
- removePortalDocument: () => void;
+ storePortalWindow: (window: Window | null) => void;
+ removePortalWindow: () => void;
+ portalWindow: null | Window;
+ setShowPreviewPortal: (arg: boolean) => void;
+ setIsAdvancing: (arg: boolean) => void;
+ isAdvancing: boolean;
}
const mapDispatchToProps = {
- storePortalDocument,
- removePortalDocument
+ storePortalWindow,
+ removePortalWindow,
+ setShowPreviewPortal,
+ setIsAdvancing
};
+const mapStateToProps = createSelector(
+ isAdvancingToChallengeSelector,
+ portalWindowSelector,
+ (isAdvancing: boolean, portalWindow: null | Window) => ({
+ isAdvancing,
+ portalWindow
+ })
+);
+
class PreviewPortal extends Component {
static displayName = 'PreviewPortal';
mainWindow: Window;
externalWindow: Window | null = null;
+ isAdvancing: boolean;
containerEl;
titleEl;
styleEl;
constructor(props: PreviewPortalProps) {
super(props);
-
this.mainWindow = window;
- this.externalWindow = null;
+ this.externalWindow = this.props.portalWindow;
+ this.isAdvancing = this.props.isAdvancing;
this.containerEl = document.createElement('div');
this.titleEl = document.createElement('title');
this.styleEl = document.createElement('style');
@@ -39,6 +64,17 @@ class PreviewPortal extends Component {
componentDidMount() {
const { t, windowTitle } = this.props;
+ if (!this.externalWindow) {
+ this.externalWindow = window.open(
+ '',
+ '',
+ 'width=960,height=540,left=100,top=100'
+ );
+ } else {
+ this.externalWindow.document.head.innerHTML = '';
+ this.externalWindow.document.body.innerHTML = '';
+ }
+
this.titleEl.innerText = `${t(
'learn.editor-tabs.preview'
)} | ${windowTitle}`;
@@ -51,12 +87,6 @@ class PreviewPortal extends Component {
}
`;
- this.externalWindow = window.open(
- '',
- '',
- 'width=960,height=540,left=100,top=100'
- );
-
this.externalWindow?.document.head.appendChild(this.titleEl);
this.externalWindow?.document.head.appendChild(this.styleEl);
this.externalWindow?.document.body.setAttribute(
@@ -69,19 +99,23 @@ class PreviewPortal extends Component {
);
this.externalWindow?.document.body.appendChild(this.containerEl);
this.externalWindow?.addEventListener('beforeunload', () => {
- this.props.togglePane('showPreviewPortal');
+ this.props.setShowPreviewPortal(false);
});
- this.props.storePortalDocument(this.externalWindow?.document);
+ this.props.storePortalWindow(this.externalWindow);
+ // close the portal if the main window closes
this.mainWindow?.addEventListener('beforeunload', () => {
this.externalWindow?.close();
});
}
componentWillUnmount() {
- this.externalWindow?.close();
- this.props.removePortalDocument();
+ if (!this.props.isAdvancing) {
+ this.externalWindow?.close();
+ }
+ this.props.removePortalWindow();
+ this.props.setIsAdvancing(false);
}
render() {
@@ -92,6 +126,6 @@ class PreviewPortal extends Component {
PreviewPortal.displayName = 'PreviewPortal';
export default connect(
- null,
+ mapStateToProps,
mapDispatchToProps
)(withTranslation()(PreviewPortal));
diff --git a/client/src/templates/Challenges/components/shortcuts-modal.tsx b/client/src/templates/Challenges/components/shortcuts-modal.tsx
index 629a59adff0117..6d882f026444a3 100644
--- a/client/src/templates/Challenges/components/shortcuts-modal.tsx
+++ b/client/src/templates/Challenges/components/shortcuts-modal.tsx
@@ -37,7 +37,7 @@ const mapDispatchToProps = (dispatch: Dispatch) =>
dispatch
);
-export function ShortcutsModal({
+function ShortcutsModal({
closeShortcutsModal,
toggleKeyboardShortcuts,
isOpen,
diff --git a/client/src/templates/Challenges/components/side-panel.css b/client/src/templates/Challenges/components/side-panel.css
index 4e15f7c07015fd..e0347eaaebad5c 100644
--- a/client/src/templates/Challenges/components/side-panel.css
+++ b/client/src/templates/Challenges/components/side-panel.css
@@ -59,3 +59,9 @@
background: var(--tc-black-5);
border-radius: 4px;
}
+
+/* MERGE */
+#mobile-layout-pane-instructions > .instructions-panel {
+ height: auto;
+ overflow-y: none;
+}
diff --git a/client/src/templates/Challenges/components/test-suite.css b/client/src/templates/Challenges/components/test-suite.css
index 20753a5aed13ab..51c0151deb92f6 100644
--- a/client/src/templates/Challenges/components/test-suite.css
+++ b/client/src/templates/Challenges/components/test-suite.css
@@ -4,7 +4,7 @@
flex-direction: column;
margin: 6px 0 16px;
margin: 15px 0;
- padding-left: 0;
+ padding-inline-start: 0;
}
.challenge-test-suite-heading {
diff --git a/client/src/templates/Challenges/components/tool-panel.tsx b/client/src/templates/Challenges/components/tool-panel.tsx
index a07cf61498dc15..412ec93096e568 100644
--- a/client/src/templates/Challenges/components/tool-panel.tsx
+++ b/client/src/templates/Challenges/components/tool-panel.tsx
@@ -108,8 +108,13 @@ function ToolPanel({
)}
{/* {challengeType !== challengeTypes.multifileCertProject && (
-
- {isMobile ? t('buttons.reset') : t('buttons.reset-code')}
+
+ {isMobile ? t('buttons.reset') : t('buttons.reset-lesson')}
)} */}
diff --git a/client/src/templates/Challenges/components/video-modal.tsx b/client/src/templates/Challenges/components/video-modal.tsx
index 1b42eeff8c8775..2ceba3ac9db6d1 100644
--- a/client/src/templates/Challenges/components/video-modal.tsx
+++ b/client/src/templates/Challenges/components/video-modal.tsx
@@ -12,7 +12,7 @@ import './video-modal.css';
interface VideoModalProps {
closeVideoModal: () => void;
- executeGA: (attributes: { type: string; data: string }) => void;
+ executeGA: (attributes: { event: string; pagePath: string }) => void;
isOpen?: boolean;
t: (attribute: string) => string;
videoUrl?: string;
@@ -28,7 +28,7 @@ const mapDispatchToProps = (dispatch: Dispatch) =>
dispatch
);
-export function VideoModal({
+function VideoModal({
closeVideoModal,
executeGA,
isOpen,
@@ -36,7 +36,7 @@ export function VideoModal({
videoUrl
}: VideoModalProps): JSX.Element {
if (isOpen) {
- executeGA({ type: 'modal', data: '/completion-modal' });
+ executeGA({ event: 'pageview', pagePath: '/completion-modal' });
}
return (
diff --git a/client/src/templates/Challenges/odin/Show.tsx b/client/src/templates/Challenges/odin/Show.tsx
new file mode 100644
index 00000000000000..10e2558c9b1484
--- /dev/null
+++ b/client/src/templates/Challenges/odin/Show.tsx
@@ -0,0 +1,420 @@
+// Package Utilities
+import { Button, Grid, Col, Row } from '@freecodecamp/react-bootstrap';
+import { graphql } from 'gatsby';
+import React, { Component } from 'react';
+import Helmet from 'react-helmet';
+import { ObserveKeys } from 'react-hotkeys';
+import { TFunction, withTranslation } from 'react-i18next';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
+import type { Dispatch } from 'redux';
+import { createSelector } from 'reselect';
+
+// Local Utilities
+import Loader from '../../../components/helpers/loader';
+import Spacer from '../../../components/helpers/spacer';
+import LearnLayout from '../../../components/layouts/learn';
+import { ChallengeNode, ChallengeMeta } from '../../../redux/prop-types';
+import Hotkeys from '../components/Hotkeys';
+import VideoPlayer from '../components/VideoPlayer';
+import CompletionModal from '../components/completion-modal';
+import PrismFormatted from '../components/prism-formatted';
+import {
+ challengeMounted,
+ updateChallengeMeta,
+ openModal,
+ updateSolutionFormValues
+} from '../redux/actions';
+import { isChallengeCompletedSelector } from '../redux/selectors';
+
+// Styles
+import './show.css';
+import '../video.css';
+
+// Redux Setup
+const mapStateToProps = createSelector(
+ isChallengeCompletedSelector,
+ (isChallengeCompleted: boolean) => ({
+ isChallengeCompleted
+ })
+);
+const mapDispatchToProps = (dispatch: Dispatch) =>
+ bindActionCreators(
+ {
+ updateChallengeMeta,
+ challengeMounted,
+ updateSolutionFormValues,
+ openCompletionModal: () => openModal('completion')
+ },
+ dispatch
+ );
+
+// Types
+interface ShowOdinProps {
+ challengeMounted: (arg0: string) => void;
+ data: { challengeNode: ChallengeNode };
+ description: string;
+ isChallengeCompleted: boolean;
+ openCompletionModal: () => void;
+ pageContext: {
+ challengeMeta: ChallengeMeta;
+ };
+ t: TFunction;
+ updateChallengeMeta: (arg0: ChallengeMeta) => void;
+ updateSolutionFormValues: () => void;
+}
+
+interface ShowOdinState {
+ subtitles: string;
+ downloadURL: string | null;
+ selectedOption: number | null;
+ answer: number;
+ isWrongAnswer: boolean;
+ assignmentsCompleted: number;
+ allAssignmentsCompleted: boolean;
+ videoIsLoaded: boolean;
+}
+
+// Component
+class ShowOdin extends Component {
+ static displayName: string;
+ private _container: HTMLElement | null | undefined;
+
+ constructor(props: ShowOdinProps) {
+ super(props);
+ this.state = {
+ subtitles: '',
+ downloadURL: null,
+ selectedOption: null,
+ answer: 1,
+ isWrongAnswer: false,
+ assignmentsCompleted: 0,
+ allAssignmentsCompleted: false,
+ videoIsLoaded: false
+ };
+
+ this.handleSubmit = this.handleSubmit.bind(this);
+ }
+
+ componentDidMount(): void {
+ const {
+ challengeMounted,
+ data: {
+ challengeNode: {
+ challenge: { title, challengeType, helpCategory }
+ }
+ },
+ pageContext: { challengeMeta },
+ updateChallengeMeta
+ } = this.props;
+ updateChallengeMeta({
+ ...challengeMeta,
+ title,
+ challengeType,
+ helpCategory
+ });
+ challengeMounted(challengeMeta.id);
+ this._container?.focus();
+ }
+
+ componentDidUpdate(prevProps: ShowOdinProps): void {
+ const {
+ data: {
+ challengeNode: {
+ challenge: { title: prevTitle }
+ }
+ }
+ } = prevProps;
+ const {
+ challengeMounted,
+ data: {
+ challengeNode: {
+ challenge: { title: currentTitle, challengeType, helpCategory }
+ }
+ },
+ pageContext: { challengeMeta },
+ updateChallengeMeta
+ } = this.props;
+ if (prevTitle !== currentTitle) {
+ updateChallengeMeta({
+ ...challengeMeta,
+ title: currentTitle,
+ challengeType,
+ helpCategory
+ });
+ challengeMounted(challengeMeta.id);
+ }
+ }
+
+ handleSubmit(
+ solution: number,
+ openCompletionModal: () => void,
+ assignments: string[]
+ ) {
+ const hasAssignments = assignments.length > 0;
+ const completed = this.state.allAssignmentsCompleted;
+ const isCorrect = solution - 1 === this.state.selectedOption;
+
+ if (isCorrect) {
+ this.setState({
+ isWrongAnswer: false
+ });
+ if (!hasAssignments || completed) openCompletionModal();
+ } else {
+ this.setState({
+ isWrongAnswer: true
+ });
+ }
+ }
+
+ handleOptionChange = (
+ changeEvent: React.ChangeEvent
+ ): void => {
+ this.setState({
+ isWrongAnswer: false,
+ selectedOption: parseInt(changeEvent.target.value, 10)
+ });
+ };
+
+ handleAssignmentChange = (
+ event: React.ChangeEvent,
+ totalAssignments: number
+ ): void => {
+ const assignmentsCompleted = event.target.checked
+ ? this.state.assignmentsCompleted + 1
+ : this.state.assignmentsCompleted - 1;
+ const allAssignmentsCompleted = totalAssignments === assignmentsCompleted;
+
+ this.setState({
+ assignmentsCompleted,
+ allAssignmentsCompleted
+ });
+ };
+
+ onVideoLoad = () => {
+ this.setState({
+ videoIsLoaded: true
+ });
+ };
+
+ render() {
+ const {
+ data: {
+ challengeNode: {
+ challenge: {
+ fields: { blockName },
+ title,
+ description,
+ superBlock,
+ certification,
+ block,
+ videoId,
+ videoLocaleIds,
+ bilibiliIds,
+ question: { text, answers, solution },
+ assignments
+ }
+ }
+ },
+ openCompletionModal,
+ pageContext: {
+ challengeMeta: { nextChallengePath, prevChallengePath }
+ },
+ t
+ } = this.props;
+
+ const blockNameTitle = `${t(
+ `intro:${superBlock}.blocks.${block}.title`
+ )} - ${title}`;
+ return (
+ {
+ this.handleSubmit(solution, openCompletionModal, assignments);
+ }}
+ innerRef={(c: HTMLElement | null) => (this._container = c)}
+ nextChallengePath={nextChallengePath}
+ prevChallengePath={prevChallengePath}
+ >
+
+
+
+
+ {videoId && (
+
+
+
+ {!this.state.videoIsLoaded ? (
+
+
+
+ ) : null}
+
+
+
+ )}
+
+
+ {title}
+
+
+
+ {assignments.length > 0 && (
+ <>
+ {t('learn.assignments')}
+ {' '}
+
+ >
+ )}
+
+ {t('learn.question')}
+
+
+
+
+
+ {this.state.isWrongAnswer && (
+ {t('learn.wrong-answer')}
+ )}
+ {!this.state.allAssignmentsCompleted &&
+ assignments.length > 0 && (
+ <>
+
+ {t('learn.assignment-not-complete')}
+ >
+ )}
+
+
+
+ this.handleSubmit(
+ solution,
+ openCompletionModal,
+ assignments
+ )
+ }
+ >
+ {t('buttons.check-answer')}
+
+
+
+
+
+
+
+
+ );
+ }
+}
+
+ShowOdin.displayName = 'ShowOdin';
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(withTranslation()(ShowOdin));
+
+export const query = graphql`
+ query TheOdinProject($slug: String!) {
+ challengeNode(challenge: { fields: { slug: { eq: $slug } } }) {
+ challenge {
+ videoId
+ videoLocaleIds {
+ espanol
+ italian
+ portuguese
+ }
+ bilibiliIds {
+ aid
+ bvid
+ cid
+ }
+ title
+ description
+ challengeType
+ helpCategory
+ superBlock
+ certification
+ block
+ fields {
+ blockName
+ slug
+ }
+ question {
+ text
+ answers
+ solution
+ }
+ translationPending
+ assignments
+ }
+ }
+ }
+`;
diff --git a/client/src/templates/Challenges/odin/show.css b/client/src/templates/Challenges/odin/show.css
new file mode 100644
index 00000000000000..8db116b549910a
--- /dev/null
+++ b/client/src/templates/Challenges/odin/show.css
@@ -0,0 +1,28 @@
+input[type='checkbox'] {
+ display: grid;
+ place-content: center;
+ -webkit-appearance: none;
+ appearance: none;
+ background-color: #fff;
+ min-width: 1.15em;
+ min-height: 1.15em;
+ max-width: 1.15em;
+ max-height: 1.15em;
+ margin-inline-end: 15px;
+ border: 2px solid black;
+ border-radius: 0.15em;
+ transform: translateY(-0.075em);
+}
+
+input[type='checkbox']::before {
+ content: '';
+ width: 0.65em;
+ height: 0.65em;
+ transform: scale(0);
+ transition: 120ms transform ease-in-out;
+ box-shadow: inset 1em 1em black;
+}
+
+input[type='checkbox']:checked::before {
+ transform: scale(1);
+}
diff --git a/client/src/templates/Challenges/projects/backend/Show.tsx b/client/src/templates/Challenges/projects/backend/Show.tsx
index 6738baeb983a20..2ce24b84c04a9f 100644
--- a/client/src/templates/Challenges/projects/backend/Show.tsx
+++ b/client/src/templates/Challenges/projects/backend/Show.tsx
@@ -6,7 +6,8 @@ import { Col, Grid, Row } from '@freecodecamp/react-bootstrap';
import { graphql } from 'gatsby';
import React, { Component } from 'react';
import Helmet from 'react-helmet';
-import { TFunction, withTranslation } from 'react-i18next';
+import { withTranslation } from 'react-i18next';
+import type { TFunction } from 'i18next';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
diff --git a/client/src/templates/Challenges/projects/solution-form.tsx b/client/src/templates/Challenges/projects/solution-form.tsx
index 0f7a5cc1afda9b..19d554b052541a 100644
--- a/client/src/templates/Challenges/projects/solution-form.tsx
+++ b/client/src/templates/Challenges/projects/solution-form.tsx
@@ -9,13 +9,16 @@ import {
frontEndProject,
pythonProject
} from '../../../../utils/challenge-types';
-import { Form, ValidatedValues } from '../../../components/formHelpers';
+import {
+ StrictSolutionForm,
+ ValidatedValues
+} from '../../../components/formHelpers/form';
interface SubmitProps {
completed: boolean;
}
-interface FormProps extends WithTranslation {
+interface SolutionFormProps extends WithTranslation {
buttonLabel?: string;
challengeType: number;
description?: string;
@@ -23,8 +26,8 @@ interface FormProps extends WithTranslation {
updateSolutionForm: (arg0: Record) => void;
}
-export class SolutionForm extends Component {
- constructor(props: FormProps) {
+export class SolutionForm extends Component {
+ constructor(props: SolutionFormProps) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
@@ -116,7 +119,7 @@ export class SolutionForm extends Component {
}
return (
-
)}
@@ -139,8 +140,6 @@ const CertChallenge = ({
CertChallenge.displayName = 'CertChallenge';
-export { CertChallenge };
-
export default connect(
mapStateToProps,
mapDispatchToProps
diff --git a/client/src/templates/Introduction/components/challenges.tsx b/client/src/templates/Introduction/components/challenges.tsx
index 6686cf863f7a84..0e28ae015296ae 100644
--- a/client/src/templates/Introduction/components/challenges.tsx
+++ b/client/src/templates/Introduction/components/challenges.tsx
@@ -9,7 +9,6 @@ import GreenNotCompleted from '../../../assets/icons/green-not-completed';
import GreenPass from '../../../assets/icons/green-pass';
import { executeGA } from '../../../redux/actions';
import { SuperBlocks } from '../../../../../config/certification-settings';
-import { ExecuteGaArg } from '../../../pages/donate';
import { ChallengeWithCompletedNode } from '../../../redux/prop-types';
import { isNewJsCert, isNewRespCert } from '../../../utils/is-a-cert';
@@ -18,7 +17,6 @@ const mapDispatchToProps = (dispatch: Dispatch) =>
interface Challenges {
challengesWithCompleted: ChallengeWithCompletedNode[];
- executeGA: (payload: ExecuteGaArg) => void;
isProjectBlock: boolean;
superBlock: SuperBlocks;
blockTitle?: string | null;
@@ -26,20 +24,11 @@ interface Challenges {
function Challenges({
challengesWithCompleted,
- executeGA,
isProjectBlock,
superBlock,
blockTitle
}: Challenges): JSX.Element {
const { t } = useTranslation();
- const handleChallengeClick = (slug: string) =>
- executeGA({
- type: 'event',
- data: {
- category: 'Map Challenge Click',
- action: slug
- }
- });
const renderCheckMark = (isCompleted: boolean) =>
isCompleted ? : ;
@@ -60,9 +49,6 @@ function Challenges({
- handleChallengeClick(firstIncompleteChallenge.fields.slug)
- }
to={firstIncompleteChallenge.fields.slug}
>
{!isChallengeStarted
@@ -88,7 +74,6 @@ function Challenges({
>
{!isProjectBlock ? (
handleChallengeClick(challenge.fields.slug)}
to={challenge.fields.slug}
className={`map-grid-item ${
+challenge.isCompleted ? 'challenge-completed' : ''
@@ -103,10 +88,7 @@ function Challenges({
) : (
-
handleChallengeClick(challenge.fields.slug)}
- to={challenge.fields.slug}
- >
+
{challenge.title}
{renderCheckMark(challenge.isCompleted)}
@@ -129,20 +111,14 @@ function Challenges({
key={'map-challenge' + challenge.fields.slug}
>
{!isProjectBlock ? (
- handleChallengeClick(challenge.fields.slug)}
- to={challenge.fields.slug}
- >
+
{renderCheckMark(challenge.isCompleted)}
{challenge.title}
) : (
- handleChallengeClick(challenge.fields.slug)}
- to={challenge.fields.slug}
- >
+
{challenge.title}
{renderCheckMark(challenge.isCompleted)}
diff --git a/client/src/templates/Introduction/intro.css b/client/src/templates/Introduction/intro.css
index 016f53495669a1..615557a8960595 100644
--- a/client/src/templates/Introduction/intro.css
+++ b/client/src/templates/Introduction/intro.css
@@ -80,7 +80,8 @@ a.cert-tag:active {
display: flex;
flex-direction: column;
justify-content: center;
- padding: 25px 15px 10px 0;
+ padding-block: 10px 25px;
+ padding-inline: 0 15px;
margin: 0 0 0.6rem;
flex-grow: 2;
flex-basis: 0;
@@ -122,7 +123,7 @@ a.cert-tag:active {
padding: 18px 0;
background: transparent;
border: none;
- text-align: left;
+ text-align: start;
width: 100%;
}
@@ -147,7 +148,7 @@ button.map-title {
}
.map-project-checkmark {
- padding-left: 15px;
+ padding-inline-start: 15px;
}
.block .map-cert-title {
@@ -184,7 +185,8 @@ button.map-title {
.map-cert-title > h3 {
font-size: 1.17rem;
- margin: 0 0 0 15px;
+ margin-block: 0;
+ margin-inline: 15px 0;
}
.map-cert-title > svg {
@@ -199,15 +201,15 @@ button.map-title {
}
.map-title-completed {
- margin-left: auto;
+ margin-inline-start: auto;
min-width: 100px;
- padding-left: 20px;
+ padding-inline-start: 20px;
}
.map-title-completed-big {
- margin-left: auto;
- padding-right: 15px;
- padding-left: 20px;
+ margin-inline-start: auto;
+ padding-inline-end: 15px;
+ padding-inline-start: 20px;
position: relative;
top: 4px;
}
@@ -225,7 +227,7 @@ button.map-title {
.block-grid .map-title > svg:last-child {
transform: rotate(180deg);
- margin-left: auto;
+ margin-inline-start: auto;
}
.block-grid.open .map-title > svg:last-child {
@@ -348,7 +350,7 @@ button.map-title {
.map-title-completed {
flex-shrink: 0;
- padding-left: 15px;
+ padding-inline-start: 15px;
}
}
@@ -381,7 +383,7 @@ button.map-title {
font-size: 1rem;
display: block;
margin-bottom: 5px;
- margin-right: 5px;
+ margin-inline-end: 5px;
padding: 4px 10px;
color: var(--highlight-color);
background-color: var(--highlight-background);
diff --git a/client/src/templates/Introduction/super-block-intro.tsx b/client/src/templates/Introduction/super-block-intro.tsx
index 9b82cece7e8e51..d0c84f3e1a5068 100644
--- a/client/src/templates/Introduction/super-block-intro.tsx
+++ b/client/src/templates/Introduction/super-block-intro.tsx
@@ -205,16 +205,17 @@ const SuperBlockIntroductionPage = (props: SuperBlockProp) => {
/>
))}
- {superBlock !== SuperBlocks.CodingInterviewPrep && (
-
-
-
- )}
+ {superBlock !== SuperBlocks.CodingInterviewPrep &&
+ superBlock !== SuperBlocks.TheOdinProject && (
+
+
+
+ )}
{!isSignedIn && !signInLoading && (