• Правильно ли я выравниваю горизонтальное меню по центру?

    @bromzh
    он куда лучше, чем комментарии вокруг элементов списка.
    Да чем он лучше-то? Хоть один явный плюс назови. И хоть один минус моего подхода.
    Очень многие крупные сайты используют комментарии, это распространённая практика. А эти костыли с размером шрифта только создают новые проблемы и всё. Как раз-таки люди, которые будут поддерживать твой код могут в неожиданном месте получить проблемы. И им придётся лопатить весь css, пытаясь понять, что же не так, и почему на компе всё нормально, а на мобильнике выглядит не так. Плюс, про адаптивность я уже сказал. Дело тут не в том, что меню заурядное и простое, а в том, что размеры шрифтов при разных разрешениях будут плохими. И это реальная проблема, а не надуманная, типа "html выглядит не очень".
  • Примеры классов в программировании?

    @bromzh
    @cjey:
    Вы не можете реализовать ООП без любого из этих паттернов.
    Очень смешно. Ты видимо прочитал про эти паттерны, но не разобрался, что есть что. Давай по пунктам:

    Инкапсуляция. Проверка прав доступа данных на уровне языка. Нельзя случайно испортить чужую переменную.
    В питоне есть ООП, но инкапсуляции нет. Нет там private-полей. По твоей логике, в питоне нет ООП. В javascript тоже нет инкапсуляции в явном виде, она там реализуется замыканиями. Да и вообще, в любом языке с поддержкой замыканий можно очень легко ограничивать уровни видимости переменных. Кроме того, сеттеры и геттеры нарушают инкапсуляцию. А с помощью рефлексии в яве и шарпах можно получить доступ к private полям напрямую. Именно поэтому в питоне отказались от инкапсуляции: вся ответственность лежит на программисте, он сам решает, менять какое-то поле или нет. И дискомфорта не ощущается.

    Наследование. Можно породить сущность на основе уже существующей, немного ее изменив.
    В javascript нет наследования (в обычном понимании). Там есть делегирование. Да, часто пишут "наследование через прототип", но это не правда. Во-первых, статические поля не наследуются, во-вторых, экземпляр потомка добавляет свои методы и к родителю:
    function Foo() {};
    Foo.prototype.foo = function() {}
    var foo = new Foo();
    function Bar() {};
    Bar.prototype = Foo.prototype;
    Bar.prototype.bar = function() {}
    foo.bar // да, метод из дочернего "класса" Bar добавится ко всем "экземплярам" "класса" Foo.

    Да, эту проблему можно обойти, если каждый раз создавать новый объект-родитель:
    Bar.prototype = new Foo();
    Хотя и в таком случае все методы попадут в родитель, просто родитель нигде не используется. К тому же, ещё и вызовется функция-конструктор Foo, что не всегда желательно. Естественно, что это можно обойти. Но в любом случае, делегирование - это не одно и тоже, что наследование. Однако, ООП в javascript есть (но. видимо, не для тебя).

    Абстракция. Можно работать с объектами как с черным ящиком, не задумываясь как оно устроено внутри.
    Каким боком это относится к ООП? Абстракция есть в любом языке. Я могу написать функцию, решающую уравнения. Как я реализую это: методом простой итерации, методом Ньютона или ещё как-нибудь, конечному пользователю не важно, он использует мою функцию как чёрный ящик: не вход подаёт функцию, на выходе ожидает значение. При этом тоже можно не задумываться о внутреннем устройстве.

    Полиморфизм. Можно работать с группой разных сущностный через общий интерфейс.
    Полиформизм - понятие теории типов. Таким образом, в любом языке с типами есть полиформизм. При этом, в таких языках, как хаскель и скала, он "более крут" (да к тому же ещё и типобезопасен!), нежели в обычных ООП, типа явы или плюсов.

    Что в итоге? Из 4-х пунктов, 2 есть во всех высокоуровневых языках, 2 пункта могут и не реализовываться языком, но при этом такой язык будет поддерживать полноценное ООП (js, например).
    Кроме того, язык может поддерживать одновременно все эти 4 пункта, но поддерживать ООП (хаскель, например).
    И да, понятие класс вводится для удобства. Если есть смысл использовать ОО-подход, то лучше взять язык с поддержкой ООП, нежели писать всё самому. Но и пихать ООП везде тоже неправильно. Однако, ни понятие "класс", ни один из 4-х пунктов не является ни необходимым ни достаточным условием для того, чтобы язык имел поддержку ООП.
  • Правильно ли я выравниваю горизонтальное меню по центру?

    @bromzh
    Alexander Mischuk: А что же ты со своим другом пашей молчишь про проблемы, которые возникают, если использовать твой метод? Может ты их и не знаешь? Давай я расскажу тогда:
    1) Твой вариант не работает на андроиде: codepen.io/stowball/details/LsICH
    2) Твой вариант ломает рендер шрифтов на сафари: cdn.css-tricks.com/wp-content/uploads/2012/04/Scre...
    3) И самое главное: при использовании твоего чудо варианта нельзя задать шрифты для ul > li в емах, только в неотносительных единицах (пикселях, пунктах и т.д.). А это значит - прощай адаптивная вёрстка. Надо объяснить, чем плохи пиксельные шрифты и как они по-разному будут выглядеть на ретине и на мобилке?

    Что в иттоге? Пока все нормальные люди пользуются методами без css с font-size:0 и живут счастливо, ты создаёшь себе проблемы на пустом месте.
  • Как делают вызов функции с разными параметрами?

    @bromzh
    Евгений Петров:
    1) да, ошибся. перепутал с питоном, где пустые словари и массивы - ложны
    2) это мелочи
    3)
    > function foo(a, b, c) {var d = c; console.log(a, b, c, d)}
    > foo(1)
    1 undefined undefined undefined

    Где тут ошибка? Если в том же питоне так сделать, то вылезет ошибка уже при попытке вызова, в js же всё работает.
  • Качество специально уменьшеной картинки — самообман?

    @bromzh
    @krasnblj: А, ну тут уже вопрос, по каким алгоритмам сжимает браузер и фотошоп. Плюс, когда ты сохраняешь картинку - это одно. Там уже идёт зависимость от формата. Для показа (если я правильно понимаю) формат не играет роли, это просто набор пикселей, которые уменьшаются каким-то алгоритме при рендере.
  • Правильно ли я выравниваю горизонтальное меню по центру?

    @bromzh
    Alexander Mischuk: ага, а потом восстанавливать его надо для дочерних. А если понадобится использовать, например, заголовки в таком li, то для них надо заново прописывать размеры (которые могут вообще задаваться юзерагентами браузера). Отлично просто.
    @GoodProject: Текст внутри li? Можно задать min-width.
    Pavel Yakovlev: это старый и самый простой вариант решения проблемы. Есть ещё решения: css-tricks.com/fighting-the-space-between-inline-b...
    Но раз это говнокод, то предложи свой более простой и красивый вариант решения, интересно послушать.
  • Python 2 vs Python 3 ?

    @bromzh
    Да, точно. Плюс, есть ещё библиотеки от создателей asyncio, которые пока не вошли в питон, но их планируют включить. Например, asyncio не будет поддерживать http, однако aiohttp будет и её включат, когда допилят.
  • Примеры классов в программировании?

    @bromzh
    На хабре была замечательная статья по этому поводу. В кратце, все эти 4 паттерна спокойно реализуются вообще без капли ООП и не являются необходимыми для реализации ООП (как и понятие "класс", см прототипное ООП).
    habrahabr.ru/post/147927
  • Создать демона на python 2.7 ?

    @bromzh
    @icCE: Согласен, штука очень похожа на супервизор и вроде довольно удобная. Но питон в юниксах встречается как раз-таки куда чаще, чем апстарт. К тому же (как я понял), последний является частью загрузки самой системы, его нельзя установить локально, а супервизор можно. Ну и как по мне, легче разобраться в настройках супервизора, их не так много. В апстарте всё немного посложнее будет.
  • Создать демона на python 2.7 ?

    @bromzh
    @icCE:
    supervisor может не быть в пакетах.
    Он доступен через pip. Так как скрипт питоновский, то pip или хотя бы eazy_install точно стоят в системе.
    Я могу привести много аргументов в пользу супервизора:

    - Автоматический перезапуск скрипта при его падении. Без него придётся писать дополнительный код на баше.

    - Запуск нескольких экземпляров одной программы с разными параметрами. Например, надо запустить 4 экземпляра сервера на разных портах. В супервизоре это делается элементарно:
    [program:foo]
    command = python runserver.py --port=80%(process_num)02d
    process_name = foo-%(process_num)02d
    stdout_logfile = foo-80%(process_num)02d.log
    numprocs = 5

    Это запустит 4 экземпляра процессов на подряд идущих портах, при этом, логи каждой будут в разных файлах:
    Имя    Порт  Лог
    foo-01 8000  foo-01.log
    foo-02 8001  foo-02.log
    foo-03 8002  foo-03.log
    foo-04 8003  foo-04.log

    В случае скрипта, придётся писать дополнительный код на баше.

    - Приоритет задач. Чем меньше число, тем важнее задача, она будет запускаться в первую очередь. Если управлять скриптами, надо, например, именовать файлы цифрами в начале, загружать конфиги из одной папки.

    - Таймаут на запуск задачи. Если задача запускается слишком долго, то она завершается. В скрипте надо опять писать код, контролирующий это.

    - Контроль за размером лога. И опять, надо писать код, чтобы такое работало в скрипте.

    - Объединение задач в группы.

    - У супервизора есть удобные веб-морды: node.js, есть версии для джанги и пхп.

    - Ещё там есть всякие полезные плагины.

    - Управление всеми запущенными процессами из одного места. Можно смотреть список запущенных из супервизора программ, их статусы, можно управлять всеми или конкретными задачами. В случае простого скрипта надо как-то хранить и получать список таких задач. И если каждая задача описывается в своём баш-файле, то надо ещё как-то контролировать запуск самих скриптов.

    В итоге, чтобы с комфортом управлять задачами в твоём варианте придётся писать много кода на баше и выйдет свой велосипед. В случае супервизора, заместо 50-1000 строк скрипта, можно всё описать простым конфигом в 3-5 строчек для каждой задачи, и при этом не выпить ни капли рома^W^W^W^W написать ни одной строчки на баше.

    Я не утверждаю, что нельзя на баше реализовать подобное. Просто это дольше и сложнее. Ну и всё-таки, разница между фоновым процессом и демоном совсем невелика, и всегда можно заменить одно на другое с некоторыми огоорками. И супервизор запускает демонов, хотя можно запускать задачи в режиме фоновых процессов.
  • Создать демона на python 2.7 ?

    @bromzh
    В техническом смысле демоном считается процесс, который не имеет управляющего терминала.
    Это с вики. Можешь ещё на английской прочитать, как демоны создавать. В некоторых дистрах есть start-stop-daemon.

    Почему я в скрипте это "зациклел"
    Ты зациклил только потому, что сама программа, которую ты запускаешь, делает какое-то действие и выходит. По-сути, ты написал новую программу на баше, которая в цикле выполняет какой-то процесс, анализирует его вывод и спит некоторое время, после чего по-новой.
    Так вот, если сама программа сама запускается в бесконечном цикле, то вручную зацикливать не нужно. Если просто запустить такую программу, то терминал будет занят, в нём будет вывод такой программы. Если запустить в фоне, то процесс всё равно будет привязан к терминалу, поэтому при закрытии терминала такой процесс будет завершён. Если же отсоединить такой процесс, то получится как раз демон.

    почему у многих программ есть отдельный режим работы демоном ?
    потому что обычно такие программы просто запускают бесконечный цикл, т.н. loop. Это может быть луп от GUI-фреймворка (например, в qt вызов метода QApplication::exec запускает такой бесконечный цикл), может быть ioloop какого-нибудь сетевого фреймворка (например, в питоне 3.4 это asyncio.get_event_loop().run_forever()). Т.е. сама программа выполняется "бесконечно". И такие программы демонизируются внешне: обычно это простой скрипт в init.d. Т.е. как такового режиме демона нет. Вот простой пример: монгоДБ. Она предоставляет 2 команды: mongod и mongo. Первая запускается в бесконечном цикле. Если отдельно её не демонизировать, то процесс при закрытии терминала умрёт. Демонизация происходит в init.d. Да, некоторый программы сразу могут запускаться как демон, но за кулисами там точно такой же алгоритм.

    и как бы мне помог ваш супервизор в данной ситуации.
    Очень просто: весь твой бесконечный цикл надо вынести в bash-скрипт, а в супервизоре в настройках надо просто указать нужную команду.
    # foo.sh
    INT_WAN=ppp0
    WAN_IP=$(ip addr show $INT_WAN | awk '/inet/ {print $2}')
    ./ipv6update 
    while true
    do
        IP_ADDR=$(ip addr show $INT_WAN | awk '/inet/ {print $2}')
        if [ "$IP_ADDR" != "$WAN_IP" ]; then
            WAN_IP="$IP_ADDR"
            ./ipv6update
        fi
        sleep 60
    done

    А в конфиге супервизора достаточно указать bash /path/to/foo.sh, настроить лог-файлы и запустить эту программу через клиента супервизора - supervisorctl reread && supervisor start.
  • Создать демона на python 2.7 ?

    @bromzh
    @icCE: Где я напутал? Демон - это процесс, отключённый от терминала. Ты в своём скрипте делаешь это вручную, супервизор делает за тебя. И разница между демоном и процессом, запущенным в screen и демоном совсем небольшая. Если в скрине у процесса перенаправить стандартные ввод и выводы (out и err) в файл, то всё будет работать идентично.
  • Создать демона на python 2.7 ?

    @bromzh
    @icCE: Не, я имею ввиду, к чему такая сложность в запуске самого демона. Вот есть готовый питоновский скрипт. Его надо демонизировать. Самый (на мой взгляд) простой и одновременно надёжный вариант - использовать supervisord.
    Он позволяет с лёгкостью запускать всякие скрипты, сервера приложений (для питона, для руби, для любого другого языка). Очень прост в использовании. Позволяет настраивать логирование, запуск от определённого пользователя, переменные окружения (для virtualenv, например), перезапуск при падении, запуск и мониторинг сразу нескольких задач, автостарт и многое другое.

    Т.е. отпадает необходимость вручную писать баш-скрипты, которые хранят пид, запускают программу, перенаправляют вывод и т.д. Это всё просто автоматизированно и очень удобно. Ты просто описываешь конфиг для каждой задачи, требующей демонизации, читаешь его (для supervisord есть удобный CLI), запускаешь. Далее, ты можеш остановить отдельную задачу, посмотреть статус, и т.д.
  • Создать демона на python 2.7 ?

    @bromzh
    @icCE: Б-же, зачем такие сложности, чтобы запустить 1 простой скрипт?
  • Кто отвечает за анимации сайта?

    @bromzh
    Правильный ответ — наличием/отсутствием класса.
    Не совсем правильный. Например, если нужна анимация при скроллинге, какой там будет отслеживаться класс?
    jQuery не справляется с этой задачей?)
    А где это я такое написал? Я лишь сказал, что есть альтернативы, приём более шустрые.
    Единственное место для применения библиотек в качестве источника анимации — применение canvas.
    ORLY? А если надо начать анимацию для элемента DOM при наведении/клике на другой элемент? А если надо анимировать что-то при скроллинге?
  • Кто отвечает за анимации сайта?

    @bromzh
    Ну css может работать только с ограниченным набором событий. На некоторые сложные события всё же нужно прикручивать js. Но тут выбор не ограничивается jquery, можно юзать greensock-библиотеку. Она быстрее jquery и богаче на всякие эффекты.
  • На сколько разумно вставлять картинки через тег i?

    @bromzh
    Я не разработчик бутстрапа, сказать точно не могу. Можешь им письмо написать и спросить.
    Я думаю, что приняли, потому что хотели выделить иконку как отдельную сущность, и i был наиболее близок и понятен на тот момент. Отказались, потому что стандарты изменились и это стало нарушать семантику. Использовать теги не по их назначению - плохо, тем более с учётом утверждения уклона html5 в семантику. Крупные интернет-деятели тоже участвуют в создании этих стандартов, и игнорировать их глупо. Поисковикам легче парсить структурированный документ, нежели кучу div-ов с ни о чём не говорящими классами.
    Что касается иконок - их очень трудно вместить в стандарт. Нужно вводить кучу определённых названий для них. Да и на семантику они влияют слабо - это всё же больше графический, нежели смысловой инструмент. С точки зрения html элемент-иконка может быть любым. А вот как отображать - маленькой картинкой или текстом - это уже удел css.
  • На сколько разумно вставлять картинки через тег i?

    @bromzh
    @mlnkv раньше все таблицами верстали. Сейчас появились нормальные инструменты и подходы для вёрстки, и это стало ненормально. Времена меняются. Если не будешь меняться вместе с ними - останешься без работы.
  • Как развернуть Java приложение на сервере?

    @bromzh
    Вместо nohup можно использовать screen. Алгоритм такой (я опишу для пользователя root, но на деле надо создать обычного пользователя в твоём VPS):
    1) Копируешь по ssh твой jar: scp foo.jar root@hostname:/root/
    2) Заходишь по ssh на твой серв: ssh root@hostname
    3) Запускаешь скрин: screen
    4) Выполняешь запуск нужной программы: java -jar foo.jar
    5) Жмёшь Ctrl-A, потом D. Скрин сворачивается, но програма в нём продолжает выполняться.
    6) Выходишь с сервера, программа продолжает работать.
    Чтобы вернуться:
    1) Логинишься по ssh к серву
    2) Открываешь свёрнутый скрин: screen -r
    Там будет сессия с запущенной ранее программой.