`, you will be redirected to the original URL.
+
+```js
+async (getUserInput) => {
+ const url = getUserInput('url');
+ const urlVariable = Date.now();
+ const fullUrl = `${url}/?v=${urlVariable}`
+ let shortenedUrlVariable;
+ const postResponse = await fetch(url + '/api/shorturl', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+ body: `url=${fullUrl}`
+ });
+ if (postResponse.ok) {
+ const { short_url } = await postResponse.json();
+ shortenedUrlVariable = short_url;
+ } else {
+ throw new Error(`${postResponse.status} ${postResponse.statusText}`);
+ }
+ const getResponse = await fetch(
+ url + '/api/shorturl/' + shortenedUrlVariable
+ );
+ if (getResponse) {
+ const { redirected, url } = getResponse;
+ assert.isTrue(redirected);
+ assert.strictEqual(url,fullUrl);
+ } else {
+ throw new Error(`${getResponse.status} ${getResponse.statusText}`);
+ }
+};
+```
+
+If you pass an invalid URL that doesn't follow the valid `http://www.example.com` format, the JSON response will contain `{ error: 'invalid url' }`
+
+```js
+async (getUserInput) => {
+ const url = getUserInput('url');
+ const res = await fetch(url + '/api/shorturl', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+ body: `url=ftp:/john-doe.org`
+ });
+ if (res.ok) {
+ const { error } = await res.json();
+ assert.isNotNull(error);
+ assert.strictEqual(error.toLowerCase(), 'invalid url');
+ } else {
+ throw new Error(`${res.status} ${res.statusText}`);
+ }
+};
+```
+
+# --solutions--
+
+```js
+/**
+ 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.
+*/
+```
diff --git a/curriculum/challenges/ukrainian/08-data-analysis-with-python/data-analysis-with-python-projects/demographic-data-analyzer.md b/curriculum/challenges/ukrainian/08-data-analysis-with-python/data-analysis-with-python-projects/demographic-data-analyzer.md
new file mode 100644
index 00000000000000..9b67fad6306a7d
--- /dev/null
+++ b/curriculum/challenges/ukrainian/08-data-analysis-with-python/data-analysis-with-python-projects/demographic-data-analyzer.md
@@ -0,0 +1,78 @@
+---
+id: 5e46f7e5ac417301a38fb929
+title: Demographic Data Analyzer
+challengeType: 10
+forumTopicId: 462367
+dashedName: demographic-data-analyzer
+---
+
+# --description--
+
+You will be [working on this project with our Replit starter code](https://replit.com/github/freeCodeCamp/boilerplate-demographic-data-analyzer).
+
+We are still developing the interactive instructional part of the Python curriculum. For now, here are some videos on the freeCodeCamp.org YouTube channel that will teach you everything you need to know to complete this project:
+
+- [Python for Everybody Video Course](https://www.freecodecamp.org/news/python-for-everybody/) (14 hours)
+- [Learn Python Video Course](https://www.freecodecamp.org/news/learn-python-video-course/) (10 hours)
+
+# --instructions--
+
+In this challenge you must analyze demographic data using Pandas. You are given a dataset of demographic data that was extracted from the 1994 Census database. Here is a sample of what the data looks like:
+
+```markdown
+| | age | workclass | fnlwgt | education | education-num | marital-status | occupation | relationship | race | sex | capital-gain | capital-loss | hours-per-week | native-country | salary |
+|---:|------:|:-----------------|---------:|:------------|----------------:|:-------------------|:------------------|:---------------|:-------|:-------|---------------:|---------------:|-----------------:|:-----------------|:---------|
+| 0 | 39 | State-gov | 77516 | Bachelors | 13 | Never-married | Adm-clerical | Not-in-family | White | Male | 2174 | 0 | 40 | United-States | <=50K |
+| 1 | 50 | Self-emp-not-inc | 83311 | Bachelors | 13 | Married-civ-spouse | Exec-managerial | Husband | White | Male | 0 | 0 | 13 | United-States | <=50K |
+| 2 | 38 | Private | 215646 | HS-grad | 9 | Divorced | Handlers-cleaners | Not-in-family | White | Male | 0 | 0 | 40 | United-States | <=50K |
+| 3 | 53 | Private | 234721 | 11th | 7 | Married-civ-spouse | Handlers-cleaners | Husband | Black | Male | 0 | 0 | 40 | United-States | <=50K |
+| 4 | 28 | Private | 338409 | Bachelors | 13 | Married-civ-spouse | Prof-specialty | Wife | Black | Female | 0 | 0 | 40 | Cuba | <=50K |
+```
+
+You must use Pandas to answer the following questions:
+
+- How many people of each race are represented in this dataset? This should be a Pandas series with race names as the index labels. (`race` column)
+- What is the average age of men?
+- What is the percentage of people who have a Bachelor's degree?
+- What percentage of people with advanced education (`Bachelors`, `Masters`, or `Doctorate`) make more than 50K?
+- What percentage of people without advanced education make more than 50K?
+- What is the minimum number of hours a person works per week?
+- What percentage of the people who work the minimum number of hours per week have a salary of more than 50K?
+- What country has the highest percentage of people that earn >50K and what is that percentage?
+- Identify the most popular occupation for those who earn >50K in India.
+
+Use the starter code in the file `demographic_data_analyzer`. Update the code so all variables set to "None" are set to the appropriate calculation or code. Round all decimals to the nearest tenth.
+
+Unit tests are written for you under `test_module.py`.
+
+## Development
+
+For development, you can use `main.py` to test your functions. Click the "run" button and `main.py` will run.
+
+## Testing
+
+We imported the tests from `test_module.py` to `main.py` for your convenience. The tests will run automatically whenever you hit the "run" button.
+
+## Submitting
+
+Copy your project's URL and submit it to freeCodeCamp.
+
+## Dataset Source
+
+Dua, D. and Graff, C. (2019). [UCI Machine Learning Repository](http://archive.ics.uci.edu/ml). Irvine, CA: University of California, School of Information and Computer Science.
+
+# --hints--
+
+It should pass all Python tests.
+
+```js
+
+```
+
+# --solutions--
+
+```py
+ # Python 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.
+```
diff --git a/curriculum/challenges/ukrainian/08-data-analysis-with-python/data-analysis-with-python-projects/mean-variance-standard-deviation-calculator.md b/curriculum/challenges/ukrainian/08-data-analysis-with-python/data-analysis-with-python-projects/mean-variance-standard-deviation-calculator.md
new file mode 100644
index 00000000000000..447e9ece0b28fd
--- /dev/null
+++ b/curriculum/challenges/ukrainian/08-data-analysis-with-python/data-analysis-with-python-projects/mean-variance-standard-deviation-calculator.md
@@ -0,0 +1,80 @@
+---
+id: 5e46f7e5ac417301a38fb928
+title: Mean-Variance-Standard Deviation Calculator
+challengeType: 10
+forumTopicId: 462366
+dashedName: mean-variance-standard-deviation-calculator
+---
+
+# --description--
+
+You will be [working on this project with our Replit starter code](https://replit.com/github/freeCodeCamp/boilerplate-mean-variance-standard-deviation-calculator).
+
+We are still developing the interactive instructional part of the Python curriculum. For now, here are some videos on the freeCodeCamp.org YouTube channel that will teach you everything you need to know to complete this project:
+
+- [Python for Everybody Video Course](https://www.freecodecamp.org/news/python-for-everybody/) (14 hours)
+- [Learn Python Video Course](https://www.freecodecamp.org/news/learn-python-video-course/) (10 hours)
+
+# --instructions--
+
+Create a function named `calculate()` in `mean_var_std.py` that uses Numpy to output the mean, variance, standard deviation, max, min, and sum of the rows, columns, and elements in a 3 x 3 matrix.
+
+The input of the function should be a list containing 9 digits. The function should convert the list into a 3 x 3 Numpy array, and then return a dictionary containing the mean, variance, standard deviation, max, min, and sum along both axes and for the flattened matrix.
+
+The returned dictionary should follow this format:
+
+```py
+{
+ 'mean': [axis1, axis2, flattened],
+ 'variance': [axis1, axis2, flattened],
+ 'standard deviation': [axis1, axis2, flattened],
+ 'max': [axis1, axis2, flattened],
+ 'min': [axis1, axis2, flattened],
+ 'sum': [axis1, axis2, flattened]
+}
+```
+
+If a list containing less than 9 elements is passed into the function, it should raise a `ValueError` exception with the message: "List must contain nine numbers." The values in the returned dictionary should be lists and not Numpy arrays.
+
+For example, `calculate([0,1,2,3,4,5,6,7,8])` should return:
+
+```py
+{
+ 'mean': [[3.0, 4.0, 5.0], [1.0, 4.0, 7.0], 4.0],
+ 'variance': [[6.0, 6.0, 6.0], [0.6666666666666666, 0.6666666666666666, 0.6666666666666666], 6.666666666666667],
+ 'standard deviation': [[2.449489742783178, 2.449489742783178, 2.449489742783178], [0.816496580927726, 0.816496580927726, 0.816496580927726], 2.581988897471611],
+ 'max': [[6, 7, 8], [2, 5, 8], 8],
+ 'min': [[0, 1, 2], [0, 3, 6], 0],
+ 'sum': [[9, 12, 15], [3, 12, 21], 36]
+}
+```
+
+The unit tests for this project are in `test_module.py`.
+
+## Development
+
+For development, you can use `main.py` to test your `calculate()` function. Click the "run" button and `main.py` will run.
+
+## Testing
+
+We imported the tests from `test_module.py` to `main.py` for your convenience. The tests will run automatically whenever you hit the "run" button.
+
+## Submitting
+
+Copy your project's URL and submit it to freeCodeCamp.
+
+# --hints--
+
+It should pass all Python tests.
+
+```js
+
+```
+
+# --solutions--
+
+```py
+ # Python 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.
+```
diff --git a/curriculum/challenges/ukrainian/08-data-analysis-with-python/data-analysis-with-python-projects/medical-data-visualizer.md b/curriculum/challenges/ukrainian/08-data-analysis-with-python/data-analysis-with-python-projects/medical-data-visualizer.md
new file mode 100644
index 00000000000000..540499ebf56bd6
--- /dev/null
+++ b/curriculum/challenges/ukrainian/08-data-analysis-with-python/data-analysis-with-python-projects/medical-data-visualizer.md
@@ -0,0 +1,90 @@
+---
+id: 5e46f7f8ac417301a38fb92a
+title: Medical Data Visualizer
+challengeType: 10
+forumTopicId: 462368
+dashedName: medical-data-visualizer
+---
+
+# --description--
+
+You will be [working on this project with our Replit starter code](https://replit.com/github/freeCodeCamp/boilerplate-medical-data-visualizer).
+
+We are still developing the interactive instructional part of the Python curriculum. For now, here are some videos on the freeCodeCamp.org YouTube channel that will teach you everything you need to know to complete this project:
+
+- [Python for Everybody Video Course](https://www.freecodecamp.org/news/python-for-everybody/) (14 hours)
+- [Learn Python Video Course](https://www.freecodecamp.org/news/learn-python-video-course/) (10 hours)
+
+# --instructions--
+
+In this project, you will visualize and make calculations from medical examination data using matplotlib, seaborn, and pandas. The dataset values were collected during medical examinations.
+
+## Data description
+
+The rows in the dataset represent patients and the columns represent information like body measurements, results from various blood tests, and lifestyle choices. You will use the dataset to explore the relationship between cardiac disease, body measurements, blood markers, and lifestyle choices.
+
+File name: medical_examination.csv
+
+| Feature | Variable Type | Variable | Value Type |
+|:-------:|:------------:|:-------------:|:----------:|
+| Age | Objective Feature | age | int (days) |
+| Height | Objective Feature | height | int (cm) |
+| Weight | Objective Feature | weight | float (kg) |
+| Gender | Objective Feature | gender | categorical code |
+| Systolic blood pressure | Examination Feature | ap_hi | int |
+| Diastolic blood pressure | Examination Feature | ap_lo | int |
+| Cholesterol | Examination Feature | cholesterol | 1: normal, 2: above normal, 3: well above normal |
+| Glucose | Examination Feature | gluc | 1: normal, 2: above normal, 3: well above normal |
+| Smoking | Subjective Feature | smoke | binary |
+| Alcohol intake | Subjective Feature | alco | binary |
+| Physical activity | Subjective Feature | active | binary |
+| Presence or absence of cardiovascular disease | Target Variable | cardio | binary |
+
+## Tasks
+
+Create a chart similar to `examples/Figure_1.png`, where we show the counts of good and bad outcomes for the `cholesterol`, `gluc`, `alco`, `active`, and `smoke` variables for patients with cardio=1 and cardio=0 in different panels.
+
+Use the data to complete the following tasks in `medical_data_visualizer.py`:
+
+- Add an `overweight` column to the data. To determine if a person is overweight, first calculate their BMI by dividing their weight in kilograms by the square of their height in meters. If that value is > 25 then the person is overweight. Use the value 0 for NOT overweight and the value 1 for overweight.
+- Normalize the data by making 0 always good and 1 always bad. If the value of `cholesterol` or `gluc` is 1, make the value 0. If the value is more than 1, make the value 1.
+- Convert the data into long format and create a chart that shows the value counts of the categorical features using seaborn's `catplot()`. The dataset should be split by 'Cardio' so there is one chart for each `cardio` value. The chart should look like `examples/Figure_1.png`.
+- Clean the data. Filter out the following patient segments that represent incorrect data:
+ - diastolic pressure is higher than systolic (Keep the correct data with `(df['ap_lo'] <= df['ap_hi'])`)
+ - height is less than the 2.5th percentile (Keep the correct data with `(df['height'] >= df['height'].quantile(0.025))`)
+ - height is more than the 97.5th percentile
+ - weight is less than the 2.5th percentile
+ - weight is more than the 97.5th percentile
+- Create a correlation matrix using the dataset. Plot the correlation matrix using seaborn's `heatmap()`. Mask the upper triangle. The chart should look like `examples/Figure_2.png`.
+
+Any time a variable is set to `None`, make sure to set it to the correct code.
+
+Unit tests are written for you under `test_module.py`.
+
+## Development
+
+For development, you can use `main.py` to test your functions. Click the "run" button and `main.py` will run.
+
+## Testing
+
+We imported the tests from `test_module.py` to `main.py` for your convenience. The tests will run automatically whenever you hit the "run" button.
+
+## Submitting
+
+Copy your project's URL and submit it to freeCodeCamp.
+
+# --hints--
+
+It should pass all Python tests.
+
+```js
+
+```
+
+# --solutions--
+
+```py
+ # Python 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.
+```
diff --git a/curriculum/challenges/ukrainian/08-data-analysis-with-python/data-analysis-with-python-projects/page-view-time-series-visualizer.md b/curriculum/challenges/ukrainian/08-data-analysis-with-python/data-analysis-with-python-projects/page-view-time-series-visualizer.md
new file mode 100644
index 00000000000000..2ca374ca72b793
--- /dev/null
+++ b/curriculum/challenges/ukrainian/08-data-analysis-with-python/data-analysis-with-python-projects/page-view-time-series-visualizer.md
@@ -0,0 +1,60 @@
+---
+id: 5e46f802ac417301a38fb92b
+title: Page View Time Series Visualizer
+challengeType: 10
+forumTopicId: 462369
+dashedName: page-view-time-series-visualizer
+---
+
+# --description--
+
+You will be [working on this project with our Replit starter code](https://replit.com/github/freeCodeCamp/boilerplate-page-view-time-series-visualizer).
+
+We are still developing the interactive instructional part of the Python curriculum. For now, here are some videos on the freeCodeCamp.org YouTube channel that will teach you everything you need to know to complete this project:
+
+- [Python for Everybody Video Course](https://www.freecodecamp.org/news/python-for-everybody/) (14 hours)
+- [Learn Python Video Course](https://www.freecodecamp.org/news/learn-python-video-course/) (10 hours)
+
+# --instructions--
+
+For this project you will visualize time series data using a line chart, bar chart, and box plots. You will use Pandas, Matplotlib, and Seaborn to visualize a dataset containing the number of page views each day on the freeCodeCamp.org forum from 2016-05-09 to 2019-12-03. The data visualizations will help you understand the patterns in visits and identify yearly and monthly growth.
+
+Use the data to complete the following tasks:
+
+- Use Pandas to import the data from "fcc-forum-pageviews.csv". Set the index to the "date" column.
+- Clean the data by filtering out days when the page views were in the top 2.5% of the dataset or bottom 2.5% of the dataset.
+- Create a `draw_line_plot` function that uses Matplotlib to draw a line chart similar to "examples/Figure_1.png". The title should be "Daily freeCodeCamp Forum Page Views 5/2016-12/2019". The label on the x axis should be "Date" and the label on the y axis should be "Page Views".
+- Create a `draw_bar_plot` function that draws a bar chart similar to "examples/Figure_2.png". It should show average daily page views for each month grouped by year. The legend should show month labels and have a title of "Months". On the chart, the label on the x axis should be "Years" and the label on the y axis should be "Average Page Views".
+- Create a `draw_box_plot` function that uses Searborn to draw two adjacent box plots similar to "examples/Figure_3.png". These box plots should show how the values are distributed within a given year or month and how it compares over time. The title of the first chart should be "Year-wise Box Plot (Trend)" and the title of the second chart should be "Month-wise Box Plot (Seasonality)". Make sure the month labels on bottom start at "Jan" and the x and x axis are labeled correctly. The boilerplate includes commands to prepare the data.
+
+For each chart, make sure to use a copy of the data frame. Unit tests are written for you under `test_module.py`.
+
+The boilerplate also includes commands to save and return the image.
+
+## Development
+
+For development, you can use `main.py` to test your functions. Click the "run" button and `main.py` will run.
+
+## Testing
+
+We imported the tests from `test_module.py` to `main.py` for your convenience. The tests will run automatically whenever you hit the "run" button.
+
+## Submitting
+
+Copy your project's URL and submit it to freeCodeCamp.
+
+# --hints--
+
+It should pass all Python tests.
+
+```js
+
+```
+
+# --solutions--
+
+```py
+ # Python 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.
+```
diff --git a/curriculum/challenges/ukrainian/08-data-analysis-with-python/data-analysis-with-python-projects/sea-level-predictor.md b/curriculum/challenges/ukrainian/08-data-analysis-with-python/data-analysis-with-python-projects/sea-level-predictor.md
new file mode 100644
index 00000000000000..04742507b64f28
--- /dev/null
+++ b/curriculum/challenges/ukrainian/08-data-analysis-with-python/data-analysis-with-python-projects/sea-level-predictor.md
@@ -0,0 +1,64 @@
+---
+id: 5e4f5c4b570f7e3a4949899f
+title: Sea Level Predictor
+challengeType: 10
+forumTopicId: 462370
+dashedName: sea-level-predictor
+---
+
+# --description--
+
+You will be [working on this project with our Replit starter code](https://replit.com/github/freeCodeCamp/boilerplate-sea-level-predictor).
+
+We are still developing the interactive instructional part of the Python curriculum. For now, here are some videos on the freeCodeCamp.org YouTube channel that will teach you everything you need to know to complete this project:
+
+- [Python for Everybody Video Course](https://www.freecodecamp.org/news/python-for-everybody/) (14 hours)
+- [Learn Python Video Course](https://www.freecodecamp.org/news/learn-python-video-course/) (10 hours)
+
+# --instructions--
+
+You will analyze a dataset of the global average sea level change since 1880. You will use the data to predict the sea level change through year 2050.
+
+Use the data to complete the following tasks:
+
+- Use Pandas to import the data from `epa-sea-level.csv`.
+- Use matplotlib to create a scatter plot using the "Year" column as the x-axis and the "CSIRO Adjusted Sea Level" column as the y-axix.
+- Use the `linregress` function from `scipy.stats` to get the slope and y-intercept of the line of best fit. Plot the line of best fit over the top of the scatter plot. Make the line go through the year 2050 to predict the sea level rise in 2050.
+- Plot a new line of best fit just using the data from year 2000 through the most recent year in the dataset. Make the line also go through the year 2050 to predict the sea level rise in 2050 if the rate of rise continues as it has since the year 2000.
+- The x label should be "Year", the y label should be "Sea Level (inches)", and the title should be "Rise in Sea Level".
+
+Unit tests are written for you under `test_module.py`.
+
+The boilerplate also includes commands to save and return the image.
+
+## Development
+
+For development, you can use `main.py` to test your functions. Click the "run" button and `main.py` will run.
+
+## Testing
+
+We imported the tests from `test_module.py` to `main.py` for your convenience. The tests will run automatically whenever you hit the "run" button.
+
+## Submitting
+
+Copy your project's URL and submit it to freeCodeCamp.
+
+## Data Source
+[Global Average Absolute Sea Level Change](https://datahub.io/core/sea-level-rise), 1880-2014 from the US Environmental Protection Agency using data from CSIRO, 2015; NOAA, 2015.
+
+
+# --hints--
+
+It should pass all Python tests.
+
+```js
+
+```
+
+# --solutions--
+
+```py
+ # Python 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.
+```
diff --git a/curriculum/challenges/ukrainian/09-information-security/information-security-projects/anonymous-message-board.md b/curriculum/challenges/ukrainian/09-information-security/information-security-projects/anonymous-message-board.md
new file mode 100644
index 00000000000000..b7be38cf5fe4d9
--- /dev/null
+++ b/curriculum/challenges/ukrainian/09-information-security/information-security-projects/anonymous-message-board.md
@@ -0,0 +1,172 @@
+---
+id: 587d824a367417b2b2512c45
+title: Anonymous Message Board
+challengeType: 4
+forumTopicId: 301568
+dashedName: anonymous-message-board
+---
+
+# --description--
+
+Build a full stack JavaScript app that is functionally similar to this: .
+
+Working on this project will involve you writing your code using one of the following methods:
+
+- Clone [this GitHub repo](https://github.com/freeCodeCamp/boilerplate-project-messageboard/) and complete your project locally.
+- Use [our Replit starter project](https://replit.com/github/freeCodeCamp/boilerplate-project-messageboard) to complete your project.
+- Use a site builder of your choice to complete the project. Be sure to incorporate all the files from our GitHub repo.
+
+When you are done, make sure a working demo of your project is hosted somewhere public. Then submit the URL to it in the `Solution Link` field. Optionally, also submit a link to your project's source code in the `GitHub Link` field.
+
+# --instructions--
+
+1. Set `NODE_ENV` to test without quotes when ready to write tests and DB to your databases connection string (in `.env`)
+2. Recommended to create controllers/handlers and handle routing in `routes/api.js`
+3. You will add any security features to `server.js`
+
+Write the following tests in `tests/2_functional-tests.js`:
+
+- Creating a new thread: POST request to `/api/threads/{board}`
+- Viewing the 10 most recent threads with 3 replies each: GET request to `/api/threads/{board}`
+- Deleting a thread with the incorrect password: DELETE request to `/api/threads/{board}` with an invalid `delete_password`
+- Deleting a thread with the correct password: DELETE request to `/api/threads/{board}` with a valid `delete_password`
+- Reporting a thread: PUT request to `/api/threads/{board}`
+- Creating a new reply: POST request to `/api/replies/{board}`
+- Viewing a single thread with all replies: GET request to `/api/replies/{board}`
+- Deleting a reply with the incorrect password: DELETE request to `/api/replies/{board}` with an invalid `delete_password`
+- Deleting a reply with the correct password: DELETE request to `/api/replies/{board}` with a valid `delete_password`
+- Reporting a reply: PUT request to `/api/replies/{board}`
+
+# --hints--
+
+You can provide your own project, not the example URL.
+
+```js
+(getUserInput) => {
+ assert(
+ !/.*\/anonymous-message-board\.freecodecamp\.rocks/.test(
+ getUserInput('url')
+ )
+ );
+};
+```
+
+Only allow your site to be loaded in an iFrame on your own pages.
+
+```js
+async (getUserInput) => {
+ const data = await fetch(getUserInput('url') + '/_api/app-info');
+ const parsed = await data.json();
+ assert.isTrue(parsed.headers['x-frame-options']?.includes('SAMEORIGIN'));
+};
+```
+
+Do not allow DNS prefetching.
+
+```js
+async (getUserInput) => {
+ const data = await fetch(getUserInput('url') + '/_api/app-info');
+ const parsed = await data.json();
+ assert.isTrue(parsed.headers['x-dns-prefetch-control']?.includes('off'));
+};
+```
+
+Only allow your site to send the referrer for your own pages.
+
+```js
+async (getUserInput) => {
+ const data = await fetch(getUserInput('url') + '/_api/app-info');
+ const parsed = await data.json();
+ assert.isTrue(parsed.headers['referrer-policy']?.includes('same-origin'));
+};
+```
+
+You can send a POST request to `/api/threads/{board}` with form data including `text` and `delete_password`. The saved database record will have at least the fields `_id`, `text`, `created_on`(date & time), `bumped_on`(date & time, starts same as `created_on`), `reported` (boolean), `delete_password`, & `replies` (array).
+
+```js
+async (getUserInput) => {
+ const date = new Date();
+ const text = `fcc_test_${date}`;
+ const deletePassword = 'delete_me';
+ const data = { text, delete_password: deletePassword };
+ const url = getUserInput('url');
+ const res = await fetch(url + '/api/threads/fcc_test', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(data)
+ });
+ if (res.ok) {
+ const checkData = await fetch(url + '/api/threads/fcc_test');
+ const parsed = await checkData.json();
+ try {
+ assert.equal(parsed[0].text, text);
+ assert.isNotNull(parsed[0]._id);
+ assert.equal(new Date(parsed[0].created_on).toDateString(), date.toDateString());
+ assert.equal(parsed[0].bumped_on, parsed[0].created_on);
+ assert.isArray(parsed[0].replies);
+ } catch (err) {
+ throw new Error(err.responseText || err.message);
+ }
+ } else {
+ throw new Error(`${res.status} ${res.statusText}`);
+ }
+};
+```
+
+You can send a POST request to `/api/replies/{board}` with form data including `text`, `delete_password`, & `thread_id`. This will update the `bumped_on` date to the comment's date. In the thread's `replies` array, an object will be saved with at least the properties `_id`, `text`, `created_on`, `delete_password`, & `reported`.
+
+```js
+
+```
+
+You can send a GET request to `/api/threads/{board}`. Returned will be an array of the most recent 10 bumped threads on the board with only the most recent 3 replies for each. The `reported` and `delete_password` fields will not be sent to the client.
+
+```js
+
+```
+
+You can send a GET request to `/api/replies/{board}?thread_id={thread_id}`. Returned will be the entire thread with all its replies, also excluding the same fields from the client as the previous test.
+
+```js
+
+```
+
+You can send a DELETE request to `/api/threads/{board}` and pass along the `thread_id` & `delete_password` to delete the thread. Returned will be the string `incorrect password` or `success`.
+
+```js
+
+```
+
+You can send a DELETE request to `/api/replies/{board}` and pass along the `thread_id`, `reply_id`, & `delete_password`. Returned will be the string `incorrect password` or `success`. On success, the text of the `reply_id` will be changed to `[deleted]`.
+
+```js
+
+```
+
+You can send a PUT request to `/api/threads/{board}` and pass along the `thread_id`. Returned will be the string `success`. The `reported` value of the `thread_id` will be changed to `true`.
+
+```js
+
+```
+
+You can send a PUT request to `/api/replies/{board}` and pass along the `thread_id` & `reply_id`. Returned will be the string `success`. The `reported` value of the `reply_id` will be changed to `true`.
+
+```js
+
+```
+
+All 10 functional tests are complete and passing.
+
+```js
+
+```
+
+# --solutions--
+
+```js
+/**
+ 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.
+*/
+```
diff --git a/curriculum/challenges/ukrainian/09-information-security/information-security-projects/port-scanner.md b/curriculum/challenges/ukrainian/09-information-security/information-security-projects/port-scanner.md
new file mode 100644
index 00000000000000..10c950657d68b1
--- /dev/null
+++ b/curriculum/challenges/ukrainian/09-information-security/information-security-projects/port-scanner.md
@@ -0,0 +1,95 @@
+---
+id: 5e46f979ac417301a38fb932
+title: Port Scanner
+challengeType: 10
+forumTopicId: 462372
+helpCategory: Python
+dashedName: port-scanner
+---
+
+# --description--
+
+You will be [working on this project with our Replit starter code](https://replit.com/github/freeCodeCamp/boilerplate-port-scanner).
+
+We are still developing the interactive instructional part of the Python curriculum. For now, here are some videos on the freeCodeCamp.org YouTube channel that will teach you everything you need to know to complete this project:
+
+- [Python for Everybody Video Course](https://www.freecodecamp.org/news/python-for-everybody/) (14 hours)
+
+- [Learn Python Video Course](https://www.freecodecamp.org/news/learn-python-video-course/) (10 hours)
+
+# --instructions--
+
+Create a port scanner using Python.
+
+In the `port_scanner.py` file, create a function called `get_open_ports` that takes a `target` argument and a `port_range` argument. `target` can be a URL or IP address. `port_range` is a list of two numbers indicating the first and last numbers of the range of ports to check.
+
+Here are examples of how the function may be called:
+
+```py
+get_open_ports("209.216.230.240", [440, 445])
+get_open_ports("www.stackoverflow.com", [79, 82])
+```
+
+The function should return a list of open ports in the given range.
+
+The `get_open_ports` function should also take an optional third argument of `True` to indicate "Verbose" mode. If this is set to true, the function should return a descriptive string instead of a list of ports.
+
+Here is the format of the string that should be returned in verbose mode (text inside `{}` indicates the information that should appear):
+
+```bash
+Open ports for {URL} ({IP address})
+PORT SERVICE
+{port} {service name}
+{port} {service name}
+```
+
+You can use the dictionary in `common_ports.py` to get the correct service name for each port.
+
+For example, if the function is called like this:
+
+```py
+port_scanner.get_open_ports("scanme.nmap.org", [20, 80], True)
+```
+
+It should return the following:
+
+```bash
+Open ports for scanme.nmap.org (45.33.32.156)
+PORT SERVICE
+22 ssh
+80 http
+```
+
+Make sure to include proper spacing and new line characters.
+
+If the URL passed into the `get_open_ports` function is invalid, the function should return the string: "Error: Invalid hostname".
+
+If the IP address passed into the `get_open_ports` function is invalid, the function should return the string: "Error: Invalid IP address".
+
+## Development
+
+Write your code in `port_scanner.py`. For development, you can use `main.py` to test your code. Click the "run" button and `main.py` will run.
+
+## Testing
+
+The unit tests for this project are in `test_module.py`. We imported the tests from `test_module.py` to `main.py` for your convenience. The tests will run automatically whenever you hit the "run" button.
+
+## Submitting
+
+Copy your project's URL and submit it to freeCodeCamp.
+
+# --hints--
+
+It should pass all Python tests.
+
+```js
+
+```
+
+# --solutions--
+
+```py
+ # Python 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.
+```
diff --git a/curriculum/challenges/ukrainian/09-information-security/information-security-projects/sha-1-password-cracker.md b/curriculum/challenges/ukrainian/09-information-security/information-security-projects/sha-1-password-cracker.md
new file mode 100644
index 00000000000000..5d297ce139fcc9
--- /dev/null
+++ b/curriculum/challenges/ukrainian/09-information-security/information-security-projects/sha-1-password-cracker.md
@@ -0,0 +1,72 @@
+---
+id: 5e46f983ac417301a38fb933
+title: SHA-1 Password Cracker
+challengeType: 10
+forumTopicId: 462374
+helpCategory: Python
+dashedName: sha-1-password-cracker
+---
+
+# --description--
+
+You will be [working on this project with our Replit starter code](https://replit.com/github/freeCodeCamp/boilerplate-SHA-1-password-cracker).
+
+We are still developing the interactive instructional part of the Python curriculum. For now, here are some videos on the freeCodeCamp.org YouTube channel that will teach you everything you need to know to complete this project:
+
+- [Python for Everybody Video Course](https://www.freecodecamp.org/news/python-for-everybody/) (14 hours)
+
+- [Learn Python Video Course](https://www.freecodecamp.org/news/learn-python-video-course/) (10 hours)
+
+# --instructions--
+
+Passwords should never be stored in plain text. They should be stored as hashes, just in case the password list is discovered. However, not all hashes are created equal.
+
+For this project you will learn about the importance of good security by creating a password cracker to figure out passwords that were hashed using SHA-1.
+
+Create a function that takes in a SHA-1 hash of a password and returns the password if it is one of the top 10,000 passwords used. If the SHA-1 hash is NOT of a password in the database, return "PASSWORD NOT IN DATABASE".
+
+The function should hash each password from `top-10000-passwords.txt` and compare it to the hash passed into the function.
+
+The function should take an optional second argument named `use_salts`. If set to true, each salt string from the file `known-salts.txt` should be appended AND prepended to each password from `top-10000-passwords.txt` before hashing and before comparing it to the hash passed into the function.
+
+Here are some hashed passwords to test the function with:
+
+- `b305921a3723cd5d70a375cd21a61e60aabb84ec` should return "sammy123"
+- `c7ab388a5ebefbf4d550652f1eb4d833e5316e3e` should return "abacab"
+- `5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8` should return "password"
+
+Here are some hashed passwords to test the function with when `use_salts` is set to `True`:
+
+- `53d8b3dc9d39f0184144674e310185e41a87ffd5` should return "superman"
+- `da5a4e8cf89539e66097acd2f8af128acae2f8ae` should return "q1w2e3r4t5"
+- `ea3f62d498e3b98557f9f9cd0d905028b3b019e1` should return "bubbles1"
+
+The `hashlib` library has been imported for you. You should condider using it in your code. [Learn more about "hashlib" here.](https://docs.python.org/3/library/hashlib.html)
+
+## Development
+
+Write your code in `password_cracker.py`. For development, you can use `main.py` to test your code. Click the "run" button and `main.py` will run.
+
+## Testing
+
+The unit tests for this project are in `test_module.py`. We imported the tests from `test_module.py` to `main.py` for your convenience. The tests will run automatically whenever you hit the "run" button.
+
+## Submitting
+
+Copy your project's URL and submit it to freeCodeCamp.
+
+# --hints--
+
+It should pass all Python tests.
+
+```js
+
+```
+
+# --solutions--
+
+```py
+ # Python 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.
+```
diff --git a/curriculum/challenges/ukrainian/09-information-security/information-security-projects/stock-price-checker.md b/curriculum/challenges/ukrainian/09-information-security/information-security-projects/stock-price-checker.md
new file mode 100644
index 00000000000000..c982308617c72c
--- /dev/null
+++ b/curriculum/challenges/ukrainian/09-information-security/information-security-projects/stock-price-checker.md
@@ -0,0 +1,136 @@
+---
+id: 587d824a367417b2b2512c44
+title: Stock Price Checker
+challengeType: 4
+forumTopicId: 301572
+dashedName: stock-price-checker
+---
+
+# --description--
+
+Build a full stack JavaScript app that is functionally similar to this: .
+
+Since all reliable stock price APIs require an API key, we've built a workaround. Use to get up-to-date stock price information without needing to sign up for your own key.
+
+Working on this project will involve you writing your code using one of the following methods:
+
+- Clone [this GitHub repo](https://github.com/freeCodeCamp/boilerplate-project-stockchecker/) and complete your project locally.
+- Use [our Replit starter project](https://replit.com/github/freeCodeCamp/boilerplate-project-stockchecker) to complete your project.
+- Use a site builder of your choice to complete the project. Be sure to incorporate all the files from our GitHub repo.
+
+When you are done, make sure a working demo of your project is hosted somewhere public. Then submit the URL to it in the `Solution Link` field. Optionally, also submit a link to your project's source code in the `GitHub Link` field.
+
+# --instructions--
+
+1. SET `NODE_ENV` to `test` without quotes and set `DB` to your MongoDB connection string
+2. Complete the project in `routes/api.js` or by creating a handler/controller
+3. You will add any security features to `server.js`
+4. You will create all of the functional tests in `tests/2_functional-tests.js`
+
+**Note** Privacy Considerations: Due to the requirement that only 1 like per IP should be accepted, you will have to save IP addresses. It is important to remain compliant with data privacy laws such as the General Data Protection Regulation. One option is to get permission to save the user's data, but it is much simpler to anonymize it. For this challenge, remember to anonymize IP addresses before saving them to the database. If you need ideas on how to do this, you may choose to hash the data, truncate it, or set part of the IP address to 0.
+
+Write the following tests in `tests/2_functional-tests.js`:
+
+- Viewing one stock: GET request to `/api/stock-prices/`
+- Viewing one stock and liking it: GET request to `/api/stock-prices/`
+- Viewing the same stock and liking it again: GET request to `/api/stock-prices/`
+- Viewing two stocks: GET request to `/api/stock-prices/`
+- Viewing two stocks and liking them: GET request to `/api/stock-prices/`
+
+# --hints--
+
+You can provide your own project, not the example URL.
+
+```js
+(getUserInput) => {
+ assert(
+ !/.*\/stock-price-checker\.freecodecamp\.rocks/.test(getUserInput('url'))
+ );
+};
+```
+
+You should set the content security policies to only allow loading of scripts and CSS from your server.
+
+```js
+async (getUserInput) => {
+ const data = await fetch(getUserInput('url') + '/_api/app-info');
+ const parsed = await data.json();
+ assert.isTrue(
+ parsed.headers['content-security-policy'].includes("script-src 'self'")
+ );
+ assert.isTrue(
+ parsed.headers['content-security-policy'].includes("style-src 'self'")
+ );
+};
+```
+
+You can send a `GET` request to `/api/stock-prices`, passing a NASDAQ stock symbol to a `stock` query parameter. The returned object will contain a property named `stockData`.
+
+```js
+async (getUserInput) => {
+ const data = await fetch(
+ getUserInput('url') + '/api/stock-prices?stock=GOOG'
+ );
+ const parsed = await data.json();
+ assert.property(parsed, 'stockData');
+};
+```
+
+The `stockData` property includes the `stock` symbol as a string, the `price` as a number, and `likes` as a number.
+
+```js
+async (getUserInput) => {
+ const data = await fetch(
+ getUserInput('url') + '/api/stock-prices?stock=GOOG'
+ );
+ const parsed = await data.json();
+ const ticker = parsed.stockData;
+ assert.typeOf(ticker.price, 'number');
+ assert.typeOf(ticker.likes, 'number');
+ assert.typeOf(ticker.stock, 'string');
+};
+```
+
+You can also pass along a `like` field as `true` (boolean) to have your like added to the stock(s). Only 1 like per IP should be accepted.
+
+```js
+
+```
+
+If you pass along 2 stocks, the returned value will be an array with information about both stocks. Instead of `likes`, it will display `rel_likes` (the difference between the likes on both stocks) for both `stockData` objects.
+
+```js
+async (getUserInput) => {
+ const data = await fetch(
+ getUserInput('url') + '/api/stock-prices?stock=GOOG&stock=MSFT'
+ );
+ const parsed = await data.json();
+ const ticker = parsed.stockData;
+ assert.typeOf(ticker, 'array');
+ assert.property(ticker[0], 'rel_likes');
+ assert.property(ticker[1], 'rel_likes');
+};
+```
+
+All 5 functional tests are complete and passing.
+
+```js
+async (getUserInput) => {
+ const tests = await fetch(getUserInput('url') + '/_api/get-tests');
+ const parsed = await tests.json();
+ assert.isTrue(parsed.length >= 5);
+ parsed.forEach((test) => {
+ assert.equal(test.state, 'passed');
+ });
+};
+```
+
+# --solutions--
+
+```js
+/**
+ 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.
+*/
+```
diff --git a/curriculum/challenges/ukrainian/09-information-security/information-security-with-helmetjs/hash-and-compare-passwords-asynchronously.md b/curriculum/challenges/ukrainian/09-information-security/information-security-with-helmetjs/hash-and-compare-passwords-asynchronously.md
new file mode 100644
index 00000000000000..1d72070146fcd2
--- /dev/null
+++ b/curriculum/challenges/ukrainian/09-information-security/information-security-with-helmetjs/hash-and-compare-passwords-asynchronously.md
@@ -0,0 +1,81 @@
+---
+id: 58a25bcff9fc0f352b528e7d
+title: Hash and Compare Passwords Asynchronously
+challengeType: 2
+forumTopicId: 301578
+dashedName: hash-and-compare-passwords-asynchronously
+---
+
+# --description--
+
+As a reminder, this project is being built upon the following starter project on [Replit](https://replit.com/github/freeCodeCamp/boilerplate-bcrypt), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-bcrypt/).
+
+As hashing is designed to be computationally intensive, it is recommended to do so asynchronously on your server as to avoid blocking incoming connections while you hash. All you have to do to hash a password asynchronous is call
+
+```js
+bcrypt.hash(myPlaintextPassword, saltRounds, (err, hash) => {
+ /*Store hash in your db*/
+});
+```
+
+# --instructions--
+
+Add this hashing function to your server (we've already defined the variables used in the function for you to use) and log it to the console for you to see! At this point you would normally save the hash to your database.
+
+Now when you need to figure out if a new input is the same data as the hash you would just use the compare function.
+
+```js
+bcrypt.compare(myPlaintextPassword, hash, (err, res) => {
+ /*res == true or false*/
+});
+```
+
+Add this into your existing hash function (since you need to wait for the hash to complete before calling the compare function) after you log the completed hash and log 'res' to the console within the compare. You should see in the console a hash then 'true' is printed! If you change 'myPlaintextPassword' in the compare function to 'someOtherPlaintextPassword' then it should say false.
+
+```js
+bcrypt.hash('passw0rd!', 13, (err, hash) => {
+ console.log(hash);
+ //$2a$12$Y.PHPE15wR25qrrtgGkiYe2sXo98cjuMCG1YwSI5rJW1DSJp0gEYS
+ bcrypt.compare('passw0rd!', hash, (err, res) => {
+ console.log(res); //true
+ });
+});
+
+```
+
+Submit your page when you think you've got it right.
+
+# --hints--
+
+Async hash should be generated and correctly compared.
+
+```js
+(getUserInput) =>
+ $.get(getUserInput('url') + '/_api/server.js').then(
+ (data) => {
+ assert.match(
+ data,
+ /START_ASYNC[^]*bcrypt.hash.*myPlaintextPassword( |),( |)saltRounds( |),( |).*err( |),( |)hash[^]*END_ASYNC/gi,
+ 'You should call bcrypt.hash on myPlaintextPassword and saltRounds and handle err and hash as a result in the callback'
+ );
+ assert.match(
+ data,
+ /START_ASYNC[^]*bcrypt.hash[^]*bcrypt.compare.*myPlaintextPassword( |),( |)hash( |),( |).*err( |),( |)res[^]*}[^]*}[^]*END_ASYNC/gi,
+ 'Nested within the hash function should be the compare function comparing myPlaintextPassword to hash'
+ );
+ },
+ (xhr) => {
+ throw new Error(xhr.statusText);
+ }
+ );
+```
+
+# --solutions--
+
+```js
+/**
+ 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.
+*/
+```
diff --git a/curriculum/challenges/ukrainian/10-coding-interview-prep/project-euler/problem-124-ordered-radicals.md b/curriculum/challenges/ukrainian/10-coding-interview-prep/project-euler/problem-124-ordered-radicals.md
new file mode 100644
index 00000000000000..08779282a3d4fa
--- /dev/null
+++ b/curriculum/challenges/ukrainian/10-coding-interview-prep/project-euler/problem-124-ordered-radicals.md
@@ -0,0 +1,142 @@
+---
+id: 5900f3e81000cf542c50fefb
+title: 'Problem 124: Ordered radicals'
+challengeType: 5
+forumTopicId: 301751
+dashedName: problem-124-ordered-radicals
+---
+
+# --description--
+
+The radical of $n$, $rad(n)$, is the product of the distinct prime factors of $n$. For example, $504 = 2^3 × 3^2 × 7$, so $rad(504) = 2 × 3 × 7 = 42$.
+
+If we calculate $rad(n)$ for $1 ≤ n ≤ 10$, then sort them on $rad(n)$, and sorting on $n$ if the radical values are equal, we get:
+
+
+
+
+
+ $Unsorted$ |
+ |
+ $Sorted$ |
+
+
+ $n$ |
+ $rad(n)$ |
+ |
+ $n$ |
+ $rad(n)$ |
+ $k$ |
+
+
+ 1 |
+ 1 |
+ |
+ 1 |
+ 1 |
+ 1 |
+
+
+ 2 |
+ 2 |
+ |
+ 2 |
+ 2 |
+ 2 |
+
+
+ 3 |
+ 3 |
+ |
+ 4 |
+ 2 |
+ 3 |
+
+
+ 4 |
+ 2 |
+ |
+ 8 |
+ 2 |
+ 4 |
+
+
+ 5 |
+ 5 |
+ |
+ 3 |
+ 3 |
+ 5 |
+
+
+ 6 |
+ 6 |
+ |
+ 9 |
+ 3 |
+ 6 |
+
+
+ 7 |
+ 7 |
+ |
+ 5 |
+ 5 |
+ 7 |
+
+
+ 8 |
+ 2 |
+ |
+ 6 |
+ 6 |
+ 8 |
+
+
+ 9 |
+ 3 |
+ |
+ 7 |
+ 7 |
+ 9 |
+
+
+ 10 |
+ 10 |
+ |
+ 10 |
+ 10 |
+ 10 |
+
+
+
+
+
+Let $E(k)$ be the $k$th element in the sorted $n$ column; for example, $E(4) = 8$ and $E(6) = 9$. If $rad(n)$ is sorted for $1 ≤ n ≤ 100000$, find $E(10000)$.
+
+# --hints--
+
+`orderedRadicals()` should return `21417`.
+
+```js
+assert.strictEqual(orderedRadicals(), 21417);
+```
+
+# --seed--
+
+## --seed-contents--
+
+```js
+function orderedRadicals() {
+
+ return true;
+}
+
+orderedRadicals();
+```
+
+# --solutions--
+
+```js
+// solution required
+```
diff --git a/curriculum/challenges/ukrainian/10-coding-interview-prep/project-euler/problem-199-iterative-circle-packing.md b/curriculum/challenges/ukrainian/10-coding-interview-prep/project-euler/problem-199-iterative-circle-packing.md
new file mode 100644
index 00000000000000..d2fc26383fccc5
--- /dev/null
+++ b/curriculum/challenges/ukrainian/10-coding-interview-prep/project-euler/problem-199-iterative-circle-packing.md
@@ -0,0 +1,75 @@
+---
+id: 5900f4341000cf542c50ff46
+title: 'Problem 199: Iterative Circle Packing'
+challengeType: 5
+forumTopicId: 301837
+dashedName: problem-199-iterative-circle-packing
+---
+
+# --description--
+
+Three circles of equal radius are placed inside a larger circle such that each pair of circles is tangent to one another and the inner circles do not overlap. There are four uncovered "gaps" which are to be filled iteratively with more tangent circles.
+
+
+
+At each iteration, a maximally sized circle is placed in each gap, which creates more gaps for the next iteration. After 3 iterations (pictured), there are 108 gaps and the fraction of the area which is not covered by circles is 0.06790342, rounded to eight decimal places.
+
+What fraction of the area is not covered by circles after `n` iterations? Give your answer rounded to eight decimal places using the format x.xxxxxxxx .
+
+# --hints--
+
+`iterativeCirclePacking(10)` should return a number.
+
+```js
+assert(typeof iterativeCirclePacking(10) === 'number');
+```
+
+`iterativeCirclePacking(10)` should return `0.00396087`.
+
+```js
+assert.strictEqual(iterativeCirclePacking(10), 0.00396087);
+```
+
+`iterativeCirclePacking(3)` should return `0.06790342`.
+
+```js
+assert.strictEqual(iterativeCirclePacking(3), 0.06790342);
+```
+
+# --seed--
+
+## --seed-contents--
+
+```js
+function iterativeCirclePacking(n) {
+
+ return true;
+}
+
+iterativeCirclePacking(10);
+```
+
+# --solutions--
+
+```js
+function iterativeCirclePacking(n) {
+ let k1 = 1;
+ let k0 = k1 * (3 - 2 * Math.sqrt(3));
+ let a0 = 1 / (k0 * k0);
+ let a1 = 3 / (k1 * k1);
+ a1 += 3 * getArea(k0, k1, k1, n);
+ a1 += getArea(k1, k1, k1, n);
+ let final = ((a0 - a1) / a0).toFixed(8);
+
+ return parseFloat(final);
+ function getArea(k1, k2, k3, depth) {
+ if (depth == 0) return 0.0;
+ let k4 = k1 + k2 + k3 + 2 * Math.sqrt(k1 * k2 + k2 * k3 + k3 * k1);
+ let a = 1 / (k4 * k4);
+ a += getArea(k1, k2, k4, depth - 1);
+ a += getArea(k2, k3, k4, depth - 1);
+ a += getArea(k3, k1, k4, depth - 1);
+ return a;
+ }
+}
+```
diff --git a/curriculum/challenges/ukrainian/10-coding-interview-prep/project-euler/problem-283-integer-sided-triangles-for-which-the-area--perimeter-ratio-is-integral.md b/curriculum/challenges/ukrainian/10-coding-interview-prep/project-euler/problem-283-integer-sided-triangles-for-which-the-area--perimeter-ratio-is-integral.md
new file mode 100644
index 00000000000000..d88415d48196b0
--- /dev/null
+++ b/curriculum/challenges/ukrainian/10-coding-interview-prep/project-euler/problem-283-integer-sided-triangles-for-which-the-area--perimeter-ratio-is-integral.md
@@ -0,0 +1,48 @@
+---
+id: 5900f4881000cf542c50ff9a
+title: >-
+ Problem 283: Integer sided triangles for which the area / perimeter ratio is integral
+challengeType: 5
+forumTopicId: 301934
+dashedName: >-
+ problem-283-integer-sided-triangles-for-which-the-area--perimeter-ratio-is-integral
+---
+
+# --description--
+
+Consider the triangle with sides 6, 8 and 10. It can be seen that the perimeter and the area are both equal to 24.
+
+So the $\frac{\text{area}}{\text{perimeter}}$ ratio is equal to 1.
+
+Consider also the triangle with sides 13, 14 and 15. The perimeter equals 42 while the area is equal to 84.
+
+So for this triangle the $\frac{\text{area}}{\text{perimeter}}$ ratio is equal to 2.
+
+Find the sum of the perimeters of all integer sided triangles for which the area/perimeter ratios are equal to positive integers not exceeding 1000.
+
+# --hints--
+
+`integralAreaPerimeterRatio()` should return `28038042525570324`.
+
+```js
+assert.strictEqual(integralAreaPerimeterRatio(), 28038042525570324);
+```
+
+# --seed--
+
+## --seed-contents--
+
+```js
+function integralAreaPerimeterRatio() {
+
+ return true;
+}
+
+integralAreaPerimeterRatio();
+```
+
+# --solutions--
+
+```js
+// solution required
+```
diff --git a/curriculum/challenges/ukrainian/10-coding-interview-prep/project-euler/problem-29-distinct-powers.md b/curriculum/challenges/ukrainian/10-coding-interview-prep/project-euler/problem-29-distinct-powers.md
new file mode 100644
index 00000000000000..0fc363ab988df2
--- /dev/null
+++ b/curriculum/challenges/ukrainian/10-coding-interview-prep/project-euler/problem-29-distinct-powers.md
@@ -0,0 +1,86 @@
+---
+id: 5900f3891000cf542c50fe9c
+title: 'Problem 29: Distinct powers'
+challengeType: 5
+forumTopicId: 301941
+dashedName: problem-29-distinct-powers
+---
+
+# --description--
+
+Consider all integer combinations of $a^b$ for 2 ≤ a ≤ 5 and 2 ≤ b ≤ 5:
+
+
+ 22=4, 23=8, 24=16, 25=32
+ 32=9, 33=27, 34=81, 35=243
+ 42=16, 43=64, 44=256, 45=1024
+ 52=25, 53=125, 54=625, 55=3125
+
+
+If they are then placed in numerical order, with any repeats removed, we get the following sequence of 15 distinct terms:
+
+
+ 4, 8, 9, 16, 25, 27, 32, 64, 81, 125, 243, 256, 625, 1024, 3125
+
+
+How many distinct terms are in the sequence generated by $a^b$ for 2 ≤ `a` ≤ `n` and 2 ≤ `b` ≤ `n`?
+
+# --hints--
+
+`distinctPowers(15)` should return a number.
+
+```js
+assert(typeof distinctPowers(15) === 'number');
+```
+
+`distinctPowers(15)` should return 177.
+
+```js
+assert.strictEqual(distinctPowers(15), 177);
+```
+
+`distinctPowers(20)` should return 324.
+
+```js
+assert.strictEqual(distinctPowers(20), 324);
+```
+
+`distinctPowers(25)` should return 519.
+
+```js
+assert.strictEqual(distinctPowers(25), 519);
+```
+
+`distinctPowers(30)` should return 755.
+
+```js
+assert.strictEqual(distinctPowers(30), 755);
+```
+
+# --seed--
+
+## --seed-contents--
+
+```js
+function distinctPowers(n) {
+
+ return n;
+}
+
+distinctPowers(30);
+```
+
+# --solutions--
+
+```js
+const distinctPowers = (n) => {
+ let list = [];
+ for (let a=2; a<=n; a++) {
+ for (let b=2; b<=n; b++) {
+ let term = Math.pow(a, b);
+ if (list.indexOf(term)===-1) list.push(term);
+ }
+ }
+ return list.length;
+};
+```
diff --git a/curriculum/challenges/ukrainian/10-coding-interview-prep/project-euler/problem-331-cross-flips.md b/curriculum/challenges/ukrainian/10-coding-interview-prep/project-euler/problem-331-cross-flips.md
new file mode 100644
index 00000000000000..024faedcfd7300
--- /dev/null
+++ b/curriculum/challenges/ukrainian/10-coding-interview-prep/project-euler/problem-331-cross-flips.md
@@ -0,0 +1,52 @@
+---
+id: 5900f4b71000cf542c50ffca
+title: 'Problem 331: Cross flips'
+challengeType: 5
+forumTopicId: 301989
+dashedName: problem-331-cross-flips
+---
+
+# --description--
+
+N×N disks are placed on a square game board. Each disk has a black side and white side.
+
+At each turn, you may choose a disk and flip all the disks in the same row and the same column as this disk: thus $2 × N - 1$ disks are flipped. The game ends when all disks show their white side. The following example shows a game on a 5×5 board.
+
+
+
+It can be proven that 3 is the minimal number of turns to finish this game.
+
+The bottom left disk on the $N×N$ board has coordinates (0, 0); the bottom right disk has coordinates ($N - 1$,$0$) and the top left disk has coordinates ($0$,$N - 1$).
+
+Let $C_N$ be the following configuration of a board with $N × N$ disks: A disk at ($x$, $y$) satisfying $N - 1 \le \sqrt{x^2 + y^2} \lt N$, shows its black side; otherwise, it shows its white side. $C_5$ is shown above.
+
+Let $T(N)$ be the minimal number of turns to finish a game starting from configuration $C_N$ or 0 if configuration $C_N$ is unsolvable. We have shown that $T(5) = 3$. You are also given that $T(10) = 29$ and $T(1\\,000) = 395\\,253$.
+
+Find $\displaystyle \sum_{i = 3}^{31} T(2^i - i)$.
+
+# --hints--
+
+`crossFlips()` should return `467178235146843500`.
+
+```js
+assert.strictEqual(crossFlips(), 467178235146843500);
+```
+
+# --seed--
+
+## --seed-contents--
+
+```js
+function crossFlips() {
+
+ return true;
+}
+
+crossFlips();
+```
+
+# --solutions--
+
+```js
+// solution required
+```