Implement application for read large set of integers between -100000
and 100000
, separated by newlines, from Stdin.
After that count four major statistical metrics and print all of them as a result.
Additionally, handle flags to display specials of the statistical metrics.
$ make build
$ ./main
Mean: 8.2
Median: 9.0
Mode: 3
SD: 4.35
$ make build
$ ./main -median -mean
Mean: 8.2
Median: 9.0
- Implement interface
DBReader
for encoding recipes of cakes from JSON or XML. - Compare original and stolen databases (should work and both formats JSON/XML).
- Compare server filesystem backups between original and stolen databases.
$ ./readDB -f original_database.xml
$ ./readDB -f stolen_database.json
.
.
.
$ ./compareDB --old original_database.xml --new stolen_database.json
ADDED cake "Moonshine Muffin"
REMOVED cake "Blueberry Muffin Cake"
CHANGED cooking time for cake "Red Velvet Strawberry Cake" - "45 min" instead of "40 min"
ADDED ingredient "Coffee beans" for cake "Red Velvet Strawberry Cake"
REMOVED ingredient "Vanilla extract" for cake "Red Velvet Strawberry Cake"
CHANGED unit for ingredient "Flour" for cake "Red Velvet Strawberry Cake" - "mugs" instead of "cups"
CHANGED unit count for ingredient "Strawberries" for cake "Red Velvet Strawberry Cake" - "8" instead of "7"
REMOVED unit "pieces" for ingredient "Cinnamon" for cake "Red Velvet Strawberry Cake
.
.
.
$ ./compareFS --old snapshot1.txt --new snapshot2.txt
ADDED /etc/systemd/system/very_important/stash_location.jpg
REMOVED /var/log/browser_history.txt
- Worked with encoding JSON/XML.
- Improved understanding of interfaces
- Implement utility
find
with set of command-line options to be able to locate different types of entries (directories as-d
, regular files as-f
and symbolic links as-sl
). - Implement option
-ext
(works only when -f is specified) for user to be able to print only files with a certain extension. - Implement utility
wc
to gather basic statistics about our files with flags:-l
for counting lines,-m
for counting characters and-w
for counting words. For some files need utilize goroutines to process them concurrently. - Implement utility
xargs
. - Implement log rotation tool
myRotate
. "Log rotation" is a process when the old log file is archived and put away for storage so logs wouldn't pile up in a single file indefinitely.
# Finding all files/directories/symlinks recursively in directory /foo
$ ./myFind /foo
/foo/bar
/foo/bar/baz
/foo/bar/baz/deep/directory
/foo/bar/test.txt
/foo/bar/buzz -> /foo/bar/baz
/foo/bar/broken_sl -> [broken]
$ ./myFind -f -ext 'go' /go
/go/src/github.com/mycoolproject/main.go
/go/src/github.com/mycoolproject/magic.go
# Counting words in file input.txt
$ ./myWc -w input.txt
777 input.txt
# Counting lines in files input2.txt and input3.txt
$ ./myWc -l input2.txt input3.txt
42 input2.txt
53 input3.txt
# Counting characters in files input4.txt, input5.txt and input6.txt
$ ./myWc -m input4.txt input5.txt input6.txt
1337 input4.txt
2664 input5.txt
3991 input6.txt
$ ./myFind -f -ext 'log' /path/to/some/logs | ./myXargs ./myWc -l
$ ./myRotate /path/to/logs/some_application.log
- Worked with operation system with packages: "os", "path/filepath".
- Worked with goroutines and package "sync".
- Use Elasticsearch as database to provide the ability to search for things on version 7.9.2. Dataset of restaurants (taken from an Open Data portal) consists of more than 13 thousands of restaurants in the area of Moscow, Russia. Every entry has:
- ID
- Name
- Address
- Phone
- Longitude
- Latitude
- Create an index and a mapping (use "places" as a name for an index and "place" as a name for an entry). You can create an index using cURL like this:
~$ curl -XPUT "http://localhost:9200/places"
but in this task you should use Go Elasticsearch bindings to do the same thing. Next thing you have to do is to provide type mappings for our data. With cURL it will look like this:
~$ curl -XPUT http://localhost:9200/places/place/_mapping?include_type_name=true -H "Content-Type: application/json" -d @"schema.json"
where schema.json
looks like this:
{
"properties": {
"name": {
"type": "text"
},
"address": {
"type": "text"
},
"phone": {
"type": "text"
},
"location": {
"type": "geo_point"
}
}
}
- Create an HTML UI for our database. Abstract your database behind an interface. To just return the list of entries and be able to paginate through them, this interface is enough:
type Store interface {
// returns a list of items, a total number of hits and (or) an error in case of one
GetPlaces(limit int, offset int) ([]types.Place, int, error)
}
HTTP application should run on port 8888, responding with a list of restaurants and providing a simple pagination over it. So. when querying "http://127.0.0.1:8888/?page=2" (mind the 'page' GET param) you should be getting a page like this:
$ curl -s -XGET "http://127.0.0.1:8888/?page=2"
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Places</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h5>Total: 13649</h5>
<ul>
<li>
<div>Sushi Wok</div>
<div>gorod Moskva, prospekt Andropova, dom 30</div>
<div>(499) 754-44-44</div>
</li>
<li>
<div>Ryba i mjaso na ugljah</div>
<div>gorod Moskva, prospekt Andropova, dom 35A</div>
<div>(499) 612-82-69</div>
</li>
<li>
<div>Hleb nasuschnyj</div>
<div>gorod Moskva, ulitsa Arbat, dom 6/2</div>
<div>(495) 984-91-82</div>
</li>
</ul>
<a href="/?page=1">Previous</a>
<a href="/?page=3">Next</a>
<a href="/?page=1364">Last</a>
</body>
</html>
A "Previous" link should disappear on page 1 and "Next" link should disappear on last page. Also, in case 'page' param is specified with a wrong value (outside [0..last_page] or not numeric) your page should return HTTP 400 error and plain text with an error description:
Invalid 'page' value: 'foo'
- Implement handler which responds with
Content-Type: application/json
and JSON version of previous task (example forhttp://127.0.0.1:8888/api/places?page=3
):
$ curl -s -XGET "http://127.0.0.1:8888/api/places?page=3"
{
"name": "Places",
"total": 13649,
"places": [
{
"id": 65,
"name": "AZERBAJDZhAN",
"address": "gorod Moskva, ulitsa Dem'jana Bednogo, dom 4",
"phone": "(495) 946-34-30",
"location": {
"lat": 55.769830485601204,
"lon": 37.486914061171504
}
},
{
"id": 69,
"name": "Vojazh",
"address": "gorod Moskva, Beskudnikovskij bul'var, dom 57, korpus 1",
"phone": "(499) 485-20-00",
"location": {
"lat": 55.872553383512496,
"lon": 37.538326789741
}
},
],
"prev_page": 2,
"next_page": 4,
"last_page": 1364
}
Also, in case 'page' param is specified with a wrong value (outside [0..last_page] or not numeric) your API should respond with a corresponding HTTP 400 error and similar JSON:
{
"error": "Invalid 'page' value: 'foo'"
}
- Implement searching for three closest restaurants, configure sorting for your query:
"sort": [
{
"_geo_distance": {
"location": {
"lat": 55.674,
"lon": 37.666
},
"order": "asc",
"unit": "km",
"mode": "min",
"distance_type": "arc",
"ignore_unmapped": true
}
}
]
where "lat" and "lon" are your current coordinates. So, for an URL http://127.0.0.1:8888/api/recommend?lat=55.674&lon=37.666 your application should return JSON like this:
$ curl -s -XGET "http://127.0.0.1:8888/api/recommend?lat=55.674&lon=37.666"
{
"name": "Recommendation",
"places": [
{
"id": 30,
"name": "Ryba i mjaso na ugljah",
"address": "gorod Moskva, prospekt Andropova, dom 35A",
"phone": "(499) 612-82-69",
"location": {
"lat": 55.67396575768212,
"lon": 37.66626689310591
}
},
{
"id": 3348,
"name": "Pizzamento",
"address": "gorod Moskva, prospekt Andropova, dom 37",
"phone": "(499) 612-33-88",
"location": {
"lat": 55.673075576456,
"lon": 37.664533747576
}
},
{
"id": 3347,
"name": "KOFEJNJa «KAPUChINOFF»",
"address": "gorod Moskva, prospekt Andropova, dom 37",
"phone": "(499) 612-33-88",
"location": {
"lat": 55.672865251005106,
"lon": 37.6645689561318
}
}
]
}
- Provide some simple form of authentication with protecting
/api/recommend
endpoint with a JWT middleware, that will check the validity of this token.
Implement an API endpoint http://127.0.0.1:8888/api/get_token
which sole purpose will be to generate a token and return it, like this (this is an example, your token will likely be different):
$ curl -s -XGET "http://127.0.0.1:8888/api/get_token"
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6dHJ1ZSwiZXhwIjoxNjAxOTc1ODI5LCJuYW1lIjoiTmlrb2xheSJ9.FqsRe0t9YhvEC3hK1pCWumGvrJgz9k9WvhJgO8HsIa8"
}
So by default when querying this API from the browser it should now fail with an HTTP 401 error, but work when Authorization: Bearer <token>
header is specified by the client.
- Worked with ElasticSearh, JWT.
- Implemented simple API with AUTH.
- Recreate the server:
---
swagger: '2.0'
info:
version: 1.0.0
title: Candy Server
paths:
/buy_candy:
post:
consumes:
- application/json
produces:
- application/json
parameters:
- in: body
name: order
description: summary of the candy order
schema:
type: object
required:
- money
- candyType
- candyCount
properties:
money:
description: amount of money put into vending machine
type: integer
candyType:
description: kind of candy
type: string
candyCount:
description: number of candy
type: integer
operationId: buyCandy
responses:
201:
description: purchase succesful
schema:
type: object
properties:
thanks:
type: string
change:
type: integer
400:
description: some error in input data
schema:
type: object
properties:
error:
type: string
402:
description: not enough money
schema:
type: object
properties:
error:
type: string
Every candy buyer puts in money, chooses which kind of candy to purchase and how many. This data is being sent over to the server via HTTP and JSON and then:
- If the sum of candy prices (see Chapter 1) is smaller or equal to the amount of money the buyer gave to a machine, the server responds with HTTP 201 and returns a JSON with two fields -
"thanks"** saying "Thank you!" and "change"
being the amount of change the machine has to give back the customer. - If the sum is larger that the amount of money provided, the server responds with HTTP 402 and an error message in JSON saying:
"You need {amount} more money!"
, where{amount}
is the difference between the provided and expected. - If the client provided a negative candyCount or wrong candyType (all five candy types are encoded by two letters, so it's one of "CE", "AA", "NT", "DE" or "YR", all other cases are considered non-valid) then the server respond with HTTP 400 and an error inside JSON describing what had gone wrong.
Hint: all data from both client and server should be in JSON, so you can test like this, for example:
$ curl -XPOST -H "Content-Type: application/json" -d '{"money": 20, "candyType": "AA", "candyCount": 1}' http://127.0.0.1:3333/buy_candy
{"change":5,"thanks":"Thank you!"}
$ curl -XPOST -H "Content-Type: application/json" -d '{"money": 46, "candyType": "YR", "candyCount": 2}' http://127.0.0.1:3333/buy_candy
{"change":0,"thanks":"Thank you!"}
- Implement a certificate authentication for the server as well as a test client which will be able to query your API using a self-signed certificate and a local security authority to "verify" it on both sides.
Need a local "certificate authority" to manage certificates e.g.: minica.
So, because we're talking a full-blown mutual TLS authentication, you'll have to generate two cert/key pairs - one for the server and one for the client. Minica will also generate a CA file called minica.pem
for you which you'll need to plug into your client somehow (your auto-generated server should already support specifying CA file as well as key.pem
and cert.pem
through command line parameters).
Also, generating certificate may require you to use a domain instead of an IP address, so in examples below we will use "candy.tld". For it to work on a local machine you can put it into '/etc/hosts' file.
Your test client should support flags '-k' (accepts two-letter abbreviation for the candy type), '-c' (count of candy to buy) and '-m' (amount of money you "gave to machine"). So, the "buying request" should look like this:
~$ ./candy-client -k AA -c 2 -m 50
Thank you! Your change is 20
- Import C to Go with for Cow say
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
unsigned int i;
unsigned int argscharcount = 0;
char *ask_cow(char phrase[]) {
int phrase_len = strlen(phrase);
char *buf = (char *)malloc(sizeof(char) * (160 + (phrase_len + 2) * 3));
strcpy(buf, " ");
for (i = 0; i < phrase_len + 2; ++i) {
strcat(buf, "_");
}
strcat(buf, "\n< ");
strcat(buf, phrase);
strcat(buf, " ");
strcat(buf, ">\n ");
for (i = 0; i < phrase_len + 2; ++i) {
strcat(buf, "-");
}
strcat(buf, "\n");
strcat(buf, " \\ ^__^\n");
strcat(buf, " \\ (oo)\\_______\n");
strcat(buf, " (__)\\ )\\/\\\n");
strcat(buf, " ||----w |\n");
strcat(buf, " || ||\n");
return buf;
}
int main(int argc, char *argv[]) {
for (i = 1; i < argc; ++i) {
argscharcount += (strlen(argv[i]) + 1);
}
argscharcount = argscharcount + 1;
char *phrase = (char *)malloc(sizeof(char) * argscharcount);
strcpy(phrase, argv[1]);
for (i = 2; i < argc; ++i) {
strcat(phrase, " ");
strcat(phrase, argv[i]);
}
char *cow = ask_cow(phrase);
printf("%s", cow);
free(phrase);
free(cow);
return 0;
}
$ curl -s --key cert/client/key.pem --cert cert/client/cert.pem --cacert cert/minica.pem -XPOST -H "Content-Type: application/json" -d '{"candyType": "NT", "candyCount": 2, "money": 34}' "https://candy.tld:3333/buy_candy"
{"change":0,"thanks":" ____________\n< Thank you! >\n ------------\n \\ ^__^\n \\ (oo)\\_______\n (__)\\ )\\/\\\n ||----w |\n || ||\n"}
Hint: > For creating
candy.tld:3333
instead of127.0.0.1:3333
need to take following steps:
- sudo nano /etc/hosts
- add "127.0.0.1 candy.tld"
- Worked with TLS server/client.
- Worked with C from Go.
- Write a function
areToysBalanced
which will receive a pointer to a tree root as an argument. The point is to spit out a true/false boolean value depending on if left subtree has the same amount of toys as the right one. The value on the root itself can be ignored. Function should returntrue
for such trees (0/1 represent false/true, equal amount of 1's on both subtrees):
Binary tree node:
type TreeNode struct {
HasToy bool
Left *TreeNode
Right *TreeNode
}
0
/ \
0 1
/ \
0 1
and false
for such trees (non-equal amount of 1's on both subtrees):
1
/ \
1 0
- Write function called
unrollGarland()
, which also receives a pointer to a root node. The idea is to go top down, layer by layer, going right on even horisontal layers and going left on every odd. The returned value of this function should be a slice of bools. So, for this tree:
1
/ \
1 0
/ \ / \
1 0 1 1
The answer will be [true, true, false, true, true, false, true] (root is true, then on second level we go from left to right, and then on third from right to left, like a zig-zag).
- Implement a function
getNCoolestPresents()
, that, given an unsorted slice of Presents and an integern
, will return a sorted slice (desc) of the "coolest" ones from the list. It should use the PresentHeap data structure inside and return an error ifn
is larger than the size of the slice or is negative.
type Present struct {
Value int
Size int
}
So, if we represent each Present by a tuple of two numbers (Value, Size), then for this input:
(5, 1)
(4, 5)
(3, 1)
(5, 2)
the two "coolest" Presents would be [(5, 1), (5, 2)], because the first one has the smaller size of those two with Value = 5.
- Implement a classic dynamic programming algorithm, also known as "Knapsack Problem". Input is almost the same, as in the previous task - you have a slice of Presents, each with Value and Size, but this time you also have a hard drive with a limited capacity. So, you have to pick only those presents, that fit into that capacity and maximize the resulting value.
Write a function
grabPresents()
, that receives a slice of Present instances and a capacity of your hard drive. As an output, this function should give out another slice of Presents, which should have a maximum cumulative Value that you can get with such capacity.
Run tests
make test
- Wordked with data structure (Binary tree, Heap).
- Worked with DFS, BFS, Knapstack problem.
- Generate 300x300px PNG file with name 'amazing_logo.png'. Image should appear in the same directory as the launched binary executable after compiling.
- Create a website (blog where everybody will be able to read ideas on the world improvement). Here is a list of features it should have:
- Database: PostgreSQL;
- Admin panel: (on '/admin' endpoint) where only you can login with just a form for posting new articles;
- Basic markdown support (so it can at least show "###" headers and links in generated HTML);
- Pagination (show no more than 3 thoughts on one page for people to not get too much of your awesomeness);
- Application UI should use port 8888.
- Admin credentials for posting access (login and password) and database credentials (database name and user) should be submitted separately as well in a file called admin_credentials.txt.
- When clicking a link to article, user should get to a page with a rendered markdown text and a single "Back" link which brings him/her back to main page.
- Protect from
- Implement rate limiting, so if ther are more than a hundred clients per second trying to access it, they should get a 429 Too Many Requests response.
Run app
make run-srv
- Implement
mincoins
algorithm. - Test it with
_test.go
.
- Working with
reflect
- Working with channels.
Fan-in
&&Fan-out
patterns.