Skip to content

Instantly share code, notes, and snippets.

@effrenus
Last active October 16, 2018 21:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save effrenus/b02f873e3e1c5159262494e0702346a9 to your computer and use it in GitHub Desktop.
Save effrenus/b02f873e3e1c5159262494e0702346a9 to your computer and use it in GitHub Desktop.
// https://pikabu.ru/page/interview/frontend/
const check = (taskNum, fn, cmp = (a,b) => a === b) =>
(expected, ...vals) =>
console.assert(
cmp(fn(...vals), expected),
`\n[Task #${taskNum}] Test failed: \n\t\texpected [${expected}] \n\t\treturns [${fn(...vals)}] \n\t\tFunction args: (${vals.map(v => typeof v == 'string' ? `'${v}'` : v).join(', ')})`
)
// Task 14.
/**
* Format hash tag.
* @function
* @param {string} text
* @param {number} [maxLen=100]
* @returns {(string|false)}
*/
const getHashTag = (text, maxLen = 100) => {
if (!text) return false;
const words = String(text).split(' ').map(w => w.trim()).filter(Boolean);
const hashText = words
.map(word => {
return word.split('')
.reduce((acc,ch) =>
/\p{L}|\d/ui.test(ch)
? acc + (!acc.length ? ch.toUpperCase() : ch.toLowerCase())
: acc, '');
})
.join('');
return hashText && hashText.length <= maxLen ? '#' + hashText : false;
}
(() => {
const test = check(14, getHashTag);
test(false, '');
test(false, null);
test('#123', 123);
test('#123', '123');
test(false, '#');
test('#Hello', '#hello');
test(false, '# ');
test('#完璧', '完璧');
test('#D', ' d ');
test(false, ' ');
test(false, '#_');
test('#ПримерНовогоХэштега', 'Пример НОВОГО "хэштега"');
test('#Sdfds423Sadsa121Выфвфы', '#sdfds 423 _sadsa ^: 121 выфвфы *');
/* > 100 */test(false, '#dasdas *** 343241dsfddsfsdfdsf *) dsfasdsadasdsf312312312sdfds %%% dfsdfdsfdsfdsfdsfdsfdsfdsfdsdsfsdfsdfdsfdsfdsfds');
/* = 100 */test('#Dasdas33241dsfddsfsdfdsfDsfasdsadasdsf312312312sdfdsDfsdfdsfdsfdsfdsfdsfdsfdsfdsdsfsdfsdfdsfdsfdsfds', '#dasdas *** 33241dsfddsfsdfdsf *) dsfasdsadasdsf312312312sdfds %%% dfsdfdsfdsfdsfdsfdsfdsfdsfdsdsfsdfsdfdsfdsfdsfds');
})();
// Task 15.
/**
* Proper pikabu domain validation.
* @function
* @param {string} url
* @returns {boolean}
*/
const isValidUrl = (url) => /^https?:\/\/(?:[0-9a-z\-]+\.)*pikabu\.ru($|\/)/i.test(url);
(() => {
const test = check(15, isValidUrl);
test(true, 'http://pikabu.ru');
test(false, '://pikabu.ru');
test(false, 'pikabu.ru');
test(true, 'http://PIKABU.ru');
test(true, 'https://pikabu.ru');
test(true, 'https://pikabu.ru');
test(true, 'https://pikabu.ru/adsa');
test(false, 'https://pikabu.ruq');
test(true, 'https://www.pikabu.ru');
test(true, 'https://t1.p-2.pikabu.ru');
test(true, 'https://t1.p-2.--.pikabu.ru');
test(false, 'httpq://t1.p-2.--.pikabu.ru');
test(false, 'http://.pikabu.ru');
test(false, 'http://..pikabu.ru');
test(false, 'http://3..pikabu.ru');
})();
// Task 16.
/**
* Product version sort by specificity of changes.
* @function
* @param {number[][]} [arr=[]]
* @returns {number[][]}
*/
const sortProductVer = (arr = []) => arr.slice().map(arr => arr.slice()).sort((a, b) => {
// Skip product id.
for (let i = 1; i < a.length; i++) if (a[i] - b[i] !== 0) return b[i] - a[i];
return 0;
});
(() => {
const test = check(16, sortProductVer, (a, b) => {
return a.every((_, i) =>
a[i].every((_, j) => a[i][j] === b[i][j]))
});
test(
[[9, 1, 0, 1], [8, 1, 0, 0], [3, 0, 1, 1], [11, 0, 1, 0], [15, 0, 0, 1]],
[[11, 0, 1, 0], [8, 1, 0, 0], [9, 1, 0, 1], [3, 0, 1, 1], [15, 0, 0, 1]]
);
test(
[[12, 3, 1, 8], [12, 2, 1, 0], [12, 1, 4, 1], [12, 1, 0, 0], [12, 0, 1, 1]],
[[12, 2, 1, 0], [12, 1, 0, 0], [12, 1, 4, 1], [12, 3, 1, 8], [12, 0, 1, 1]]
);
})();
// Task 17.
/**
* Encode word using caesar cipher. Support latin letters only.
* @function
* @param {number} shift - For 256 char alphabet.
* @returns {function(string): string}
*/
const Caesar = (shift) => (word) =>
(typeof shift !== 'number' || shift < 0) || !word
? ''
: String(word)
.split('')
.reduce((acc, ch) =>
acc + (!/\w/.test(ch) ? ch : String.fromCharCode((ch.charCodeAt(0)+(shift%256)))), '');
(() => {
check(17, Caesar(10))('}m|sz~', 'script');
check(17, Caesar(266))('}m|sz~,', 'script,');
check(17, Caesar(3))('DEF', 'ABC');
check(17, Caesar())('', 'ABC');
check(17, Caesar('sds'))('', 'ABC');
})();
// Task 18.
class Base {}
Object.defineProperty(Base, 'x', { get() { return 3/2; } });
Object.assign(Base.prototype, {x: Base.x*2});
(() => {
check(18, () => Base.x + Base.x === 3 && (new Base().x) === Base.x + Base.x)(true);
})();
// Task 19.
/**
* Remove all child nodes with `data-role="user"`.
* @param {string} [selector=#container]
*/
function clearContainer(selector = '#container') {
const parent = document.querySelector(selector);
parent && Array.from(parent.childNodes)
.filter(elm => elm.nodeType === Element.ELEMENT_NODE && elm.dataset.role === 'user')
.forEach(elm => elm.remove());
}
// Task 20.
/*
<meta http-equiv="content-language"/> считается устаревшим, рекоменуется http заголовок или указание в корневом элементе`<html lang="ru">`.
Проблемы с разметкой и именованием классов:
* не используется ни одно из распространенных соглашений по именованию классов.
* элементы не соответствуют своей семантике (`<nav>`, `<section>`, `<article>`).
* использовние атрибутов (obsolete) для стилизации элементов.
* для кастомных атрибутов рекомендуют указывать перфик `data-` (`data-type`, `data-aid`), меньше вероятность конфликтов в будущем.
* deprecated элементы (`<font>`).
* javascript в атрибутах.
* сам обработчик ненадежен: что если появится какой-то другой элемент перед ним.
* указание стилей в конце документа: чем раньше стили загрузятся (парсинг документа с параллельной загрузкой), тем быстрее страница отобразится.
*/
// Task 21.
// https://codepen.io/anon/pen/NOvPJP?editors=1100
/*
form>div:not(.line)>input+div>span:nth-of-type(3n+1) {
border: 2px solid green;
}
*/
// Task 22.
// https://codepen.io/anon/pen/NOaqRP?editors=1010
/**
* Make markup to display text like wave.
* @function
* @param {string} txt
* @param {number} [startSize=10]
* @param {number} [step=5]
* @param {function} fmt - Format function (str: string, size: number) => string
* @returns {string}
*/
const makeWaveString = (txt, startSize = 10, step = 5, fmt = (str, size) => { return `<span style="font-size:${size}px">${str}</span>`; }) => {
if (!txt) return '';
let size = startSize;
let left = '', right = '';
for (let i = 0, j = txt.length - 1; i <= j;) {
while (i <= j && /\s/.test(txt[i])) left += txt[i++];
while (j > i && /\s/.test(txt[j])) right += txt[j--];
if (i > j) break;
right = (i < j ? fmt(txt[j--], size) : '') + right;
left += fmt(txt[i++], size);
size += step;
}
return left + right;
}
(() => {
const test = check(22, makeWaveString);
const params = [10, 5, (str, size) => `${str}{${size}}`]
test(' ', ' ');
test('', '');
test('', null);
test('o{10}o{10}', 'oo', ...params);
test('o{10}', 'o', ...params);
test(' o{10} y{10} ', ' o y ', ...params);
test(' o{10} ', ' o ', ...params);
test(' o{10}', ' o', ...params);
test(' o{10}l{10}', ' ol', ...params);
test('o{10}l{15}o{10}', 'olo', ...params);
test('h{10}e{15}l{20}l{25}o{30}_{35}o{30}l{25}l{20}e{15}h{10}', 'hello_olleh', ...params);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment