Alex
Підписатись

Alex

Приєднався: 4 роки тому | 9 Читає   16 Читачів | 2.1K

Адмін сайту

  1. В perl6 це можна зробити ось так

    perl6 -e 'print(%*ENV<SHELL>,"\n")'
    

  2. Виконайте наступне:

    grep -rnw '/path/to/somewhere/' -e 'pattern'
    
    • -r або -R - рекурсивний пошук,
    • -n - вивести номер рядка
    • -w пошук цілого слова.
    • -l (нижній регістр L) можна додати, щоб просто вказати ім'я відповідного файлу.

    Також можна використовувати, --exclude, --include, --exclude-dir. Ці прапори можуть бути використані для ефективного пошуку:

    Ця команда буде здійснювати пошук лише у тих файлах з розширенням .c або .h:

    grep --include=\*.{c,h} -rnw '/path/to/somewhere/' -e "pattern"
    

    Ця команда виконає пошук у всіх файлах, за виключенням тих що закінчуються розширенням .o:

    grep --exclude=\*.o -rnw '/path/to/somewhere/' -e "pattern"
    

    Для каталогів можна виключити один або кілька каталогів за допомогою параметра --exclude-dir. Наприклад, ця команда виключить директорії dir1/, dir2/ а також ті що відповідають *.dst/:

    grep --exclude-dir={dir1,dir2,*.dst} -rnw '/path/to/somewhere/' -e "pattern"
    

    Для отримання додаткових опцій перевірте man grep.


  3. Поки що так. Відвідувачів на сайті ще не дуже багато, треба з чогось починати :)


  4. Якщо проблема програмна, то варто перевірити /var/log/syslog та journalctl, там має бути видно що останнє запускалося.

    Якщо проблема апаратна, то ядро може падати в Kernel panic, для перевірки необхідно підключити монітор і можливо буде зрозуміла причина.


  5. Знайдіть індекс елемента масиву, який потрібно видалити, за допомогою indexOf, а потім видаліть цей індекс за допомогою splice.

    const array = [2, 5, 9];
    
    console.log(array);
    
    const index = array.indexOf(5);
    if (index > -1) { // only splice array when item is found
      array.splice(index, 1); // 2nd parameter means remove one item only
    }
    
    // array = [2, 9]
    console.log(array); 
    

    Другим параметром splice є кількість елементів, які потрібно видалити. Зауважте, що splice модифікує масив на місці та повертає новий масив, що містить елементи, які було видалено.


  6. Обмеження при створенні статті наступні:

    • Максимальна довжина заголовка: 191 символ
    • Мінімальна довжина тексту: 100 слів
    • Максимальна кількість тегів: 7
    • В тегах забороняється використовувати спецсимволи ([]{}#%^&()=\|/"~) та emoji.

  7. Я б рекомендував вибирати серед найпопулярніших дистрибутивів: Ubuntu, Mint, Fedora, Manjaro. Вибирайте яка графічна оболонка вам більше подобається (KDE, Gnome, Mate, Cinnamon, Unity, Pantheon, Xfce) і далі вибирайте з топових дистрибутивів які йдуть з цією оболонкою


  8. Виправити помилку можна наступним чином

    1. Необхідно встановити пакет guzzlehttp/psr7
    composer require guzzlehttp/psr7
    
    1. Далі в composer.json міняємо версію з "guzzlehttp/psr7": "^2.0", на "guzzlehttp/psr7": "^1.5"
    2. Оновлюємо пакети командою
    composer update
    
    1. Після чого зможемо успішно встановити пакет paquettg/php-html-parser командою
    composer require paquettg/php-html-parser
    

  9. Це можна зробити так:

    list_3 = [ f'{i}-{j}' for i, j in zip(list_1, list_2) ]
    

    або так

    list_3 = [*map(lambda x: f'{x[0]}-{x[1]}', zip(list_1, list_2))]
    

    або так

    list_3 = [*map(lambda x: '-'.join(x), zip(list_1, list_2))]
    

    або так

    list_3 = [*map(lambda x, y: f'{x}-{y}', list_1, list_2)]
    

    або так

    list_3 = [*map('{}-{}'.format, list_1, list_2)]
    

    або так (поки що найкоротший запис)

    list_3 = [*map('-'.join, zip(list_1, list_2))]
    

  10. Основна ідея - поліпшення переносимості. Не гарантується, що на різних системах виконуваний файл буде лежати по шляху, який вказаний в shebang.

    Використання env дозволяє знизити цей ризик за рахунок запуску команди на основі даних зі змінної середовища PATH

    Більш того, якщо з яких-небудь причин замість стандартного файлу користувач хоче використовувати свій, то йому достатньо додати шлях до цього файлу в PATH без необхідності виправлення скриптів:

    ~ $ cp /bin/bash /home/soon/python                                         
    ~ $ export PATH=/home/soon:$PATH                                                 
    ~ $ env python                                                                   
    [soon@archlinux ~]$ exit
    

    В наведеному вище прикладі я скопіював bash до себе в домашню директорію (перейменувавши при цьому файл в python), додав шлях в PATH і запустив python за допомогою env, яка запустила bash, тому що знайшла його раніше.

    Ще одним прикладом є використання віртуальних оточень при розробці на Python (virtualenv). Оскільки вони також перебивають PATH, env дозволяє використовувати потрібну версію виконуваного файлу:

    ~ $ workon black-box-challenge-2016-py2     
    ~ (venv:black-box-challenge-2016-py2) $ env python
    
    Python 2.7.11 (default, Mar 31 2016, 06:18:34) 
    [GCC 5.3.0] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import sys
    >>> print sys.executable
    /home/soon/.virtualenvs/black-box-challenge-2016-py2/bin/python
    >>> 
    

  11. Різниця між PUT і POST - це питання семантики. Оскільки для операцій використовуються різні дієслова, то і сенс у них повинен бути різним.

    Уявіть, що ваш сервіс оперує поняттями блокнот (notebook) і запис (post). Один блокнот може містити безліч записів.

    Для додавання нового запису в блокнот c ідентифікатором id ви будете використовувати метод POST з URL mydomain/notebooks/id/. Ваш сервіс, орієнтуючись на метод POST, сам присвоїть потрібний ідентифікатор запису, додасть її в блокнот і поверне вам URL створеного запису (для доступу до запису по GET або для видалення по DELETE). При цьому добре б повернути клієнту URL створеної записи.

    Припустимо, запис з ідентифікатором post-id вже створено і він доступний по URL mydomain/notebooks/id/posts/post-id. Але клієнт (власник запису) виправив в ній помилку і хоче перезаписати її. Для цього він використовує метод PUT з URL mydomain/notebooks/id/posts/post-id і передає оновлений запис в тілі запиту. Ваш сервіс, орієнтуючись на метод PUT видаляє старий запис і записує новий, при цьому він доступний за тим же URL.

    Звичайно, ніхто не заважає вам завжди використовувати метод POST (наприклад HTML 4 дозволяв використовувати тільки методи GET і POST). Але все ж варто дотримуватися рекомендацій з метою однакового трактування методів усіма розробниками.

    Рекомендується використовуватися метод POST для створення підлеглого ресурсу (дочірнього по відношенню до іншого ресурсу; приклад блокнота і записи якраз дуже підходить).


  12. Відмінності насправді кардинальні.

    Річ у тому, що в першому випадку у вас ліниве, а в другому - енергійне обчислення відповіді. Це означає, що елементи вихідної послідовності в енергійному випадку обчислюються всі і відразу, а в ледачому випадку - тільки коли запитані і тільки ті, що запитані.

    Подивімося, де з практичного боку є різниця.

    Для випадку ледачого обчислення вся послідовність не присутня повністю в пам'яті. Це означає, що при обробці по елементах у нас не виділяється пам'ять, і зберігається cache locality:

    IEnumerable GenerateHugeSequenceLazy()
    {
        for (int i = 0; i < 1000000; i++)
            yield return 13 * i;
    }
    
    IEnumerable GenerateHugeSequenceEager()
    {
        var result = new List();
        for (int i = 0; i < 1000000; i++)
            result.Add(13 * i);
        return result;
    }
    

    Обчислюємо функцію на всій послідовності, порівнюємо витрата пам'яті:

    var seqLazy = GenerateHugeSequenceLazy();
    // вичисляємо максимум вручну
    var max = 0;
    foreach (var v in seqLazy)
        if (v > max)
            max = v;
    
    var memLazy = GC.GetTotalMemory(forceFullCollection: false);
    
    var seqEager = GenerateHugeSequenceEager();
    // вичисляємо максимум вручну
    max = 0;
    foreach (var v in seqEager)
        if (v > max)
            max = v;
    
    var memEager = GC.GetTotalMemory(forceFullCollection: false);
    
    Console.WriteLine($"Memory footprint lazy: , eager: ");
    

    Результат:

    Memory footprint lazy: 29868, eager: 6323088
    

    Далі, у нас досить великі відмінності в розумінні операцій. Енергійні обчислення проводяться в момент виклику функції, в той час, як ледачі обчислення відбуваються в момент, коли ви користуєтеся результатом. А значить, для реального обчислення ледачої послідовності стан аргументів буде взято на момент перерахування. Ось приклад:

    IEnumerable DoubleEager(IEnumerable seq)
    {
        var result = new List();
        foreach (var e in seq)
            result.Add(e * 2);
        return result;
    }
    
    IEnumerable DoubleLazy(IEnumerable seq)
    {
        foreach (var e in seq)
            yield return e * 2;
    }
    

    Дивимося на відмінності:

    var seq = new List() { 1 };
    var eagerlyDoubled = DoubleEager(seq);
    var lazilyDoubled = DoubleLazy(seq);
    
    Console.WriteLine("Eager: " + string.Join(" ", eagerlyDoubled));
    Console.WriteLine("Lazy : " + string.Join(" ", lazilyDoubled));
    // виведе обидва рази 2, поки відмінностей немає
    
    seq.Add(2); // змінюємо вихідну послідовність
    
    Console.WriteLine("Eager: " + string.Join(" ", eagerlyDoubled)); // 2
    Console.WriteLine("Lazy : " + string.Join(" ", lazilyDoubled));  // 2 4
    

    Оскільки ліниве обчислення відбувається при перерахуванні, ми бачимо, що при зміні послідовності лінива версія підхоплює зміни.

    Інший приклад. Подивимося, що буде, якщо ми не обчислюємо всю послідовність. Обчислимо одну і ту ж послідовність енергійно та ліниво:

    IEnumerable Eager10()
    {
        Console.WriteLine("Eager");
        int counter = 0;
        try
        {
            var result = new List();
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine($"Adding: ");
                counter++;
                result.Add(i);
            }
            return result;
        }
        finally
        {
            Console.WriteLine($"Eagerly computed: ");
        }
    }
    
    IEnumerable Lazy10()
    {
        Console.WriteLine("Lazy");
        int counter = 0;
        try
        {
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine($"Adding: ");
                counter++;
                yield return i;
            }
        }
        finally
        {
            Console.WriteLine($"Lazily computed: ");
        }
    }
    

    Беремо тільки 2 елементи з результату:

    foreach (var e in Eager10().Take(2))
        Console.WriteLine($"Obtained: ");
    
    foreach (var e in Lazy10().Take(2))
        Console.WriteLine($"Obtained: ");
    
    foreach (var e in Lazy10())
    {
        Console.WriteLine($"Obtained: ");
        if (e == 1)
            break;
    }
    

    Отримуємо такий висновок на консоль:

    Eager
    Adding: 0
    Adding: 1
    Adding: 2
    Adding: 3
    Adding: 4
    Adding: 5
    Adding: 6
    Adding: 7
    Adding: 8
    Adding: 9
    Eagerly computed: 10
    Obtained: 0
    Obtained: 1
    Lazy
    Adding: 0
    Obtained: 0
    Adding: 1
    Obtained: 1
    Lazily computed: 2
    Lazy
    Adding: 0
    Obtained: 0
    Adding: 1
    Obtained: 1
    Lazily computed: 2
    

    Бачите різницю? Лінивий варіант прогнав цикл всього два рази, і не обчислював «хвіст» послідовності.

    Ще одна різниця між випадками - коли повідомляються помилки. У разі енергійного обчислення вони повідомляються відразу. У разі ледачого - лише при перерахуванні результату. приклад:

    IEnumerable CheckEagerly(int value)
    {
        if (value == 0)
            throw new ArgumentException("value cannot be 0");
        return new List { value };
    }
    
    IEnumerable CheckLazily(int value)
    {
        if (value == 0)
            throw new ArgumentException("value cannot be 0");
        yield return value;
    }
    

    Застосовуємо try / catch:

    Console.WriteLine("Eager:");
    IEnumerable seqEager = null;
    try
    {
        seqEager = CheckEagerly(0);
    }
    catch (ArgumentException)
    {
        Console.WriteLine("Exception caught");
    }
    
    if (seqEager != null)
        foreach (var e in seqEager)
            Console.WriteLine(e);
    
    Console.WriteLine("Lazy:");
    IEnumerable seqLazy = null;
    try
    {
        seqLazy = CheckLazily(0);
    }
    catch (ArgumentException)
    {
        Console.WriteLine("Exception caught");
    }
    
    if (seqLazy != null)
        foreach (var e in seqLazy)
            Console.WriteLine(e);
    

    Отримуємо результат:

    Eager:
    Exception caught
    Lazy:
    
    Unhandled Exception: System.ArgumentException: value cannot be 0
       at Program.d__3.MoveNext() in ...\Program.cs:line 59
       at Program.Run() in ...\Program.cs:line 45
       at Program.Main(String[] args) in ...\Program.cs:line 13
    

    Для того, щоб отримати «найкраще з обох світів», тобто, ліниве обчислення, але енергійну перевірку аргументів, найпростіше розділити функцію на дві: енергійну перевірку і ліниве обчислення без перевірки. Для сучасних версій C# зручно використовувати вкладені функції:

    IEnumerable CheckEagerlyEnumerateLazily(int value)
    {
        if (value == 0)
            throw new ArgumentException("value cannot be 0");
        return Impl();
    
        IEnumerable Impl()
        {
            yield return value;
        }
    }
    

    Перевіряємо:

    Console.WriteLine("Recommended way:");
    IEnumerable seqLazy = null;
    try
    {
        seqLazy = CheckEagerlyEnumerateLazily(0);
    }
    catch (ArgumentException)
    {
        Console.WriteLine("Exception caught");
    }
    
    if (seqLazy != null)
        foreach (var e in seqLazy)
            Console.WriteLine(e);
    

    і отримуємо

    Recommended way:
    Exception caught
    

    Ще один випадок відмінності - залежність від зовнішніх даних в процесі обчислення. Наступний код намагається впливати на обчислення, змінюючи глобальний стан. (Це не дуже хороший код, не робіть так в реальних програмах!)

    bool evilMutableAllowCompute;
    
    IEnumerable EagerGet5WithExternalDependency()
    {
        List result = new List();
        for (int i = 0; i < 5; i++)
        {
            if (evilMutableAllowCompute)
                result.Add(i);
        }
        return result;
    }
    
    IEnumerable LazyGet5WithExternalDependency()
    {
        for (int i = 0; i < 5; i++)
        {
            if (evilMutableAllowCompute)
                yield return i;
        }
    }
    

    Використовуємо:

    Console.WriteLine("Eager:");
    evilMutableAllowCompute = true;
    foreach (var e in EagerGet5WithExternalDependency())
    {
        Console.WriteLine($"Obtained: ");
        if (e > 0)
            evilMutableAllowCompute = false;
    }
    
    Console.WriteLine("Lazy:");
    evilMutableAllowCompute = true;
    foreach (var e in LazyGet5WithExternalDependency())
    {
        Console.WriteLine($"Obtained: ");
        if (e > 0)
            evilMutableAllowCompute = false;
    }
    

    Результат:

    Eager:
    Obtained: 0
    Obtained: 1
    Obtained: 2
    Obtained: 3
    Obtained: 4
    Lazy:
    Obtained: 0
    Obtained: 1
    

    Ми бачимо, що зміна глобальних даних навіть після формального відпрацювання ледачої функції може впливати на обчислення.

    (Це ще один аргумент на користь того, що функціональне програмування і мутабельний стан погано поєднуються.)