rebase against next

This commit is contained in:
Shaun Hamilton
2021-06-24 18:27:41 +00:00
220 changed files with 9652 additions and 4942 deletions

View File

@ -3,7 +3,8 @@
"es6": true,
"browser": true,
"mocha": true,
"node": true
"node": true,
"jest": true
},
"parser": "babel-eslint",
"root": true,

3
.gitignore vendored
View File

@ -179,3 +179,6 @@ api-server/lib/*
curriculum/dist
curriculum/build
client/static/_redirects
### UI Components ###
tools/ui-components/dist

View File

@ -1,4 +1,3 @@
/* global expect */
import { ensureLowerCaseEmail } from './User-Identity';
test('returns lowercase email when one exists', () => {

View File

@ -26,7 +26,7 @@ import {
renderSignInEmail
} from '../utils';
import { blocklistedUsernames } from '../../server/utils/constants.js';
import { blocklistedUsernames } from '../../../../config/constants';
import { wrapHandledError } from '../../server/utils/create-handled-error.js';
import { saveUser, observeMethod } from '../../server/utils/rx.js';
import { getEmailSender } from '../../server/utils/url-utils';

View File

@ -1,5 +1,3 @@
/* global it expect */
import { getFallbackFrontEndDate } from '../boot/certificate';
import { fullStackChallenges } from './fixtures';

View File

@ -1,4 +1,3 @@
/* global describe xdescribe it expect jest */
import { first, find } from 'lodash';
import {

View File

@ -1,4 +1,3 @@
/* global jest*/
import { isEqual } from 'lodash';
import { isEmail } from 'validator';

View File

@ -1,4 +1,3 @@
/* global describe it expect jest */
import { mockReq as mockRequest, mockRes } from '../boot_tests/challenge.test';
import jwt from 'jsonwebtoken';

View File

@ -1,4 +1,3 @@
/* global describe expect it */
import moment from 'moment-timezone';
import { dayCount } from './date-utils';

View File

@ -1,7 +1,4 @@
/* eslint-disable camelcase */
/* global describe it expect */
/* global jest*/
import axios from 'axios';
import keys from '../../../../config/secrets';
import {

View File

@ -1,4 +1,3 @@
/* global describe it expect */
import {
getAccessTokenFromRequest,
errorTypes,

View File

@ -1,4 +1,3 @@
/* global describe beforeEach expect it jest */
import inMemoryCache from './in-memory-cache';
describe('InMemoryCache', () => {

View File

@ -1,5 +1,3 @@
/* global describe expect it jest */
const jwt = require('jsonwebtoken');
const { getReturnTo, normalizeParams } = require('./redirection');

View File

@ -1,4 +1,3 @@
/* global describe it expect jest */
import moment from 'moment-timezone';
import {

View File

@ -1,4 +1,3 @@
/* global expect */
import {
availableLangs,
langDisplayNames,

View File

@ -297,15 +297,15 @@
}
},
"relational-databases": {
"title": "Relational Databases",
"title": "關係型數據庫",
"intro": [
"placeholder"
"佔位符"
],
"blocks": {
"learn-relational-databases": {
"title": "Learn Relational Databases",
"title": "學習關係型數據庫",
"intro": [
"placeholder"
"佔位符"
]
}
}

View File

@ -395,7 +395,8 @@
"analytics": "條形圖和折線圖",
"shield": "帶有複選標記的盾牌",
"tensorflow": "Tensorflow 圖標",
"algorithm": "分支節點"
"algorithm": "分支節點",
"magnifier": "magnifier"
},
"aria": {
"fcc-logo": "freeCodeCamp 徽標",

View File

@ -297,15 +297,15 @@
}
},
"relational-databases": {
"title": "Relational Databases",
"title": "关系型数据库",
"intro": [
"placeholder"
"占位符"
],
"blocks": {
"learn-relational-databases": {
"title": "Learn Relational Databases",
"title": "学习关系型数据库",
"intro": [
"placeholder"
"占位符"
]
}
}

View File

@ -395,7 +395,8 @@
"analytics": "条形图和折线图",
"shield": "带有复选标记的盾牌",
"tensorflow": "Tensorflow 图标",
"algorithm": "分支节点"
"algorithm": "分支节点",
"magnifier": "magnifier"
},
"aria": {
"fcc-logo": "freeCodeCamp 徽标",

View File

@ -395,7 +395,8 @@
"analytics": "A bar chart and line graph",
"shield": "A shield with a checkmark",
"tensorflow": "Tensorflow icon",
"algorithm": "Branching nodes"
"algorithm": "Branching nodes",
"magnifier": "magnifier"
},
"aria": {
"fcc-logo": "freeCodeCamp Logo",

View File

@ -395,7 +395,8 @@
"analytics": "Un gráfico de barras y un gráfico de líneas",
"shield": "Un escudo con una marca de verificación",
"tensorflow": "Icono de Tensorflow",
"algorithm": "Nodos ramificados"
"algorithm": "Nodos ramificados",
"magnifier": "magnifier"
},
"aria": {
"fcc-logo": "Logo de freeCodeCamp",

View File

@ -395,7 +395,8 @@
"analytics": "Un grafico a barre e un grafico a linea",
"shield": "Uno scudo con un segno di spunta",
"tensorflow": "Icona di Tensorflow",
"algorithm": "Nodi con rami"
"algorithm": "Nodi con rami",
"magnifier": "magnifier"
},
"aria": {
"fcc-logo": "Logo freeCodeCamp",
@ -529,7 +530,7 @@
"Caesars Cipher": "Cifrario di Cesare",
"Telephone Number Validator": "Validatore Numero Di Telefono",
"Cash Register": "Registro dei Contanti",
"Build a Drum Machine": "Costruisci una macchina a tamburo",
"Build a Drum Machine": "Costruisci una batteria",
"Visualize Data with a Choropleth Map": "Visualizza i dati con una mappa a colori Coropletica",
"Visualize Data with a Treemap Diagram": "Visualizza i dati con una mappa ad albero",
"Exercise Tracker": "Monitor degli esercizi",

View File

@ -395,7 +395,8 @@
"analytics": "A bar chart and line graph",
"shield": "A shield with a checkmark",
"tensorflow": "Tensorflow icon",
"algorithm": "Branching nodes"
"algorithm": "Branching nodes",
"magnifier": "magnifier"
},
"aria": {
"fcc-logo": "freeCodeCamp Logo",

2589
client/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -39,9 +39,9 @@
"@babel/plugin-proposal-export-default-from": "7.14.5",
"@babel/plugin-proposal-function-bind": "7.14.5",
"@babel/polyfill": "7.12.1",
"@babel/preset-env": "7.14.5",
"@babel/preset-env": "7.14.7",
"@babel/preset-react": "7.14.5",
"@babel/standalone": "7.14.6",
"@babel/standalone": "7.14.7",
"@fortawesome/fontawesome": "1.1.8",
"@fortawesome/fontawesome-svg-core": "1.2.35",
"@fortawesome/free-brands-svg-icons": "5.15.3",
@ -70,17 +70,17 @@
"enzyme": "3.11.0",
"enzyme-adapter-react-16": "1.15.6",
"final-form": "4.20.2",
"gatsby": "3.7.2",
"gatsby-cli": "3.7.1",
"gatsby": "3.8.0",
"gatsby-cli": "3.8.0",
"gatsby-plugin-advanced-sitemap": "1.6.0",
"gatsby-plugin-create-client-paths": "3.7.1",
"gatsby-plugin-manifest": "3.7.1",
"gatsby-plugin-postcss": "4.7.1",
"gatsby-plugin-react-helmet": "4.7.1",
"gatsby-plugin-create-client-paths": "3.8.0",
"gatsby-plugin-manifest": "3.8.0",
"gatsby-plugin-postcss": "4.8.0",
"gatsby-plugin-react-helmet": "4.8.0",
"gatsby-plugin-remove-serviceworker": "1.0.0",
"gatsby-remark-prismjs": "5.4.1",
"gatsby-source-filesystem": "3.7.1",
"gatsby-transformer-remark": "4.4.1",
"gatsby-remark-prismjs": "5.5.0",
"gatsby-source-filesystem": "3.8.0",
"gatsby-transformer-remark": "4.5.0",
"i18next": "20.3.2",
"jquery": "3.6.0",
"lodash": "4.17.21",
@ -94,7 +94,7 @@
"process": "0.11.10",
"prop-types": "15.7.2",
"psl": "1.8.0",
"query-string": "7.0.0",
"query-string": "7.0.1",
"react": "16.14.0",
"react-dom": "16.14.0",
"react-final-form": "6.5.3",
@ -130,22 +130,36 @@
},
"devDependencies": {
"@babel/types": "7.14.5",
"@codesee/babel-plugin-instrument": "0.38.0",
"@codesee/tracker": "0.38.0",
"@codesee/babel-plugin-instrument": "0.41.0",
"@codesee/tracker": "0.41.0",
"@testing-library/jest-dom": "5.14.1",
"@testing-library/react": "11.2.7",
"@types/jest": "^26.0.23",
"@types/loadable__component": "^5.13.3",
"@types/lodash-es": "^4.17.4",
"@types/react-dom": "^17.0.8",
"@types/react-helmet": "^6.1.1",
"@types/react-instantsearch-dom": "^6.10.0",
"@types/react-monaco-editor": "^0.16.0",
"@types/react-redux": "^7.1.16",
"@types/react-responsive": "^8.0.2",
"@types/react-spinkit": "^3.0.6",
"@types/react-test-renderer": "^17.0.1",
"@types/react-transition-group": "4.4.1",
"@types/redux-actions": "2.6.1",
"@types/sanitize-html": "^2.3.1",
"@types/store": "^2.0.2",
"@types/validator": "^13.1.4",
"autoprefixer": "10.2.6",
"babel-plugin-transform-imports": "2.0.0",
"chokidar": "3.5.2",
"copy-webpack-plugin": "9.0.0",
"gatsby-plugin-webpack-bundle-analyser-v2": "1.1.22",
"gatsby-plugin-webpack-bundle-analyser-v2": "1.1.24",
"jest-json-schema-extended": "1.0.0",
"monaco-editor-webpack-plugin": "4.0.0",
"react-test-renderer": "16.14.0",
"redux-saga-test-plan": "4.0.1",
"webpack": "5.39.1",
"webpack": "5.40.0",
"webpack-cli": "4.7.2"
}
}

View File

@ -1,6 +1,5 @@
/* eslint-disable react/prop-types */
/* eslint-disable react/display-name */
/* global jest */
import React from 'react';
const reactI18next = jest.genMockFromModule('react-i18next');

View File

@ -1,4 +1,3 @@
/* global describe it expect */
import {
wrapHandledError,
unwrapHandledError

View File

@ -0,0 +1,24 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
const Magnifier = (): JSX.Element => {
const { t } = useTranslation();
return (
<>
<span className='sr-only'>{t('icons.Magnifier')}</span>
<svg
className='ais-SearchBox-submitIcon'
height='10'
viewBox='0 0 40 40'
width='10'
xmlns='http://www.w3.org/2000/svg'
>
<path d='M26.804 29.01c-2.832 2.34-6.465 3.746-10.426 3.746C7.333 32.756 0 25.424 0 16.378 0 7.333 7.333 0 16.378 0c9.046 0 16.378 7.333 16.378 16.378 0 3.96-1.406 7.594-3.746 10.426l10.534 10.534c.607.607.61 1.59-.004 2.202-.61.61-1.597.61-2.202.004L26.804 29.01zm-10.426.627c7.323 0 13.26-5.936 13.26-13.26 0-7.32-5.937-13.257-13.26-13.257C9.056 3.12 3.12 9.056 3.12 16.378c0 7.323 5.936 13.26 13.258 13.26z' />
</svg>
</>
);
};
Magnifier.displayName = 'Magnifier';
export default Magnifier;

View File

@ -1,4 +1,3 @@
/* global jest, expect */
import React from 'react';
import ShallowRenderer from 'react-test-renderer/shallow';
import envData from '../../../config/env.json';

View File

@ -1,4 +1,3 @@
/* global expect */
import React from 'react';
import renderer from 'react-test-renderer';

View File

@ -1,4 +1,3 @@
/* global expect jest */
import React from 'react';
import ShallowRenderer from 'react-test-renderer/shallow';

View File

@ -3,10 +3,17 @@ import PropTypes from 'prop-types';
import { Link, SkeletonSprite } from '../../helpers';
import NavLogo from './NavLogo';
import SearchBar from '../../search/searchBar/SearchBar';
import MenuButton from './MenuButton';
import NavLinks from './NavLinks';
import './universalNav.css';
import { isLanding } from '../../../utils/path-parsers';
import Loadable from '@loadable/component';
const SearchBar = Loadable(() => import('../../search/searchBar/SearchBar'));
const SearchBarOptimized = Loadable(() =>
import('../../search/searchBar/search-bar-optimized')
);
export const UniversalNav = ({
displayMenu,
@ -17,6 +24,14 @@ export const UniversalNav = ({
fetchState
}) => {
const { pending } = fetchState;
const search =
typeof window !== `undefined` && isLanding(window.location.pathname) ? (
<SearchBarOptimized />
) : (
<SearchBar innerRef={searchBarRef} />
);
return (
<nav
className={'universal-nav' + (displayMenu ? ' expand-nav' : '')}
@ -27,7 +42,7 @@ export const UniversalNav = ({
'universal-nav-left' + (displayMenu ? ' display-search' : '')
}
>
<SearchBar innerRef={searchBarRef} />
{search}
</div>
<div className='universal-nav-middle'>
<Link id='universal-nav-logo' to='/learn'>

View File

@ -1,4 +1,3 @@
/* global expect jest */
import React from 'react';
import renderer from 'react-test-renderer';
import { Provider } from 'react-redux';

View File

@ -1,5 +1,3 @@
/* global expect jest */
import React from 'react';
import { useStaticQuery } from 'gatsby';
import { render } from '@testing-library/react';

View File

@ -1,5 +1,3 @@
/* global expect */
import createExternalRedirect from './createExternalRedirects';
describe('createExternalRedirects', () => {

View File

@ -1,5 +1,3 @@
/* global expect */
import createLanguageRedirect from './createLanguageRedirect';
describe('createLanguageRedirect for clientLocale === english', () => {

View File

@ -1,5 +1,3 @@
/* global expect */
import React from 'react';
import { render } from '@testing-library/react';

View File

@ -1,5 +1,3 @@
/* global expect */
import React from 'react';
import { render } from '@testing-library/react';

View File

@ -1,5 +1,3 @@
/* global jest, expect */
import React from 'react';
import { render, fireEvent } from '@testing-library/react';

View File

@ -1,4 +1,3 @@
/* global expect */
import React from 'react';
import renderer, { ReactTestRendererJSON } from 'react-test-renderer';

View File

@ -1,4 +1,3 @@
/* global expect */
import React from 'react';
import { render, cleanup } from '@testing-library/react';

View File

@ -1,4 +1,3 @@
/* global expect jest */
import React from 'react';
import ShallowRenderer from 'react-test-renderer/shallow';

View File

@ -21,7 +21,6 @@ import { flashMessageSelector, removeFlashMessage } from '../Flash/redux';
import { isBrowser } from '../../../utils';
import WithInstantSearch from '../search/WithInstantSearch';
import OfflineWarning from '../OfflineWarning';
import Flash from '../Flash';
import Header from '../Header';
@ -201,17 +200,15 @@ class DefaultLayout extends Component {
/>
<style>{fontawesome.dom.css()}</style>
</Helmet>
<WithInstantSearch>
<div className={`default-layout`}>
<Header fetchState={fetchState} user={user} />
<OfflineWarning isOnline={isOnline} isSignedIn={isSignedIn} />
{hasMessage && flashMessage ? (
<Flash flashMessage={flashMessage} onClose={removeFlashMessage} />
) : null}
{children}
</div>
{showFooter && <Footer />}
</WithInstantSearch>
<div className={`default-layout`}>
<Header fetchState={fetchState} user={user} />
<OfflineWarning isOnline={isOnline} isSignedIn={isSignedIn} />
{hasMessage && flashMessage ? (
<Flash flashMessage={flashMessage} onClose={removeFlashMessage} />
) : null}
{children}
</div>
{showFooter && <Footer />}
</div>
);
}

View File

@ -1,5 +1,3 @@
/* global expect jest */
import React from 'react';
import { render } from '@testing-library/react';

View File

@ -1,5 +1,3 @@
/* global expect jest */
import React from 'react';
import { render } from '@testing-library/react';

View File

@ -1,5 +1,3 @@
/* global expect */
import React from 'react';
import { render } from '@testing-library/react';
import TimeLine from './TimeLine';

View File

@ -9,6 +9,8 @@ import { isEqual } from 'lodash-es';
import { withTranslation } from 'react-i18next';
import { searchPageUrl } from '../../../utils/algolia-locale-setup';
import WithInstantSearch from '../WithInstantSearch';
import {
isSearchDropdownEnabledSelector,
isSearchBarFocusedSelector,
@ -177,33 +179,39 @@ export class SearchBar extends Component {
const placeholder = t('search.placeholder');
return (
<div className='fcc_searchBar' data-testid='fcc_searchBar' ref={innerRef}>
<HotKeys handlers={this.keyHandlers} keyMap={this.keyMap}>
<div className='fcc_search_wrapper'>
<label className='fcc_sr_only' htmlFor='fcc_instantsearch'>
{t('search.label')}
</label>
<ObserveKeys except={['Space']}>
<SearchBox
focusShortcuts={[83, 191]}
onChange={this.handleChange}
onFocus={this.handleFocus}
onSubmit={this.handleSearch}
showLoadingIndicator={false}
translations={{ placeholder }}
/>
</ObserveKeys>
{isDropdownEnabled && isSearchFocused && (
<SearchHits
handleHits={this.handleHits}
handleMouseEnter={this.handleMouseEnter}
handleMouseLeave={this.handleMouseLeave}
selectedIndex={index}
/>
)}
</div>
</HotKeys>
</div>
<WithInstantSearch>
<div
className='fcc_searchBar'
data-testid='fcc_searchBar'
ref={innerRef}
>
<HotKeys handlers={this.keyHandlers} keyMap={this.keyMap}>
<div className='fcc_search_wrapper'>
<label className='fcc_sr_only' htmlFor='fcc_instantsearch'>
{t('search.label')}
</label>
<ObserveKeys except={['Space']}>
<SearchBox
focusShortcuts={[83, 191]}
onChange={this.handleChange}
onFocus={this.handleFocus}
onSubmit={this.handleSearch}
showLoadingIndicator={false}
translations={{ placeholder }}
/>
</ObserveKeys>
{isDropdownEnabled && isSearchFocused && (
<SearchHits
handleHits={this.handleHits}
handleMouseEnter={this.handleMouseEnter}
handleMouseLeave={this.handleMouseLeave}
selectedIndex={index}
/>
)}
</div>
</HotKeys>
</div>
</WithInstantSearch>
);
}
}

View File

@ -1,4 +1,3 @@
/* global jest, expect */
import React from 'react';
import ShallowRenderer from 'react-test-renderer/shallow';

View File

@ -46,7 +46,7 @@ const CustomHits = connectHits(
return (
<div className='ais-Hits'>
<ul className='ais-Hits-list'>
<ul className='ais-Hits-list' data-cy='ais-Hits-list'>
{allHits.map((hit, i) => (
<li
className={

View File

@ -0,0 +1,59 @@
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import Magnifier from '../../../assets/icons/Magnifier';
import { searchPageUrl } from '../../../utils/algolia-locale-setup';
const SearchBarOptimized = (): JSX.Element => {
const { t } = useTranslation();
const placeholder = t('search.placeholder');
const searchUrl: string = searchPageUrl as string;
const [value, setValue] = useState('');
const onChange = (event: React.ChangeEvent<HTMLInputElement>) =>
setValue(event.target.value);
const onSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (value && value.length > 1) {
window.open(`${searchUrl}?query=${encodeURIComponent(value)}`, '_blank');
}
};
return (
<div className='fcc_searchBar' data-testid='fcc_searchBar'>
<div className='fcc_search_wrapper'>
<div className='ais-SearchBox' data-cy='ais-SearchBox'>
<form
action=''
className='ais-SearchBox-form'
data-cy='ais-SearchBox-form'
onSubmit={onSubmit}
role='search'
>
<input
aria-label='Search'
autoCapitalize='off'
autoComplete='off'
autoCorrect='off'
className='ais-SearchBox-input'
maxLength={512}
onChange={onChange}
placeholder={placeholder}
spellCheck='false'
type='search'
value={value}
/>
<button
className='ais-SearchBox-submit'
title='Submit your search query.'
type='submit'
>
<Magnifier />
</button>
</form>
</div>
</div>
</div>
);
};
SearchBarOptimized.displayName = 'SearchBarOptimized';
export default SearchBarOptimized;

View File

@ -1,56 +0,0 @@
import React from 'react';
import {
Highlight,
connectStateResults,
connectAutoComplete
} from 'react-instantsearch-dom';
import { isEmpty } from 'lodash-es';
import EmptySearch from './EmptySearch';
import NoResults from './NoResults';
import './search-page-hits.css';
const AllHits = connectAutoComplete(({ hits, currentRefinement }) => {
const isHitsEmpty = !hits.length;
return currentRefinement && !isHitsEmpty ? (
<div className='ais-Hits search-page'>
<ul className='ais-Hits-list'>
{hits.map(result => (
<a
href={result.url}
key={result.objectID}
rel='noopener noreferrer'
target='_blank'
>
<li className='ais-Hits-item dataset-node'>
<p>
<Highlight attribute='title' hit={result} />
</p>
</li>
</a>
))}
</ul>
</div>
) : (
<NoResults query={currentRefinement} />
);
});
AllHits.displayName = 'AllHits';
const SearchHits = connectStateResults(({ handleClick, searchState }) => {
const isSearchEmpty = isEmpty(searchState) || isEmpty(searchState.query);
return isSearchEmpty ? (
<EmptySearch />
) : (
<AllHits handleClick={handleClick} />
);
});
SearchHits.displayName = 'SearchHits';
export default SearchHits;

View File

@ -1,5 +1,3 @@
/* global expect jest */
import React from 'react';
import { render } from '@testing-library/react';
import { Provider } from 'react-redux';

View File

@ -1,4 +1,3 @@
/* global expect jest */
import React from 'react';
import ShallowRenderer from 'react-test-renderer/shallow';
import TestRenderer from 'react-test-renderer';

View File

@ -1,4 +1,3 @@
/* global expect */
import toLearnPath from '../utils/to-learn-path';
import { withPrefix } from 'gatsby';

View File

@ -1,48 +0,0 @@
import React, { Fragment, Component } from 'react';
import PropTypes from 'prop-types';
import Helmet from 'react-helmet';
import { connect } from 'react-redux';
import { Index } from 'react-instantsearch-dom';
import { Grid, Row, Col } from '@freecodecamp/react-bootstrap';
import { withTranslation } from 'react-i18next';
import { updateSearchQuery } from '../components/search/redux';
import SearchPageHits from '../components/search/searchPage/SearchPageHits';
import './search.css';
const propTypes = {
t: PropTypes.func.isRequired,
updateSearchQuery: PropTypes.func.isRequired
};
const mapDispatchToProps = { updateSearchQuery };
class SearchPage extends Component {
componentWillUnmount() {
this.props.updateSearchQuery('');
}
render() {
const { t } = this.props;
return (
<Fragment>
<Helmet title={`${t('search.label')} | freeCodeCamp.org`} />
<Index indexName='news' />
<Grid>
<Row>
<Col xs={12}>
<main>
<SearchPageHits />
</main>
</Col>
</Row>
</Grid>
</Fragment>
);
}
}
SearchPage.displayName = 'SearchPage';
SearchPage.propTypes = propTypes;
export default connect(null, mapDispatchToProps)(withTranslation()(SearchPage));

View File

@ -1,5 +1,3 @@
/* global expect jest */
import { Subject } from 'rxjs';
import { ActionsObservable, StateObservable } from 'redux-observable';
import failedUpdatesEpic from './failed-updates-epic';

View File

@ -1,5 +1,3 @@
/* global jest */
import { types } from '.';
import { createGaSaga } from './ga-saga';
import ga from '../analytics';

View File

@ -84,69 +84,79 @@ class DesktopLayout extends Component {
return (
<Fragment>
{projectBasedChallenge && (
<ActionRow switchDisplayTab={this.switchDisplayTab} {...this.state} />
)}
<ReflexContainer className='desktop-layout' orientation='vertical'>
{!projectBasedChallenge && (
<ReflexElement
flex={instructionPane.flex}
name='instructionPane'
{...resizeProps}
>
{instructions}
</ReflexElement>
<ReflexContainer className='desktop-layout' orientation='horizontal'>
{projectBasedChallenge && (
<ActionRow
switchDisplayTab={this.switchDisplayTab}
{...this.state}
/>
)}
{!projectBasedChallenge && (
<ReflexSplitter propagate={true} {...resizeProps} />
)}
<ReflexElement
flex={editorPane.flex}
name='editorPane'
{...resizeProps}
>
{challengeFile && showUpcomingChanges && !hasEditableBoundries && (
<EditorTabs />
)}
{challengeFile && (
<ReflexContainer key={challengeFile.key} orientation='horizontal'>
<ReflexElement flex={8} {...reflexProps} {...resizeProps}>
<ReflexContainer orientation='vertical'>
{!projectBasedChallenge && (
<ReflexElement
flex={codePane.flex}
name='codePane'
{...reflexProps}
flex={instructionPane.flex}
name='instructionPane'
{...resizeProps}
>
{<Fragment>{editor}</Fragment>}
{instructions}
</ReflexElement>
{isConsoleDisplayable && (
<ReflexSplitter propagate={true} {...resizeProps} />
)}
{isConsoleDisplayable && (
<ReflexElement
flex={testsPane.flex}
name='testsPane'
{...reflexProps}
{...resizeProps}
)}
{!projectBasedChallenge && (
<ReflexSplitter propagate={true} {...resizeProps} />
)}
<ReflexElement
flex={editorPane.flex}
name='editorPane'
{...resizeProps}
>
{challengeFile &&
showUpcomingChanges &&
!hasEditableBoundries && <EditorTabs />}
{challengeFile && (
<ReflexContainer
key={challengeFile.key}
orientation='horizontal'
>
{testOutput}
</ReflexElement>
<ReflexElement
flex={codePane.flex}
name='codePane'
{...reflexProps}
{...resizeProps}
>
<Fragment>{editor}</Fragment>
</ReflexElement>
{isConsoleDisplayable && (
<ReflexSplitter propagate={true} {...resizeProps} />
)}
{isConsoleDisplayable && (
<ReflexElement
flex={testsPane.flex}
name='testsPane'
{...reflexProps}
{...resizeProps}
>
{testOutput}
</ReflexElement>
)}
</ReflexContainer>
)}
</ReflexContainer>
)}
</ReflexElement>
{isPreviewDisplayable && (
<ReflexSplitter propagate={true} {...resizeProps} />
)}
{isPreviewDisplayable && (
<ReflexElement
flex={previewPane.flex}
name='previewPane'
{...resizeProps}
>
{preview}
</ReflexElement>
)}
</ReflexContainer>
</ReflexElement>
{isPreviewDisplayable && (
<ReflexSplitter propagate={true} {...resizeProps} />
)}
{isPreviewDisplayable && (
<ReflexElement
flex={previewPane.flex}
name='previewPane'
{...resizeProps}
>
{preview}
</ReflexElement>
)}
</ReflexContainer>
</Fragment>
);

View File

@ -1,5 +1,3 @@
/* global expect */
import React from 'react';
import renderer from 'react-test-renderer';

View File

@ -1,5 +1,3 @@
/* global expect jest */
import { getCompletedPercent } from './CompletionModal';
jest.mock('../../../analytics');

View File

@ -1,5 +1,3 @@
/* global jest, expect */
import React from 'react';
import { render, fireEvent } from '@testing-library/react';

View File

@ -1,4 +1,3 @@
/* global expect */
import { findIndexHtml } from './builders.js';
const withHTML = [

View File

@ -1,5 +1,3 @@
/* global expect */
import { transformEditorLink } from '../utils';
describe('create-question-epic', () => {

View File

@ -1,5 +1,3 @@
/* global expect */
import envData from '../../../../../config/env.json';
const { forumLocation } = envData;

View File

@ -1,5 +1,3 @@
/* global expect, jest */
import createWorker from './worker-executor';
function mockWorker({ init, postMessage, terminate } = {}) {

View File

@ -1,4 +1,3 @@
/* global describe it expect */
import { cssString } from './__fixtures/curriculum-helpers-css';
import CSSHelp from './css-help';

View File

@ -1,5 +1,3 @@
/* global describe it expect */
import __testHelpers, { removeJSComments } from './curriculum-helpers';
import jsTestValues from './__fixtures/curriculum-helpers-javascript';
import cssTestValues from './__fixtures/curriculum-helpers-css';

View File

@ -1,4 +1,4 @@
/* global expect BigInt */
/* global BigInt */
const { format } = require('./format');

View File

@ -1,4 +1,3 @@
/* global expect jest */
import { isObject } from 'lodash-es';
import {
isHandledError,

View File

@ -0,0 +1,66 @@
/* global describe it expect */
import { isChallenge, isLanding } from './path-parsers';
const pathnames = {
english: {
landing: '/',
superBlock: '/learn/responsive-web-design',
challenge:
'/learn/responsive-web-design/basic-html-and-html5/say-hello-to-html-elements'
},
espanol: {
landing: '/espanol',
superBlock: '/espanol/learn/responsive-web-design',
challenge:
'/espanol/learn/responsive-web-design/basic-html-and-html5/say-hello-to-html-elements'
}
};
describe('isLanding', () => {
it('returns a booleans', () => {
expect(typeof isLanding('/')).toBe('boolean');
});
it('return true for Espanol landing pathname', () => {
expect(isLanding(pathnames.espanol.landing)).toBe(true);
});
it('returns false for Espanol super block pathname', () => {
expect(isLanding(pathnames.espanol.superBlock)).toBe(false);
});
it('returns false for Espanol challenge pathname', () => {
expect(isLanding(pathnames.espanol.challenge)).toBe(false);
});
it('returns true for English landing pathname', () => {
expect(isLanding(pathnames.english.landing)).toBe(true);
});
it('returns false for English super block pathname', () => {
expect(isLanding(pathnames.english.superBlock)).toBe(false);
});
it('returns false for English challenge pathname', () => {
expect(isLanding(pathnames.english.challenge)).toBe(false);
});
});
describe('isChallenge', () => {
it('returns a boolean', () => {
expect(typeof isChallenge('/')).toBe('boolean');
});
it('returns false for Espanol landing pathname', () => {
expect(isChallenge(pathnames.espanol.landing)).toBe(false);
});
it('returns false for Espanol super block pathname', () => {
expect(isChallenge(pathnames.espanol.superBlock)).toBe(false);
});
it('returns true for Espanol challenge pathname', () => {
expect(isChallenge(pathnames.espanol.challenge)).toBe(true);
});
it('returns false for English landing pathname', () => {
expect(isChallenge(pathnames.english.landing)).toBe(false);
});
it('returns false for English super block pathname', () => {
expect(isChallenge(pathnames.english.superBlock)).toBe(false);
});
it('returns true for English challenge pathname', () => {
expect(isChallenge(pathnames.english.challenge)).toBe(true);
});
});

View File

@ -0,0 +1,23 @@
import { i18nConstants } from '../../../config/constants';
const splitPath = (pathname: string): string[] =>
pathname.split('/').filter(x => x);
export const isChallenge = (pathname: string): boolean => {
const pathArray = splitPath(pathname);
return (
(pathArray.length === 4 && pathArray[0]) === 'learn' ||
(pathArray.length === 5 && pathArray[1]) === 'learn'
);
};
export const isLanding = (pathname: string): boolean => {
const pathArray = splitPath(pathname);
const isEnglishLanding = pathArray.length === 0;
const isI18Landing =
pathArray.length === 1 && i18nConstants.includes(pathArray[0]);
return isEnglishLanding || isI18Landing;
};
const pathParsers = { isLanding, isChallenge };
export default pathParsers;

View File

@ -1,5 +1,10 @@
{
"include": ["./i18n/**/*", "./plugins/**/*", "./src/**/*", "./utils/**/*"],
"include": [
"./i18n/**/*",
"./plugins/**/*",
"./src/**/*",
"./utils/**/*"
],
"compilerOptions": {
"target": "es2020",
"module": "es2020",
@ -11,7 +16,12 @@
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"noEmit": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"resolveJsonModule": true
"types": [
"node",
"jest",
"@testing-library/jest-dom"
]
}
}
}

View File

@ -6,6 +6,7 @@ import {
DefaultLayout
} from '../../src/components/layouts';
import FourOhFourPage from '../../src/pages/404';
import { isChallenge } from '../../src/utils/path-parsers';
export default function layoutSelector({ element, props }) {
const {
@ -18,32 +19,23 @@ export default function layoutSelector({ element, props }) {
{element}
</DefaultLayout>
);
}
if (/\/certification\//.test(pathname)) {
} else if (/\/certification\//.test(pathname)) {
return (
<CertificationLayout pathname={pathname}>{element}</CertificationLayout>
);
}
const splitPath = pathname.split('/').filter(x => x);
const isChallenge =
(splitPath.length === 4 && splitPath[0]) === 'learn' ||
(splitPath.length === 5 && splitPath[1]) === 'learn';
if (isChallenge) {
} else if (isChallenge(pathname)) {
return (
<DefaultLayout pathname={pathname} showFooter={false}>
{element}
</DefaultLayout>
);
} else {
return (
<DefaultLayout pathname={pathname} showFooter={true}>
{element}
</DefaultLayout>
);
}
return (
<DefaultLayout pathname={pathname} showFooter={true}>
{element}
</DefaultLayout>
);
}
layoutSelector.propTypes = {

View File

@ -1,4 +1,3 @@
/* global expect jest */
import React from 'react';
import { Provider } from 'react-redux';
import ShallowRenderer from 'react-test-renderer/shallow';

View File

@ -1,5 +1,3 @@
/* global expect */
import { injectConditionalTags } from './tags';
describe('Tags', () => {

View File

@ -4,8 +4,44 @@ for (let i = 0; i < 26; i++) {
alphabet = alphabet.concat(String.fromCharCode(97 + i));
}
const i18nConstants = [
// reserved paths for localizations
'afrikaans',
'arabic',
'bengali',
'catalan',
'chinese',
'czech',
'danish',
'dutch',
'espanol',
'finnish',
'french',
'german',
'greek',
'hebrew',
'hindi',
'hungarian',
'italian',
'japanese',
'korean',
'norwegian',
'polish',
'portuguese',
'romanian',
'russian',
'serbian',
'spanish',
'swahili',
'swedish',
'turkish',
'ukrainian',
'vietnamese'
];
let blocklist = [
...alphabet.split(''),
...i18nConstants,
'about',
'academic-honesty',
'account',
@ -85,40 +121,6 @@ let blocklist = [
'user',
'username',
'wiki',
// reserved paths for localizations
'afrikaans',
'arabic',
'bengali',
'catalan',
'chinese',
'czech',
'danish',
'dutch',
'espanol',
'finnish',
'french',
'german',
'greek',
'hebrew',
'hindi',
'hungarian',
'italian',
'japanese',
'korean',
'norwegian',
'polish',
'portuguese',
'romanian',
'russian',
'serbian',
'spanish',
'swahili',
'swedish',
'turkish',
'ukrainian',
'vietnamese',
// some more names from https://github.com/marteinn/The-Big-Username-Blacklist-JS/blob/master/src/list.js
'.htaccess',
'.htpasswd',
@ -647,4 +649,5 @@ let blocklist = [
'zlib'
];
export const blocklistedUsernames = [...new Set(blocklist)];
exports.blocklistedUsernames = [...new Set(blocklist)];
exports.i18nConstants = i18nConstants;

View File

@ -42,7 +42,7 @@ dashedName: nest-an-anchor-element-within-a-paragraph
此示例的最終輸出結果是這樣:
你可以訪問 <a href="https://www.freecodecamp.org" target="_blank">link to www.freecodecamp.org</a>
Here's a <a href="https://www.freecodecamp.org" target="_blank">link to www.freecodecamp.org</a> for you to follow.
# --instructions--

View File

@ -17,7 +17,7 @@ Animal.prototype.eat = function() {
};
```
在這一節以及下一節挑戰中我們將學習如何在 `Bird``Dog` 中重用 `Animal's` 中的方法,而無需重新定義它們。 這裏我們會用到構造函數的繼承特性。 這一節挑戰中我們學習第一步:創建一個超類 `supertype`(或者叫父類)的實例。 你已經學會了一種創建 `Animal` 實例的方法,即使用 `new` 操作符:
在這一節以及下一節挑戰中我們將學習如何在 `Bird``Dog` 中重用 `Animal` 中的方法,而無需重新定義它們。 這裏我們會用到構造函數的繼承特性。 這一節挑戰中我們學習第一步:創建一個超類 `supertype`(或者叫父類)的實例。 你已經學會了一種創建 `Animal` 實例的方法,即使用 `new` 操作符:
```js
let animal = new Animal();
@ -29,7 +29,7 @@ let animal = new Animal();
let animal = Object.create(Animal.prototype);
```
`Object.create(obj)` 創建了一個新對象,並指定了 `obj` 作爲新對象的 `prototype`。 回憶一下,我們之前說過 `prototype` 就像是創建對象的“配方”。 如果我們把 `animal``prototype` 設置爲與 `Animal's` 構造函數的 `prototype` 一樣,那麼就相當於讓 `animal` 這個實例的配方`Animal` 其他實例的配方一樣了。
`Object.create(obj)` 創建了一個新對象,並指定了 `obj` 作爲新對象的 `prototype`。 回憶一下,我們之前說過 `prototype` 就像是創建對象的“配方”。 如果我們把 `animal``prototype` 設置爲與 `Animal` 構造函數的 `prototype` 一樣,那麼就相當於讓 `animal` 這個實例具有`Animal` 其他實例相同的“配方”了。
```js
animal.eat();

View File

@ -36,7 +36,7 @@ Bird.prototype.eat = function() {
};
```
如果你有一個實例:`let duck = new Bird();`,然後你調用了 `duck.eat()`,以下就是 JavaScript 在 `ducks``prototype` 鏈上尋找方法的過程:
如果你有一個實例:`let duck = new Bird();`,然後你調用了 `duck.eat()`,以下就是 JavaScript 在 `duck``prototype` 鏈上尋找方法的過程:
1. `duck` => `eat()` 是定義在這裏嗎? 不是。
2. `Bird` => `eat()` 是定義在這裏嗎? => 是的。 執行它並停止往上搜索。

View File

@ -19,7 +19,7 @@ let duck = new Bird();
duck.constructor
```
但是 `duck` 和其他所有 `Bird` 的實例都應該表明它們是由 `Bird` 創建的,而不是由 `Animal` 創建的。 爲此,你可以手動 `Bird's` constructor 屬性設置爲 `Bird` 對象:
但是 `duck` 和其他所有 `Bird` 的實例都應該表明它們是由 `Bird` 創建的,而不是由 `Animal` 創建的。 爲此,你可以手動 `Bird`構造函數屬性設置爲 `Bird` 對象:
```js
Bird.prototype.constructor = Bird;

View File

@ -12,7 +12,7 @@ dashedName: use-prototype-properties-to-reduce-duplicate-code
當只有兩個實例時可能並不是什麼問題,但想象一下如果有數百萬個實例。 這將會產生許許多多重複的變量。
這裏有一個更好的方法可以解決上述問題,那就是使用 `Birds``prototype``prototype` 是一個可以在所有 `Bird` 實例之間共享的對象。 以下是一個在 `Bird prototype` 中添加 `numLegs` 屬性的示例:
更好的方法是使用 `Bird``prototype``prototype` 是一個可以在所有 `Bird` 實例之間共享的對象。 以下是一個在 `Bird prototype` 中添加 `numLegs` 屬性的示例:
```js
Bird.prototype.numLegs = 2;
@ -45,7 +45,7 @@ assert(beagle.numLegs !== undefined);
assert(typeof beagle.numLegs === 'number');
```
`numLegs` 應該是一個 `prototype` 屬性而不是一個 `own` 屬性。
`numLegs` 應該是一個 `prototype` 屬性而不是一個自身屬性。
```js
assert(beagle.hasOwnProperty('numLegs') === false);

View File

@ -16,7 +16,7 @@ dashedName: create-a-controlled-form
我們增加了一個提交表單的按鈕。 可以看到它的 `type` 被設置爲 `submit`,表明它是控制表單提交的按鈕。 在 `form` 中添加 `input` 元素,並像上個挑戰一樣設置其 `value``onChange()` 屬性。 然後,應該完成 `handleSubmit` 方法,以便將組件 state 屬性 `submit` 設置爲本地 `state` 下的當前輸入值。
**注意:** 還必須在提交處理程序中調用 `event.preventDefault()`,以防止默認的表單提交行爲刷新網頁
**注意:** 還必須在提交處理程序中調用 `event.preventDefault()`,以防止將會刷新網頁的默認的表單提交行爲。 爲了便於學員操作,默認行爲在這裏被禁用,以防止重置挑戰的代碼
最後,在 `form` 元素之後創建一個 `h1` 標籤,該標籤從組件的 `state` 渲染 `submit` 的值。 然後,可以在表單中鍵入任何內容,然後單擊按鈕(或按 enter 鍵),輸入會渲染到頁面上。
@ -98,7 +98,26 @@ assert(
})();
```
`h1` 標題應該從組件的 state 渲染 `submit` 字段的值
`handleSubmit` 應該調用 `event.preventDefault`
```js
const handleSubmit = MyForm.prototype.handleSubmit.toString();
const allMatches = handleSubmit.match(/\bevent\.preventDefault\(\s*?\)/g) ?? [];
const blockCommented = handleSubmit.match(
/\/\*.*?\bevent\.preventDefault\(\s*?\).*?\*\//gs
);
const lineCommented = handleSubmit.match(
/\/\/.*?\bevent\.preventDefault\(\s*?\)/g
);
const commentedMatches = [...(blockCommented ?? []), ...(lineCommented ?? [])];
assert(
// At least one event.preventDefault() call exists and is not commented out
allMatches.length > commentedMatches.length
);
```
`h1` 標頭應該從組件的 state 渲染 `submit` 字段的值。
```js
(() => {

View File

@ -18,8 +18,7 @@ dashedName: personal-library
# --instructions--
1. 將的 MongoDB 連接字符串添加到 `.env`(沒有引號),`DB`
示例: `DB=mongodb://admin:pass@1234.mlab.com:1234/fccpersonallib`
1.的 MongoDB 連接字符串添加到 `.env`,作爲 `DB` 示例:`DB=mongodb://admin:pass@1234.mlab.com:1234/fccpersonallib`
2.`.env` 文件中設置 `NODE_ENV``test`中,沒有引號
3. 需要在 `routes/api.js` 中創建所有路由
4.`tests/2_functional-tests.js` 中創建所有的功能測試
@ -66,7 +65,7 @@ async (getUserInput) => {
let a = $.post(url, { title: 'Faux Book A' });
let b = $.post(url, { title: 'Faux Book B' });
let c = $.post(url, { title: 'Faux Book C' });
Promise.all([a, b, c]).then(async () => {
await Promise.all([a, b, c]).then(async () => {
let data = await $.get(url);
assert.isArray(data);
assert.isAtLeast(data.length, 3);
@ -214,8 +213,8 @@ async (getUserInput) => {
```js
/**
Backend challenges don't need solutions,
because they would need to be tested against a full working project.
Backend challenges don't need solutions,
because they would need to be tested against a full working project.
Please check our contributing guidelines to learn more.
*/
```

View File

@ -1,6 +1,6 @@
---
id: 5e7b9f060b6c005b0e76f05b
title: Build your own Functions
title: 編寫你自己的函數
challengeType: 11
videoId: nLDychdBwUg
dashedName: build-your-own-functions
@ -8,15 +8,15 @@ dashedName: build-your-own-functions
# --description--
More resources:
更多資源
\- [Exercise](https://www.youtube.com/watch?v=ksvGhDsjtpw)
\- [練習](https://www.youtube.com/watch?v=ksvGhDsjtpw)
# --question--
## --text--
What will the following Python program print out?:
下面這個 Python 程序會打印什麼?:
```python
def fred():

View File

@ -1,6 +1,6 @@
---
id: 5e7b9f0b0b6c005b0e76f06d
title: Comparing and Sorting Tuples
title: Tuples 的比較和排序
challengeType: 11
videoId: dZXzBXUxxCs
dashedName: comparing-and-sorting-tuples
@ -8,15 +8,15 @@ dashedName: comparing-and-sorting-tuples
# --description--
More resources:
更多資源:
\- [Exercise](https://www.youtube.com/watch?v=EhQxwzyT16E)
\- [練習](https://www.youtube.com/watch?v=EhQxwzyT16E)
# --question--
## --text--
Which does the same thing as the following code?:
哪個代碼與示例代碼完成相同的功能?
```python
lst = []

View File

@ -1,6 +1,6 @@
---
id: 5e7b9f050b6c005b0e76f058
title: Conditional Execution
title: 根據條件執行
challengeType: 11
videoId: gz_IfIsZQtc
dashedName: conditional-execution
@ -10,7 +10,7 @@ dashedName: conditional-execution
## --text--
Which code is indented correctly to print "Yes" if x = 0 and y = 10?
以下哪個代碼縮進能夠滿足當“x=0”和“y=10”的時打印 "Yes"
## --answers--

View File

@ -1,6 +1,6 @@
---
id: 5e7b9f6a0b6c005b0e76f097
title: 'Data Visualization: Mailing Lists'
title: '數據可視化:郵件列表'
challengeType: 11
videoId: RYdW660KkaQ
dashedName: data-visualization-mailing-lists
@ -8,27 +8,27 @@ dashedName: data-visualization-mailing-lists
# --description--
More resources:
更多資源:
\- [Exercise: Geodata](https://www.youtube.com/watch?v=KfhslNzopxo)
\- [練習:Geodata](https://www.youtube.com/watch?v=KfhslNzopxo)
\- [Exercise: Gmane Model](https://www.youtube.com/watch?v=wSpl1-7afAk)
\- [練習:Gmane 模型](https://www.youtube.com/watch?v=wSpl1-7afAk)
\- [Exercise: Gmane Spider](https://www.youtube.com/watch?v=H3w4lOFBUOI)
\- [練習:Gmane Spider](https://www.youtube.com/watch?v=H3w4lOFBUOI)
\- [Exercise: Gmane Viz](https://www.youtube.com/watch?v=LRqVPMEXByw)
\- [練習:Gmane Viz](https://www.youtube.com/watch?v=LRqVPMEXByw)
\- [Exercise: Page Rank](https://www.youtube.com/watch?v=yFRAZBkBDBs)
\- [練習:Page Rank](https://www.youtube.com/watch?v=yFRAZBkBDBs)
\- [Exercise: Page Spider](https://www.youtube.com/watch?v=sXedPQ_AnWA)
\- [練習:Page Spider](https://www.youtube.com/watch?v=sXedPQ_AnWA)
\- [Exercise: Page Viz](https://www.youtube.com/watch?v=Fm0hpkxsZoo)
\- [練習: Page Viz](https://www.youtube.com/watch?v=Fm0hpkxsZoo)
# --question--
## --text--
Which is a common JavaScript visualization library?
哪個是常見的 JavaScript 可視化庫?
## --answers--

View File

@ -1,6 +1,6 @@
---
id: 5e7b9f6a0b6c005b0e76f096
title: 'Data Visualization: Page Rank'
title: '數據可視化:頁面排名'
challengeType: 11
videoId: 6-w_qIUwaxU
dashedName: data-visualization-page-rank
@ -10,19 +10,19 @@ dashedName: data-visualization-page-rank
## --text--
How does the PageRank algorithm work?
頁面排名算法是如何工作的?
## --answers--
It determines which pages are most highly connected.
它決定哪些頁面之間的連接程度最高。
---
It ranks pages based on view counts.
它用瀏覽量來決定排名
---
It figures out which pages contain the most important content.
它能判斷出哪些頁面包含最重要的內容。
## --video-solution--

View File

@ -1,6 +1,6 @@
---
id: 5e7b9f0a0b6c005b0e76f069
title: Dictionaries and Loops
title: 字典和循環
challengeType: 11
videoId: EEmekKiKG70
dashedName: dictionaries-and-loops
@ -8,15 +8,15 @@ dashedName: dictionaries-and-loops
# --description--
More resources:
更多資源:
\- [Exercise](https://www.youtube.com/watch?v=PrhZ9qwBDD8)
\- [練習](https://www.youtube.com/watch?v=PrhZ9qwBDD8)
# --question--
## --text--
What will the following code print?:
以下代碼將打印什麼?
```python
counts = { 'chuck' : 1 , 'annie' : 42, 'jan': 100}
@ -42,7 +42,7 @@ jan 100</pre>
---
<pre>[Error]</pre>
<pre>[Error](錯誤)</pre>
## --video-solution--

View File

@ -1,6 +1,6 @@
---
id: 5e7b9f070b6c005b0e76f061
title: Intermediate Strings
title: 中間字符串
challengeType: 11
videoId: KgT_fYLXnyk
dashedName: intermediate-strings
@ -8,15 +8,15 @@ dashedName: intermediate-strings
# --description--
More resources:
更多資料:
\- [Exercise](https://www.youtube.com/watch?v=1bSqHot-KwE)
[練習](https://www.youtube.com/watch?v=1bSqHot-KwE)
# --question--
## --text--
What is the value of i in the following code?
下面的代碼中 i 的值是什麼?
```python
word = "bananana"
@ -37,7 +37,7 @@ nanana
---
True
True(真)
---

View File

@ -1,6 +1,6 @@
---
id: 5e6a54c358d3af90110a60a3
title: 'Introduction: Elements of Python'
title: '導言:Python 的元素'
challengeType: 11
videoId: aRY_xjL35v0
dashedName: introduction-elements-of-python
@ -10,7 +10,7 @@ dashedName: introduction-elements-of-python
## --text--
What will the following program print out:
以下代碼將打印出什麼?
```python
x = 43

View File

@ -1,6 +1,6 @@
---
id: 5e6a54af58d3af90110a60a1
title: 'Introduction: Hardware Architecture'
title: '導言:硬件架構'
challengeType: 11
videoId: H6qtjRTfSog
dashedName: introduction-hardware-architecture
@ -10,19 +10,19 @@ dashedName: introduction-hardware-architecture
## --text--
Where are your programs stored when they are running?
當你的程序運作時,它被存儲在哪裏?
## --answers--
Hard Drive.
硬盤。
---
Memory.
內存。
---
Central Processing Unit.
中央處理器。
## --video-solution--

View File

@ -1,6 +1,6 @@
---
id: 5e6a54ba58d3af90110a60a2
title: 'Introduction: Python as a Language'
title: '導言Python 這門編程語言'
challengeType: 11
videoId: 0QeGbZNS_bY
dashedName: introduction-python-as-a-language
@ -10,7 +10,7 @@ dashedName: introduction-python-as-a-language
## --text--
What will print out after running these two lines of code:
運行這兩行代碼後打印出什麼樣的內容:
```python
x = 6

View File

@ -1,6 +1,6 @@
---
id: 5e6a54a558d3af90110a60a0
title: 'Introduction: Why Program?'
title: '導言:爲何編程?'
challengeType: 11
videoId: 3muQV-Im3Z0
dashedName: introduction-why-program
@ -8,29 +8,29 @@ dashedName: introduction-why-program
# --description--
More resources:
更多資源:
\- [Install Python on Windows](https://youtu.be/F7mtLrYzZP8)
\- [Windows 系統安裝 Python](https://youtu.be/F7mtLrYzZP8)
\- [Install Python on MacOS](https://youtu.be/wfLnZP-4sZw)
\- [MacOS 系統安裝 Python](https://youtu.be/wfLnZP-4sZw)
# --question--
## --text--
Who should learn to program?
誰應該學習編程?
## --answers--
College students.
大學生。
---
People who want to become software developers.
想成爲軟件開發者的人。
---
Everyone.
所有人。
## --video-solution--

View File

@ -1,6 +1,6 @@
---
id: 5e7b9f070b6c005b0e76f05d
title: 'Iterations: Definite Loops'
title: '迭代:定義循環'
challengeType: 11
videoId: hiRTRAqNlpE
dashedName: iterations-definite-loops
@ -10,7 +10,7 @@ dashedName: iterations-definite-loops
## --text--
How many lines will the following code print?:
以下代碼將打印多少行?
```python
for i in [2,1,5]:

View File

@ -1,6 +1,6 @@
---
id: 5e7b9f070b6c005b0e76f05e
title: 'Iterations: Loop Idioms'
title: '迭代:循環成語'
challengeType: 11
videoId: AelGAcoMXbI
dashedName: iterations-loop-idioms
@ -10,7 +10,7 @@ dashedName: iterations-loop-idioms
## --text--
Below is code to find the smallest value from a list of values. One line has an error that will cause the code to not work as expected. Which line is it?:
以下是一個如何在一串數值中找到最小的數值的代碼。 一行代碼有錯誤,導致整個代碼無法和預期一樣的運行。 那麼是哪一行?
```python
smallest = None

View File

@ -1,6 +1,6 @@
---
id: 5e7b9f070b6c005b0e76f05f
title: 'Iterations: More Patterns'
title: '迭代:更多模式'
challengeType: 11
videoId: 9Wtqo6vha1M
dashedName: iterations-more-patterns
@ -8,15 +8,15 @@ dashedName: iterations-more-patterns
# --description--
More resources:
更多資源:
\- [Exercise](https://www.youtube.com/watch?v=kjxXZQw0uPg)
\- [練習](https://www.youtube.com/watch?v=kjxXZQw0uPg)
# --question--
## --text--
Which of these evaluates to False?
其中哪一個評估爲 False(假)?
## --answers--

View File

@ -1,6 +1,6 @@
---
id: 5e7b9f060b6c005b0e76f05c
title: Loops and Iterations
title: 循環和迭代
challengeType: 11
videoId: dLA-szNRnUY
dashedName: loops-and-iterations
@ -10,7 +10,7 @@ dashedName: loops-and-iterations
## --text--
What will the following code print out?:
這些代碼會打印出什麼?
```python
n = 0

View File

@ -1,6 +1,6 @@
---
id: 5e7b9f170b6c005b0e76f08b
title: Make a Relational Database
title: 建立關係數據庫
challengeType: 11
videoId: MQ5z4bdF92U
dashedName: make-a-relational-database
@ -10,7 +10,7 @@ dashedName: make-a-relational-database
## --text--
What SQL command would you use to retrieve all users that have the email address `quincy@freecodecamp.org`?
您將使用什麼 SQL 命令來檢索具有電子郵件地址 `quincy@freecodecamp.org` 的所有用戶?
## --answers--

View File

@ -1,6 +1,6 @@
---
id: 5e7b9f060b6c005b0e76f059
title: More Conditional Structures
title: 更多條件結構
challengeType: 11
videoId: HdL82tAZR20
dashedName: more-conditional-structures
@ -8,17 +8,17 @@ dashedName: more-conditional-structures
# --description--
More resources:
更多資源:
\- [Exercise 1](https://www.youtube.com/watch?v=crLerB4ZxMI)
\- [練習 1](https://www.youtube.com/watch?v=crLerB4ZxMI)
\- [Exercise 2](https://www.youtube.com/watch?v=KJN3-7HH6yk)
\- [練習 2](https://www.youtube.com/watch?v=KJN3-7HH6yk)
# --question--
## --text--
Given the following code:
給出以下代碼:
```python
temp = "5 degrees"
@ -28,7 +28,7 @@ cel = (fahr - 32.0) * 5.0 / 9.0
print(cel)
```
Which line/lines should be surrounded by `try` block?
哪一行/幾行應該被 `try` 塊包圍?
## --answers--
@ -40,7 +40,7 @@ Which line/lines should be surrounded by `try` block?
---
3,4
34
---
@ -48,7 +48,7 @@ Which line/lines should be surrounded by `try` block?
---
None
## --video-solution--

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