garyck
garyck
Записная книжка
35 posts
Don't wanna be here? Send us removal request.
garyck · 3 years ago
Text
Шпаргалка по Docker
Установка
Linux curl -sSL https://get.docker.com/ | sh Mac Скачайте dmg по этой ссылке: https://download.docker.com/mac/stable/Docker.dmg Windows Используйте MSI-инсталлятор: https://download.docker.com/win/stable/InstallDocker.msi
Реестры и репозитории Docker
Вход в реестр docker login docker login localhost:8080 Выход из реестра docker logout docker logout localhost:8080 Поиск образа docker search nginx docker search nginx -- filter stars=3 --no-trunc busybox Pull (выгрузка из реестра) образа docker pull nginx docker pull eon01/nginx localhost:5000/myadmin/nginx Push (загрузка в реестр) образа docker push eon01/nginx docker push eon01/nginx localhost:5000/myadmin/nginx
Первые действия с контейнерами
Создание контейнера docker create -t -i eon01/infinite --name infinite Первый запуск контейнера docker run -it --name infinite -d eon01/infinite Переименование контейнера docker rename infinite infinity Удаление контейнера docker rm infinite Обновление контейнера docker update --cpu-shares 512 -m 300M infinite
Запуск и остановка контейнеров
Запуск остановленного контейнера docker start nginx Остановка docker stop nginx Перезагрузка docker restart nginx Пауза (приостановка всех процессов контейнера) docker pause nginx Снятие паузы docker unpause nginx Блокировка (до остановки контейнера) docker wait nginx Отправка SIGKILL (завершающего сигнала) docker kill nginx Отправка другого сигнала docker kill -s HUP nginx Подключение к существующему контейнеру docker attach nginx
Получение информации о контейнерах
Работающие контейнеры docker ps docker ps -a Логи контейнера docker logs infinite Информация о контейнере docker inspect infinite docker inspect --format '{{ .NetworkSettings.IPAddress }}' $(docker ps -q) События контейнера docker events infinite Публичные порты docker port infinite Выполняющиеся процессы docker top infinite Использование ресурсов docker stats infinite Изменения в файлах или директориях файловой системы контейнера docker diff infinite
Управление образами
Список образов docker images Создание образов docker build . docker build github.com/creack/docker-firefox docker build - < Dockerfile docker build - < context.tar.gz docker build -t eon/infinite . docker build -f myOtherDockerfile . curl example.com/remote/Dockerfile | docker build -f - . Удаление образа docker rmi nginx Загрузка репозитория в tar (из файла или стандартного ввода) docker load < ubuntu.tar.gz docker load --input ubuntu.tar Сохранение образа в tar-архив docker save busybox > ubuntu.tar Просмотр истории образа docker history Создание образа из контейнера docker commit nginx Тегирование образа docker tag nginx eon01/nginx Push (загрузка в реестр) образа docker push eon01/nginx
Сеть
Создание сети docker network create -d overlay MyOverlayNetwork docker network create -d bridge MyBridgeNetwork docker network create -d overlay \ --subnet=192.168.0.0/16 \ --subnet=192.170.0.0/16 \ --gateway=192.168.0.100 \ --gateway=192.170.0.100 \ --ip-range=192.168.1.0/24 \ --aux-address="my-router=192.168.1.5" --aux-address="my-switch=192.168.1.6" \ --aux-address="my-printer=192.170.1.5" --aux-address="my-nas=192.170.1.6" \ MyOverlayNetwork Удаление сети docker network rm MyOverlayNetwork Список сетей docker network ls Получение информации о сети docker network inspect MyOverlayNetwork Подключение работающего контейнера к сети docker network connect MyOverlayNetwork nginx Подключение контейнера к сети при его запуске docker run -it -d --network=MyOverlayNetwork nginx Отключение контейнера от сети docker network disconnect MyOverlayNetwork nginx
Очистка Docker
Удаление работающего контейнера docker rm nginx Удаление контейнера и его тома (volume) docker rm -v nginx Удаление всех контейнеров со статусом exited docker rm $(docker ps -a -f status=exited -q) Удаление всех остановленных контейнеров docker container prune docker rm `docker ps -a -q` Удаление контейнеров, остановленных более суток назад docker container prune --filter "until=24h" Удаление образа docker rmi nginx Удаление неиспользуемых (dangling) образов docker image prune docker rmi $(docker images -f dangling=true -q) Удаление неиспользуемых (dangling) образов даже с тегами docker image prune -a Удаление всех образов docker rmi $(docker images -a -q) Удаление всех образов без тегов docker rmi -f $(docker images | grep "^<none>" | awk "{print $3}") Остановка и удаление всех контейнеров docker stop $(docker ps -a -q) && docker rm $(docker ps -a -q) Удаление неиспользуемых (dangling) томов docker volume prune docker volume rm $(docker volume ls -f dangling=true -q) Удаление неиспользуемых (dangling) томов по фильтру docker volume prune --filter "label!=keep" Удаление неиспользуемых сетей docker network prune Удаление всех неиспользуемых объектов docker system prune По умолчанию для Docker 17.06.1+ тома не удаляются. Чтобы удалились и они тоже: docker system prune --volumes
Docker Swarm
Установка Docker Swarm curl -ssl https://get.docker.com | bash Прим. перев.: в Docker версий 1.12.0+ ничего дополнительно устанавливать не требуется, т.к. Docker Swarm встроен в Docker Engine в виде специального режима (Swarm mode). Инициализация Swarm docker swarm init --advertise-addr 192.168.10.1 Подключение рабочего узла (worker) к Swarm docker swarm join-token worker Подключение управляющего узла (manager) к Swarm docker swarm join-token manager Список сервисов docker service ls Список узлов docker node ls Создание сервиса docker service create --name vote -p 8080:80 instavote/vote Список заданий Swarm docker service ps Масштабирование сервиса docker service scale vote=3 Обновление сервиса docker service update --image instavote/vote:movies vote docker service update --force --update-parallelism 1 --update-delay 30s nginx docker service update --update-parallelism 5--update-delay 2s --image instavote/vote:indent vote docker service update --limit-cpu 2 nginx docker service update --replicas=5 nginx
P.S.
Прим. перев.: Напомню, что оригинальная (англоязычная) версия Docker Cheat Sheet доступна и обновл��ется в Git-репозитории. Автор будет рад исправлениям/пополнениям от сообщества. Читайте также в нашем блоге:
«Play with Docker — онлайн-сервис для практического знакомства с Docker».
«В чём суть проекта Moby и почему главным репозиторием Docker вдруг стал moby/moby?»
«Собираем Docker-образы для CI/CD быстро и удобно вместе с dapp (обзор и видео)».
1 note · View note
garyck · 3 years ago
Text
Установка cytomine
1. Распаковка Cytomine-bootstrap
Для установки Cytomine Community необходимо запустить:
mkdir Cytomine_bootstrap/ cd Cytomine_bootstrap/ wget https://github.com/cytomine/Cytomine-bootstrap/archive/v3.0.1.zip -O bootstrap.zip unzip bootstrap.zip mv Cytomine-bootstrap-3.0.1/* . rm -rf bootstrap.zip Cytomine-bootstrap-3.0.1/
2. Конфигурация Cytomine
Открыть файл configuration.sh в текстовом редакторе.
Настройка ссылок
Для запуска Cytomine необходимо настроить ссылки:
CORE_URL ссылка на основной Cytomine сервер.
IMS_URL ссылка на сервер изображений.
UPLOAD_URL ссылка для загрузки новых изображений.
CORE_URL, IMS_URL и UPLOAD_URL эти ссылки ДОЛЖНЫ быть ра��ными доменами. Как пример, cytomine.domain.my и cytomine.domain.my/ims не будет работать, т.к. это один домен, зато cytomine.domain.my, cytomine-ims.domain.my, ... являются правильными ссылками.
Организуйте доступность установленной системы:
Для организации общего доступа, создайте DNS записи и сделайте доступными порты HTTP(S) (80/443) для адресов ваших хостов. Обычно это делают администраторы.
переменные $CORE_URL, $IMS_URL and $UPLOAD_URL должны быть заменены на ваши значения. Для локальной установки, откройте файл /etc/hosts в текстовом редакторе и добавьте например такие записи: 127.0.0.1 localhost-core 127.0.0.1 localhost-ims1 127.0.0.1 localhost-ims2 127.0.0.1 localhost-upload 127.0.0.1 rabbitmq
В Mac OS, запустите run sudo killall -HUP mDNSResponder после изменения /etc/hosts update.
Настройка путей на диске
Все пути указанные в файле конфигурации в разделе PATH должны существовать, в нашем случае должны быть проброшены из Докера.
Другие настройки
О других настройках можно почитать по этой ссылке.
3. Запуск Cytomine
Для инициализации вашего конфигурационного файла. Запустите:
bash init.sh
Затем запустите запуск Cytomine
sudo bash start_deploy.sh
В первый запуск будет произведено скачивание необходимых компонентов, это может занять значительное время, всё зависит от скорости соединения.
4. Первый запуск
Для входа в Cytomine необходимо в браузере набрать ссылку, которая была указана в переменной CORE_URL (в примере localhost-core). По-умолчанию в системе создана учетная запись admin . Пароль к этому аккаунту генерируется случайным образом. Посмотреть сгенерированный пароль администратора можно в файле configs/core/cytomineconfig.groovy для этого можно набрать команду:
cat configs/core/cytomineconfig.groovy | grep adminPassword
При первом входе желательно изменить пароль администратора.
Изменение конфигурации
Если вам необходимо что-то изменить в файле configuration.sh необходимо после манипуляций снова проинициализировать систему, запустив:
bash init.sh sudo bash restart.sh
Остановка сервера
Для остановки Cytomine запустите скрипт clean_docker_keep_data.sh он остановит все докер контейнеры.
sudo bash clean_docker_keep_data.sh
Сервер будет остановлен, но все данные (ба��ы данных и изображения) останутся
Если что-то не заработает:
1) Если хотите использовать вместо 80 порта другой нужно сделать следующее:
1.1. В файле configuration.sh:
Найти строку и поменять по подобию:
CORE_URL=хост:порт
1.2. Запустить:
sudo bash init.sh
1.3. Добавить в файл configs/core/cytomineconfig.groovy строки:
grails.plugin.springsecurity.failureHandler.ajaxAuthFailUrl = "${grails.serverURL}/login/authfail?ajax=true"
grails.plugin.springsecurity.failureHandler.ajaxAuthFailUrl = "${grails.serverURL}/login/ajaxSuccess"
1.4. В файле start_deploy.sh найти и заменить строку:
-p 80:80 \
на
-p порт:80 \
2) Если пароль не будет подходить:
sudo sh clean_docker_keep_data.sh sudo docker volume rm postgis_data #clean the database sudo sh restart.sh
0 notes
garyck · 4 years ago
Text
Шпаргалка PostgreSQL
АДМИНИСТРИРОВАНИЕ
Узнать версию БД
SELECT version()
Узнать размер БД
SELECT pg_size_pretty(pg_database_size(current__database()));
Размер таблицы
SELECT pg_size_pretty(pg_relation_size('имя базы'));
Найти самую большую таблицу
SELECT p.relname, p.relpages FROM pg_class p ORDER BY relpages DESC
Перечень пользователей
SELECT p.datname,p.usename,p.client_addr,p.client_port FROM pg_stat_activity p
Информация о запросах
SELECT p.pid, age(p.query_start, clock_timestamp()), p.query_start, p.usename, p.query FROM pg_stat_activity p
WHERE p.query!='<IDLE>' AND p.query NOT LIKE '%pg_stat_activity%'
ORDER BY p.query_start desc
Остановка процесса
SELECT pg_cancel_backend(procpid)
Уничтожение процесса
SELECT pg_terminate_backend(procpid)
Просмотреть настройки БД
SHOW all
Просмотреть работу репликации (на сервере репликации)
SELECT * FROM pg_stat_wal_receiver
Проверить неиспользуемые индексы БД
SELECT
ui.schemaname || '.' || ui.relname AS table,
ui.indexrelname AS index,
pg_size_pretty(pg_relation_size(i.indexrelid)) as index_size, ui.idx_scan as index_scans FROM pg_stat_user_indexes ui
JOIN pg_index i ON ui.indexrelid=i.indexrelid
WHERE NOT indisunique AND idx_scan<50 AND pg_relation_size(relid)>5*819
ORDER BY pg_relation_size(i.indexrelid)/NULLIF(ui.idx_scan,0) DESC NULLS FIRST, pg_relation_size(i.indexrelid) DESC
Дублирование индексов
SELECT a.indrelid::regclass, a.indexrelid::regclass, b.indexrelid::regclass
FROM (SELECT *,array_to_string(indkey,' ') AS cols FROM pg_index) a
JOIN (SELECT *,array_to_string(indkey,' ') as cols FROM pg_index) b ON (a.indrelid=b.indrelid AND a.indexrelid > b.indexrelid AND (
(a.cols LIKE b.cols||'%' AND COALESCE(substr(a.cols,length(b.cols)+1,1),' ')=' ') OR
(b.cols LIKE a.cols||'%' AND COALESCE(substr(b.cols,length(a.cols)+1,1),' ')=' ')
ORDER BY indrelid
Анализ индексов
SELECT s.relname AS tname, s.indexrelname as iname, s.idx_scan as used, pg_size_pretty(pg_relation_size(s.relid)) AS tsize, pg_size_pretty(pg_relation_size(s.indexrelid)) as isize, t.n_tup_upd+t.n_tup_ins+t.n_tup_del as writes, i.indexdef as create FROM pg_stat_user_indexes AS s
JOIN pg_indexes i ON (i.indexname=s.indexrelname AND s.schemaname=i.schemaname)
JOIN pg_stat_user_tables t ON t.relid=s.relid WHERE s.idx_scan<200 AND i.indexdef !~* 'unique'
ORDER BY s.relname, s.indexrelname
Создать таблицу на основе запроса
CREATE TABLE public.spsall AS SELECT a."ге_ключ",a.sps FROM public.allu a
Запрос из соседней БД
CREATE EXTENSION dblink;
SELECT max(l.date_edit) FROM
dblink('hostaddr=127.0.0.1 dbname=flats user=postgres password=postgresselect date_edit from public.logdata') as l(date_edit timestamp)
Список таблиц и полей
SELECT * FROM information_schema.tables WHERE table_schema='public'
Резервное копирование
SET PGPASSWORD=ПАРОЛЬ
pg_dump93.exe -i -h АДРЕС -p ПОРТ -U ПОЛЬЗОВАТЕЛЬ -F c -b -v -f ПУТЬ БАЗА
Настройка состояния сервера PGAdmin в файле конфигурации postgresql.conf найти lc_messages и прописать :
lc_messages = 'UTF-8'
Создание таблицы на основании запроса
CREATE TABLE public.table AS SELECT a.id FROM public.user u WHERE u.on=TRUE
Экспорт информации в файл CSV
COPY (SELECT * FROM people) TO 'ФАЙЛ' ENCODING 'Win1251' DELIMITER ';' CSV HEADER
Импорт информации в файл CSV
COPY ТАБЛИЦА(ПОЛЕ,ПОЛЕ) FROM 'ФАЙЛ' ENCODING 'Win1251' DELIMITER ';' CSV HEADER
Удаление дубликатов (поле ctid имеется во всех строках всех таблиц)
DELETE FROM table WHERE ctid NOT IN
(SELECT max(ctid) FROM table GROUP BY table.*)
Вставка данных из запроса
INSERT INTO ТАБЛИЦА1(ПОЛЕ,ПОЛЕ) SELECT ПОЛЕ,ПОЛЕ FROM ТАБЛИЦА2
Генератор последних четвергов месяца
SELECT (
date trunc('month',d)-interval '1 day' -
(case EXTRACT(DOW FROM date_trunc('month',d)-interval '1 day') when 0 then 3
when 6 then 2
when 5 then 1
when 3 then 6
when 2 then 5
when 1 then 4
else 0
end)*interval '1 day'
)::DATE as last_thesday_in_month FROM
generate_series('01.11.2019'::date,'01.01.2022'::date,interval '1 month') as d ORDER BY 1
Обновление полей из подзапроса
UPDATE accounts SET (contact_first_name, contact_.last_name) = (SELECT first_name, last_name FROM salesmen WHERE salesmen.id = accounts.sales_id);
или
UPDATE accounts SET pontact_first_name = first_name, contact_last_name = last_name FROM salesmen WHERE salesmen.id = accounts.sales id;
Пересечение диапазонов
SELECT * FROM table
WHERE (start1,end1) OVERLAPS (start2,end2)
Рекурсивный запрос
WITH RECURSIVE chtopar AS (
SELECT d.id, d.parent_ref, d.department_sh, 1 as level
FROM staff.departments d
WHERE d.id = 1
UNION ALL
SELECT d.id, d.parent_ref, d.department_sh, c.level+1 as level
FROM staff.departments d
JOIN chtopar c
ON d.parent_ref = c.id
)
SELECT * FROM chtopar;
Работа с массивами
Содержимое массива
SELECT ARRAY[1,4,3] @> ARRAY[3,1] --содержатся ли элементы второго массива в первом
SELECT ARRAY[3,1] <@ ARRAY[1,4,3] --содержатся ли элементы первого массива во втором
Поле массив - в строки
SELECT unnest(arr) as field FROM public.table
Собрать строки в массив
SELECT array_agg(fields) as arr FROM public.table
Множественный LIKE
SELECT * FROM table
WHERE cols LIKE ANY (ARRAY['m%','m%m','%mmm'])
Работа c JSONB
Человекопонятное представиление jsonb
SELECT jsonb_pretty('{"a":{"b":"too"},"c":"foo"}'::jsonb
/*вернет
{"a":
{"b":"too"},
"c":"foo",
"e":3}
*/
Создание jsonb из последовательности значений
SELECT jsonb_build_object('a', 'bar', 'c', 'foo')
--вернет '{"a":"bar","c":"foo"}'
Объединение jsonb
SELECT '{"a":{"b":"too"},"c":"foo"}'::jsonb||'{"e":3}'::jsonb --вернет {"a".{"b";"too"},"c":"foo","e":3}
Получение значений по пути
SELECT '{"а":{"b":"too"},"с":"foo"}'::jsonb#>'{"a","b"}' --вернет "too" SELECT ' {"a": {"b":"too"},"c":"foo"} '::jsonb#>'{"a","b"} ' --вернет too
Преобразование массива в JSONB
SELECT array_to_json('{{1,5},{99, 100}}'::int []) --[ [ 1,5], [ 99, 100]]
Вставить значение
SELECT jsonb_insert('{"а":{"b":"too"},"c":"foo"}'::jsonb, '{a,"d"}', '"bar"')
--вернет {"a":{"b":"too","d":"bar"},"c":"foo"}
Содержится ли пара ключ-значение в JSON
SELECT '{"а": 1,"b":2}'::jsonb @> '{"b":2}'::jsonb
----- вернет true
SELECT '{"b":2}'::jsonb <@ '{"a":1, "b":2}'::jsonb
----- вернет true
Является ли строка ключем JSON
SELECT '{"a":1, "b":2}' ::jsonb ? 'b' -- вернет true
Является ли какой-либо элемент массива ключем JSON
SELECT '{"а":1, "b":2, "с":3}'::jsonb ?| array['b', 'с']
----- вернет true
Все элементы массива являются ключами JSON
SELECT '["a", "b"]'::jsonb ?& array['а', 'b']
----- вернет true
1 note · View note
garyck · 4 years ago
Text
Шпаргалка по Debian
Просмотр открытых портов:
netstat -pnltu
1 note · View note
garyck · 4 years ago
Text
Установка Docker на Debian
Обновить репозиторий и установить необходимые пакеты:
sudo apt-get update
sudo apt-get install \
ca-certificates \
curl \
gnupg \
lsb-release
Добавление официального GPG ключа
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
Добавление репозитория:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Непосредственная установка:
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
Проверка работы Докера:
sudo docker run hello-world
0 notes
garyck · 4 years ago
Text
Запуск скрипта node js в фоне
Для того чтобы скритпы nodejs не закрывались при закрытии консоли нужно настроить фоновую службу для этого скрипта
С правами root создать файл в папке /etc/systemd/system с названием app.service
[Unit]
Description=название
[Service]
ExecStart=/usr/bin/node /usr/bin/yarn run dev - команда
ExecStop=/bin/kill -INT $MAINPID
Restart=always
User=user -пользователь под которым нужно запустить скрипт
Group=user - группа
# Environment=PATH=/usr/bin:/usr/local/bin
# Environment=NODE_ENV=development
WorkingDirectory=рабочий каталог скрипта
[Install]
WantedBy=multi-user.targetuser
Команды для управления службами
Переинициировать службы (при изменении файлов служб) sudo systemctl daemon-reload
Состояние службы systemctl status app
Запустить службу sudo systemctl start app
Посмотреть журнал ошибок sudo journalctl -xe
1 note · View note
garyck · 4 years ago
Text
Команды Screen
screen -ls список всех сессий
screen -r <номер> - перейти в сессию с номером
screen -S <название> создать сессию с названием
screen -dmS <название> <команда> запустить новую сессию с командой
0 notes
garyck · 4 years ago
Text
Ошибка ERROR: [Errno 2] No such file or directory: "Что-то"
Если появилась ошибка запуска приложения в nodejs
Попробуйте следующее для Debian:
sudo apt remove cmdtest
sudo apt remove yarn
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt-get update
sudo apt-get install yarn -y
0 notes
garyck · 4 years ago
Text
Работа с GitHub
Система контроля версий Git
Для начала определим, что такое система контроля версий.
Так называют программу, которая позволяет хранить разные версии одного и того же документа, легко переключаться между ранними и поздними вариантами, вносить и отслеживать изменения.
Систем контроля версий много и все они работают по принципу компьютерной игры, где вы можете вернуться к месту сохранения, если что-то пошло не так.
Одна из самых популярных систем называется Git. Её отличие от других программ — отсутствие графической версии. Поэтому работа с Git ведётся через командную строку. В разных операционных системах свои программы для взаимодействия с Git.
В Windows их две: PowerShell и cmd.exe. В Ubuntu это Terminal. Самая популярная программа на macOS тоже называется Terminal. Если вам не подходит встроенная в систему программа для работы с командной строкой, вы можете поставить свою. Например, написанную на JavaScript программу Hyper, кото��ая работает на любой операционной системе. На Windows популярны программы Cmder и Git Bash, а на macOS — iTerm.
В мире разработки такие программы называют «терминал» или «консоль». А работает это так: мы вводим команду и получаем реакцию машины: сообщение об ошибке, запрос на подтверждение информации, результат выполненных действий.
Git — важный навык веб-разработчика
А лучший способ научиться программировать — профессия «React-разработчик». В программе три интенсива, прокачка навыков и оплачиваемая стажировка.
Устанавливаем Git
Если раньше вы не работали с Git, сперва его нужно установить. Способы зависят от операционной системы вашего компьютера.
Установка в Windows
Скачайте exe-файл инсталлятора с сайта Git и запустите его. Это Git для Windows, он называется msysGit. Установщик спросит добавлять ли в меню проводника возможность запуска файлов с помощью Git Bash (консольная версия) и GUI (графическая версия). Подтвердите действие, чтобы далее вести работу через консоль в Git Bash. Остальные пункты можно оставить по умолчанию.
Установка на macOS
Скачиваем Git со страницы проекта.
Запускаем загруженный файл.
Система может показать окно с ошибкой, где будет написано, что файл скачан с неавторизованного сайта и инсталлятор не может быть запущен. В таком случае нужно зайти в «Системные настройки» — «Безопасность» (Security and Privacy), в появившемся окне будет сообщение об ошибке и кнопка Open anyway (Всё равно открыть). Нажимаем.
Система покажет окно, уточняющее хотите ли вы запустить установку. Подтверждаем действие.
Установщик проведёт через все необходимые шаги.
Установка в Linux
Используйте обычный менеджер пакетов вашего дистрибутива. Откройте терминал и введите подходящие команды.
Если у вас 21 или более ранняя версия Fedora, используйте yum install git.
Для 22 и последующих версий Fedora вводите dnf install git.
Для дистрибутивов, основанных на Debian, например, Ubuntu, используйте apt-get: sudo apt-get install git.
Полный список команд для различных дистрибутивов можно посмотреть здесь.
Проверим, что Git установлен
После того, как все действия по установке завершены, убедимся, что Git появился в системе компьютера. Откройте терминал и введите git --version, должна появиться текущая версия программы на вашей машине. Эта проверка подходит для всех операционных систем.
Настройка Git
После того как Git появился на компьютере, нужно ввести свои данные, а именно имя и адрес электронной почты. Ваши действия в Git будут содержать эту информацию.
Откройте терминал и используйте следующую команду, чтобы добавить своё имя: git config --global user.name "ваше имя"
Для добавления почтового адреса вводите: git config --global user.email адрес
Обратите внимание, что в командах, указанных выше, есть опция --global. Это значит, что такие данные будут сохранены для всех ваших действий в Git и вводить их больше не надо. Если вы хотите менять эту информацию для разных проектов, то в директории проекта вводите эти же команды, только ��ез опции --global.
Регистрация на GitHub
Что такое GitHub?
GitHub — веб-сервис, который основан на системе Git. Это такая социальная сеть для разработчиков, которая помогает удобно вести коллективную разработку IT-проектов. Здесь можно публиковать и редактировать свой код, комментировать чужие наработки, следить за новостями других пользователей. Именно в GitHub работаем мы, команда Академии, и студенты интенсивов.
Чтобы начать работу с GitHub, нужно зарегистрироваться на сайте, если вы ещё этого не сделали. За дело.
Переходим на сайт GitHub.
Для начала регистрации:
Третий шаг — небольшой опрос от GitHub, который вы можете пройти, заполнив все поля и нажать Submit или пропустить, нажав skip this step.
После прохождения всех этапов на сайте, на указанный при регистрации ящик вам придёт письмо от GitHub. Откройте его и подтвердите свой почтовый адрес, нажав Verify email address (подтвердить электронный адрес) или скопируйте вспомогательную ссылку из письма и вставьте её в адресную строку браузера.
После верификации GitHub предложит создать новый репозиторий, организацию или узнать больше о GitHub. Этот пункт пока можно пропустить и перейти в профиль.
Нажимаем кнопку Sign up (зарегистрироваться), попадаем на страницу регистрации, где вводим обязательные данные: имя пользователя, адрес электронной почты и пароль. После заполнения полей проходим верификацию.
После заполнения данных и успешного прохождения верификации нажимаем на кнопку Select a plan.
Теперь у вас есть профиль на GitHub.
Устанавливаем SSH-ключи
Git установлен, профиль на GitHub создан. Осталось добавить SSH-ключ и можно приступать к работе с проектом.
Что такое SSH-ключ и зачем он нужен?
Чтобы работать со своего компьютера с GitHub, иметь доступ к проектам, хранящимся на сервисе, выполнять команды в консоли без постоянного подтверждения пароля, нужно пройти авторизацию у сервера. В этом помогают SSH-ключи.
Каждый SSH-ключ содержит пару: открытый (публичный) и закрытый (приватный) ключ. Открытый ключ отправляется на сервер, его можно не прятать от всех и не переживать, что кто-то его увидит и украдёт. Он бесполезен без своей пары — закрытого ключа. А вот закрытый ключ — секретная часть. Доступ к нему должен быть только у вас.
Вы отправляете какую-то информацию на сервер, где хранится ваш публичный ключ, сервер понимает, что вы это вы, то есть идентифицирует именно вас, и даёт вам какой-то ответ. И только вы можете расшифровать этот ответ, потому что только у вас есть подходящий закрытый ключ. Получается что-то вроде связки логин-пароль только намного безопасней. Ваш пароль кто-то может узнать или подобрать, а чтобы получить ваш приватный SSH-ключ, злоумышленнику придётся взломать ваш компьютер.
Чтобы пройти авторизацию по SSH-ключу, его надо сгенерировать или найти уже ранее созданный ключ на своём компьютере.
Сначала проверим, есть ли уже на компьютере ключ. По умолчанию SSH-ключи хранятся в каталоге ~/.ssh, поэтому нужно проверить содержимое этого каталога.
1. Открываем консоль.
2. Вводим
cd ~/.ssh
, чтобы перейти в нужный каталог.
Tumblr media
Используем
ls
, чтобы увидеть список всех файлов в каталоге.
Tumblr media
Ищем пару файлов с названиями вида имя и имя.pub. Обычно имя — id_rsa, id_dsa, id_ecdsa или id_ed25519. Файл с расширением .pub — ваш публичный ключ, а второй — ваш приватный, секретный ключ. Если таких файлов или даже каталога .ssh у вас нет, вы можете их сгенерировать. Для этого делаем следующее.
- Открываем консоль и вводим команду:
ssh-keygen -t rsa -b 4096 -C "[email protected]"
Указываем тот адрес электронной почты, который вводили при регистрации на GitHub.
Tumblr media
- Далее нужно указать расположение файла для сохранения ключа. Если вы не введёте путь до файла и просто нажмёте Enter, ключ сохранится в файле, указанном в скобках.
- Теперь нужно установить пароль к вашему ключу и дважды ввести его. Если вы не хотите вводить пароль каждый раз, когда используете ключ, пропустите этот шаг, нажав «Enter», и ничего не вводите.
Tumblr media
4. Добавляем ключ в
ssh-agent
(сгенерированный или уже существующий). Проверяем доступность ключа командой
eval "$(ssh-agent -s)"
и добавляем с помощью
ssh-add ~/.ssh/your_key_name
, где указываем верный путь до файла с ключом и его имя.
Tumblr media
Несколько важных примечаний:
- Если вы захотите переименовать ключ, могут возникнуть проблемы. Их можно решить, добавив в ~/.ssh/config связь ключа с доменом.
- Если у вас Windows и вы пользуетесь программой Cmder, возможны проблемы с командой eval "$(ssh-agent -s)". Может появиться такое сообщение об ошибке: «eval не является внутренней или внешней командой, исполняемой программой или пакетным файлом».
Если проблема осталась, рекомендуем работать в Git Bash
- Если у вас macOS Sierra версии 10.12.2 и выше, нужно изменить ваш ~/.ssh/config файл, чтобы автоматически загрузить ключи в ssh-agent и хранить пароли.
Host * AddKeysToAgent yes UseKeychain yes IdentityFile ~/.ssh/id_rsa
Вы можете добавить свой приватный ключ в
ssh-agent
и сохранить пароль к нему с помощью команды
ssh-add -K ~/.ssh/id_rsa
. Если у вашего ключа другое имя, не забудьте заменить
id_rsa
в команде на правильное название.
- Если у вас Linux, может понадобится переназначить для ~/.ssh права доступа командой chmod 700 ~/.ssh/
5. После того как создан ключ, его нужно добавить на GitHub. Для этого копируем его содержимое с помощью одной из следующих команд:
Если вы на Windows clip .
Для пользователей macOS pbcopy .
На Linux используйте sudo apt-get install xclip, чтобы установить необходимый для копирования пакет xclip, а затем введите xclip -sel clip . Или введите команду cat ~/.ssh/id_rsa.pub, контент документа появится прямо в консоли и вы сможете скопировать ключ оттуда.
6. Переходим на страницу для работы с ключами в вашем профиле на GitHub.
Tumblr media
Нажимаем кнопку New SSH key (новый SSH-ключ). Вводим имя ключа (можно придумать абсолютно любое) в поле Title (название), а в Key (ключ) вставляем сам ключ из буфера обмена. Теперь нажимаем Add SSH key (добавить SSH-ключ).
Если всё сделано верно, в списке появится новый ключ.
Tumblr media
Теперь, наконец-то, мы можем начать работу с самим проектом.
Работа с репозиториями
Для начала определим, что такое репозиторий
.
Это рабочая директория с вашим проектом. По сути, это та же папка с HTML, CSS, JavaScript и прочими файлами, что хранится у вас на компьютере, но находится на сервере GitHub. Поэтому вы можете работать с проектом удалённо на любой машине, не переживая, что какие-то из ваших файлов потеряются — все данные будут в репозитории при условии, что вы их туда отправите. Но об этом позже.
Если над проектом трудится команда разработчиков, как прави��о, создаётся общий репозиторий, в котором находится рабочая версия проекта (назовём его мастер-репозиторий). При этом каждый пользователь клонирует себе в профиль оригинальный репозиторий и работает именно с копией. Такая копия называется форком. Так как форк — ваша персональная версия мастер-репозитория, в нём вы можете пробовать разные решения, менять код и не бояться что-то сломать в основной версии проекта.
Как сделать форк мастер-репозитория?
Заходим в нужный репозиторий, нажимаем на «вилку» с надписью fork. Форк репозитория создан и находится в вашем профиле на GitHub.
Теперь нужно склонировать форк себе на компьютер, чтобы вести работу с кодом локально. Тут нам и пригодится SSH.
Открываем консоль, переходим в директорию, где хотим сохранить папку с проектом, и вводим команду:
git clone [email protected]:your-nickname/your-project.git
Если вы правильно настроили SSH-ключи, Git начнёт процесс копирования репозитория на ваш компьютер. Если вы видите ошибку, в которой написано Error: Permission denied (publickey), скорее всего, вы ошиблись где-то при выполнении инструкции по настройке SSH-ключа. Вернитесь на несколько абзацев ранее и попробуйте повторить процесс настройки.
Если вы не хотите вручную вводить адрес репозитория, вы можете зайти на страницу проекта, нажать зелёную кнопку Clone or download (клонировать или скачать), выбрать Clone with SSH (клонировать по SSH) и скопировать адрес, который находится в текстовом поле. Этот адрес вы можете вставить в команду git clone.
Кстати, если вы хотите, чтобы название папки с проектом у вас на компьютере отличалось от имени репозитория, можете дополнить команду клонирования, добавив в конце другое название:
git clone [email protected]:_your-nickname_/_your-project_.git folder_name
Теперь, на вашем компьютере, в папке your_project или в той, название которой вы указали самостоятельно, находится полная копия репозитория c GitHub.
Чтобы начать работу с проектом, надо оказаться в его директории. Для этого используем команду cd, после которой указываем название проекта на вашем компьютере: cd your-project
Tumblr media
Работу над проектом принято вести в ветках. В каждом репозитории есть как минимум одна ветка. Это основная ветка, которую создаёт сам Git, она называется master . Обычно в ней находится стабильная версия программы без ошибок. Если вы хотите исправить баг, добавить новую функциональность в проект, попробовать какую-то технологию, но не хотите сломать код в основной ветке, вы ответвляетесь из master и трудитесь в своей новой ветке. Здесь вы можете реализовывать свои идеи, не переживая, что рабочий код сломается. Каждая ветка — что-то вроде второстепенной дороги, которая затем снова соединяется с основной.
Создадим новую ветку. Открываем терминал, вводим команду git branch. Она показывает список веток, с которыми мы работаем в проекте, и выделяет текущую. Если мы находимся в master создаём новую ветку: git checkout -b имя-новой-ветки.
Tumblr media
Если текущая ветка не master, сначала переключимся в основную ветку: git checkout master. Мы делаем это, чтобы новая ветка содержала свежую, на момент создания, рабочую версию проекта.
Эта команда позволяет переключаться между существующими ветками в проекте, после git checkout надо указать название нужной ветки.
Tumblr media
Если вы ошиблись в названии, например, допустили опечатку, вы можете изменить название ветки с помощью команды: git branch -m старое-имя-ветки новое-имя-ветки.
После того как вы создали ветку, поработали в ней у себя локально — нужно сохранить результат, чтобы он не пропал и в итоге оказался в репозитории.
Если вы хотите сохранить изменения не во всех файлах, для начала можно ввести команду git status. Она покажет текущее состояние в вашей ветке, а именно список с названиями изменённых файлов, если они есть, и укажет на те, которые ожидают записи и сохранения (обычно они выделены красным цветом).
Tumblr media
Перед тем, как зафиксировать изменения отдельных файлов, нужно добавить файлы в набор этих изменений. Воспользуйтесь командой git add имя-файла. Если название очень длинное, вы можете начать его писать, затем нажать Tab и консоль сама предложит вам продолжение пути к файлу.
Если вы хотите сохранить все изменения разом, вводите git add -A.
Теперь мы можем сделать коммит, то есть зафиксировать все сохранённые изменения и дать им название. Это делается с помощью команды git commit -m "ваше сообщение". Текст сообщения должен быть лаконичным и в то же время сообщать о том, что делает коммит (внесённые изменения). Например, «добавляет имя наставника в Readme», «вводит функцию сортировки изображений», «правит ошибку в поиске городов на карте».
Tumblr media
Сохранения зафиксированы, всё? Они теперь в репозитории и видны коллегам? Пока нет. Те изменения, которые мы внесли и сохранили, пока локальны. Их нужно послать на GitHub.
Чтобы отправить свои изменения (коммиты) в репозиторий на GitHub, введите команду git push origin название-текущей-ветки, где origin означает репозиторий, который был склонирован на компьютер, то есть ваш форк.
Tumblr media
Теперь заходим на страницу нашего форка и создаём пулреквест, чтобы слить сво�� код с данными в мастер-репозитории. Что такое пулреквест? Это предложение изменить код в репозитории.
Любое предложение можно принять или отвергнуть. Так же и с пулреквестом. После его создания, он должен получить ревью и одобрение так называемого коллаборатора — пользователя GitHub, который имеет права администратора в мастер-репозитории. Им может быть ваш коллега-разработчик, техлид, наставник. Если к вашему коду нет вопросов, пулреквест принимается и изменения из вашей ветки попадают в master главного репозитория. Если в код нужно внести изменения, пулреквест отклоняется, и вам нужно снова пройти по цепочке локальные изменения — сохранение — коммит — пуш, только пулреквест заново делать не нужно. Если вы продолжаете вести работу в той же ветке и пулреквест ещё не принят, все ваши изменения автоматически добавятся в пулреквест, созданный из этой ветки после команды git push origin название-текущей-ветки.
Вы исправили код, наставник или техлид одобрил ваши правки и принял пулреквест. Теперь код в мастер-репозитории обновился, а в вашем форке нет, вы ведь не обновляли свою версию репозитория с тех пор, как клонировали её себе на компьютер. Приведём форк в актуальное состояние.
1. В локальном репозитории вводим команду git checkout master, переходим в master.
2. Теперь забираем (подтягиваем) изменения из ветки master мастер-репозитория git pull academy master. Academy здесь — сокращённое название мастер-репозитория, такое имя используется в проектах студентов Академии, вы можете выбрать любое другое название.
Tumblr media
Если консоль выдаёт ошибку и говорит, что не знает директории с таким именем, нужно добавить ссылку на этот репозиторий:
git remote add academy [email protected]:your-repo.git
Вместо academy указывайте своё название и оно закрепится за этим репозиторием.
3. Теперь отправьте изменения уже из своей ветки master в ваш форк на GitHub с помощью команды git push origin master.
Tumblr media
Готово, теперь форк и оригинальный репозиторий находятся в актуальном состоянии.
0 notes
garyck · 9 years ago
Text
Тестирование производительности сайтов
Решил собрать подборку инструментов для тестирования сайтов.
http://loadimpact.com - нагрузочные испытания сайта
https://developers.google.com/speed/pagespeed/insights/ - анализ производительности сайта
0 notes
garyck · 9 years ago
Text
Вывод команды Ping  со временем
Появилась необходимость сделать лог файл наблюдения доступности узла сети. Для этой цели вполне подходит команда ping. Но для того чтобы со строкой доступности узла было указано время поможет следующий скрипт:
ping 8.8.8.8 | while read pong; do echo "$(date): $pong"; done
0 notes
garyck · 10 years ago
Text
Включение ЧПУ в apache2
1. Для начала нужно включить поддержку .htaccess.
Для того, чтобы включить .htaccess в Apache2, надо отредактировать всего-лишь один файл. Этот файл лежит в /etc/apache2/sites-available и называется default или другой конфигурационный.
и исправляем:
AllowOverride None
на
AllowOverride All
2. Создаем файл .htaccess
# Кодировка сайта: AddDefaultCharset UTF-8 # Запрет на отображение содержимого каталога при отсутствии индексного файла(например, index.html) Options -Indexes # Правило для url # Включаем модуль RewriteEngine для создания единой точки входа RewriteEngine On # Правила для шаблон MVC # Чтобы не обрабатывать файлом index.php графические файлы, css. # js файлы, а позволять их скачивать браузеру на прямую RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d # Перенаправлять все запросы на index.php RewriteRule $ index.php [nocase,last]
3. Включаем mod_rewrite и перезагружаем сервер:
a2enmod rewrite /etc/init.d/apache2 restart
0 notes
garyck · 10 years ago
Text
После обновления Composer выдает Deprecation Notice
Ошибка
Deprecation Notice: Composer\Package\Version\VersionParser::parseLinks is deprecated. Use \Composer\Package\Loader\ArrayLoader::parseLinks() instead in phar:///home/user/site.ru/composer.phar/src/Composer/Package/Version/VersionParser.php:226
Решение (12:00 29 июля) 10:00 30 июля. Обновился плагин до 1.0.3, достаточно обновить плагин в режиме global:
php composer.phar global require "fxp/composer-asset-plugin:~1.0"
Старое решение
1. удаляем lock файл в папке проекта и папке global (~/.composer папка в корне с общими настройками composer) и папку vendor (можно просто её переименовать)
2. Чистим кэш
php composer.phar clear-cache
3. Обновляем плагин до версии "dev-master" (скоро добавят тэг https://github.com/francoispluchino/composer-asset...):
/opt/php5.6/bin/php -d memory_limit=-1 composer.phar global require "fxp/composer-asset-plugin:dev-master"
## или без лишних флагов:
php composer.phar global require "fxp/composer-asset-plugin:dev-master"
обязательно global require, тк при установке yii2 мы устанавливаем этот плагин как раз с global.
4. Ну и еще разок запускаем обновление
/opt/php5.6/bin/php -d memory_limit=-1 composer.phar update
готово
0 notes
garyck · 10 years ago
Text
Установка LAMP для ленивых в Ubuntu Server 14.04
В Ubuntu Server 14.04 LTS есть отличная команда, которая позволяет веб-мастерам совсем и навсегда облениться. Ставим LAMP в одну строку:
sudo apt-get install lamp-server^
Крышка в конце названия «пакета» — не опечатка.
Для совсем ленивых предлагаю такое комбо:
sudo apt-get -y update && sudo apt-get -y upgrade && sudo apt-get -y install lamp-server^ && sudo apt-get -y install phpmyadmin
Новчикам поясню:
Ключ -y для apt-get за вас отвечает согласием на установку и обновление пакетов.
Связка && между командами, запускает следующую, если предыдущая отработала без ошибок.
Для обеспечения элементарной безопасности (чтобы не забрутфорсили) я вам рекомендую сменить сразу дефолтный адрес phpMyAdmin. Для этого редактируйте файл: sudo nano /etc/apache2/conf-enabled/phpmyadmin.conf
В нём строку: Alias /phpmyadmin /usr/share/phpmyadmin
Замените на: Alias /secret /usr/share/phpmyadmin
Сохраните файл (в nano для этого достаточно нажать F2) и перезапустите Apache: sudo service apache2 restart
Теперь phpMyAdmin будет доступен по ссылке http://127.0.0.1/secret (где 127.0.0.1 — IP вашего сервера)
0 notes
garyck · 10 years ago
Text
Как настроить проводную сеть в андроиде
При установке операционной системы андроид на ноутбук, ПК или виртуальную машину, может понадобиться настроить проводную сеть.
Например, если в виртуальной машине сеть настроена как “Сетевой мост”.
Для установки андроида, я использовал сборку android-x86-4.0-r1-thinkpad.iso отсюда: http://www.android-x86.org/download
После установки и запуска андроид, настраиваем следующим ��бразом:
Запускаем терминал и в нем набираем:
su
И подтверждаем права суперпользователя. Тем самым начинаем работать в терминале под рутом.
Команда
netcfg
Показывает установленные сетевые устройства. И их статус (UP или DOWN). eth0 - это и есть проводная сетевая карта.
Теперь нужно назначить ей адрес:
ifconfig eth0 [IP-адрес] netmask [маска сети]
Добавляем шлюз:
route add default gw [IP-адрес шлюза] dev eth0
Для установки DNS следующая команда:
setprop net.dns1 8.8.8.8 setprop net.dns2 8.8.4.4
Вроде всё!
0 notes
garyck · 10 years ago
Text
Как сделать свою карту на D3js
Сегодня я расскажу вам, как с помощью JavaScript и d3 нарисовать карту, подобную моей.
Утилиты (Prerequisites)
Для начала работы нам понадобятся две утилиты ogr2ogr и topojson. ogr2ogr входит в состав GDAL — библиотеки и набора утилит для работы с гео‑данными. topojson — небольшая утилита, написанная на JavaScript и работающая на node.js.
Установить GDAL (и, соответственно, ogr2ogr) 
Под Linux тоже есть соответствующий пакет:
sudo apt-get install gdal-bin
Далее необходимо установить node.js:
sudo apt-get install nodejs 
Устанавливаем npm:
sudo apt-get install npm
Вторая утилита ставится через npm :
sudo npm install -g topojson
Всё, теперь можно приступать к работе.
Данные
Вся суть любой карты — это данные. Не будет данных, нечего будет рисовать. Я рекомендую данные Natural Earth из‑за их доступности и открытости. Итак, идём в раздел 1:10m, Cultural и скачиваем карту с делением по странам (первый раздел, Admin 0 — Countries, любая ссылка).
Скачали, распаковали. Теперь с этим добром нужно что‑то делать, данные‑то в формате Shapefile. Для преобразования данных в читаемый вид нам и понадобится ogr2ogr — утилита, которая преобразует данные из одного векторного формата в другой. У неё огромное количество различных параметров, но я облегчу вам задачу.
ogr2ogr -f GeoJSON countries.json ne_10m_admin_0_countries_lakes/ne_10m_admin_0_countries_lakes.shp
После вызова этой команды должен появиться файл countries.json, содержащий те же данные, но в формате GeoJSON. Размер файла, конечно, не маленький — 24 Мб. Но не стоит отчаиваться: для работы понадобится его более оптимизированный собрат — TopoJSON.
topojson -o world.json countries.json
Если во время выполнения скрипта выпало сообщение:
/usr/bin/env: node: Нет такого файла или каталога
или
/usr/bin/env: node: No such file or directory
Это связано с тем что некоторые дистрибутивы линукс включают node.js под именем nodejs. Поэтому нужно создать сначала создать ссылку:
ln -s /usr/bin/nodejs /usr/bin/node
После снова попробовать переконвертировать файл. В результате имеем файл размером 2.3 Мб, с ним и будем работать. Этот размер можно ещё значительно уменьшить, но об этом я расскажу чуть позже.
Первая картинка
Начнём с создания новой страницы:
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Map Tutorial 01</title> <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/normalize/3.0.1/normalize.min.css"/> <script src="http://d3js.org/d3.v3.min.js"></script> <script src="http://d3js.org/topojson.v1.min.js"></script> </head> <body> <script> // Здесь будет код </script> </body> </html>
Теперь можно открывать всё это в браузере. Подойдёт любой статический сервер. Например, в PhpStorm, который я использую, можно просто нажать на файл правой клавишей и выбрать «Открыть в браузере» — выбранный файл отобразится с помощью небольшого встроенного в IDE сервера.
Создаём элемент <svg> размером с окно, в котором и будет происходить вся отрисовка. Для этого заменяем комментарий на подходящий код:
var width = window.innerWidth; var height = window.innerHeight; var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height);
��та инструкция создаёт html‑элемент <svg>, добавляет его к <body> и прописывает подходящие размеры в атрибуты width и height.
Пришла пора загрузить данные. Дописываем в конец:
   d3.json("/js/world.json", function (error, world) {        if (error) {            console.log(error);            return;        }
       // Тут будет отображение    });
Я думаю, тут не надо ничего объяснять.
Теперь можно отобразить данные!
       svg.append("path")                .datum(topojson.feature(world, world.objects.countries))                .attr("d", d3.geo.path().projection(d3.geo.mercator()));
Красота!
Результат, Исходники
На самом деле это я быстро набросал, чтобы было что показать. Теперь будем постепенно менять, приводя к виду, который на самом деле хочется получить.
После каждого логического куска поста есть две ссылки: на результат, который должен был получиться, и на написанный мной код. Первые две можете наблюдать под картинкой чуть выше. Если вдруг что‑то не получается, всегда можно подсмотреть или даже скопировать мою версию.
Проекция
Пока не начинаешь рисовать карту, даже не задумываешься, какое огромное количество проекций придумали люди, чтобы покрасивее отобразить объёмную землю на плоской бумаге. Меркатор, Winkel Tripel, Aitoff, Dymaxion, проекция Гуда… Их десятки, если не сотни. В контексте d3 проекция — это просто функция, которая переводит географические координаты (широту и долготу) в координаты на экране.
На картинке выше используется Меркатор. Это можно увидеть и в коде.
Вынесем код создания проекции в самый верх и поместим проекцию в отдельную переменную, она нам ещё пригодится.
var projection = d3.geo.winkel3();
Код отрисовки карты чуть поменялся и стал ссылаться на новую переменную.
svg.append("path")        .datum(topojson.feature(world, world.objects.countries))        .attr("d", d3.geo.path().projection(projection));
Как, может быть, вы уже заметили, я заменил Меркатора на более аккуратную Winkel Tripel (именно эту проекцию использует National Geographic для своих изданий). К сожалению, проекция не входит в стандартную поставку d3, поэтому придётся подключить ещё отдельный плагин с её определением.
<script src="http://d3js.org/d3.geo.projection.v0.min.js"></script>
Обновляем страницу и смотрим на новую картинку.
Результат, Исходники
Страны и GeoJSON
Возвращаемся к данным. Помните, что мы преобразовали наши данные в компактный TopoJSON? Перед отрисовкой эти данные всё равно придётся преобразовать обратно в GeoJSON, для этого у нас и подключена библиотека TopoJSON, посмотрите в заголовке нашего html.
var countries = topojson.feature(world, world.objects.countries).features;
В переменной countries теперь содержится массив с описанием стран в формате GeoJSON. Нарисуем их с помощью раздельных элементов <path>, благо d3 позволяет сделать это быстро и просто.
Создаём группу (элемент <g>), которая очень пригодится нам в будущем. Это нужно вставить сразу после объявления переменной svg.
var g = svg.append('g');
Заменяем код, ответственный за рисование.
svg.selectAll('.country').data(countries).enter()        .append('path')        .attr('class', 'country')        .attr('d', path);
Если вы ещё не знаете, что делает enter c выборкой из selectAll, то быстренько сходите и восполните этот пробел.
Переменная path в последней строчке — это функция, которая переводит описание страны из GeoJSON в строку, подходящую для отображения в svg. Её можно объявить в самом верху, сразу после объявления проекции.
var path = d3.geo.path().projection(projection);
Обновляем страницу (Результат, Исходники). Теперь границы государств стали более различимыми. Сделаем их ещё более видимыми с помощью css. Добавим в заголовок страницы блок <style>:
<style>    .country {        fill: #ffffdd;        stroke: #226688;    } </style>
Результат, Исходники
Фон и сетка координат
Следующий этап. Подсветим водные пространства синим. Для этого добавляем сразу после создания группы элемент <path>, который будет отвечать за фон.
       g.append('path')                .datum({'type': 'Sphere'})                .attr('class', 'background')                .attr('d', path);
Добавим также стиль фона к нашему css вверху документа.
   .background {    fill: #ddeeff;    }
Результат, Исходники
Теперь добавим координатную сетку на фон.
g.append('path')        .datum(d3.geo.graticule().minorStep([5, 5]))        .attr('class', 'graticule')        .attr('d', path);
И стиль для сетки:
   .graticule {    fill: none;    stroke: #000;    stroke-opacity: .3;    stroke-dasharray: 3, 1; }
Результат, Исходники
И последний штрих — граница карты, просто для красоты. Создаётся точно так же, как и фон, разве что стиль другой.
       g.append('path')                .datum({'type': 'Sphere'})                .attr('class', 'graticule outline')                .attr('d', path);
Стиль:
       .graticule.outline {            stroke: #333;            stroke-opacity: 1;            stroke-width: 1.5px;            stroke-dasharray: initial;        }
Результат, Исходники
Масштабирование
Пришла пора добавить интерактива к карте. Но для начала разместим карту по центру и растянем на весь экран.
Для растягивания проекции нужно указать параметр scale, который по‑умолчанию равен 150. К сожалению, все соотношения меняются от проекции к проекции, поэтому просто посчитаем нужные параметры для нашей. Для этого в инспекторе браузера нужно глянуть ширину и высоту элемента path, соответствующего фону. В случае Winkel Triple ширина равна 772, а высота — 472.
Максимальное увеличение, при котором карта будет помещаться на экран, по горизонтали равно 150 / 772 * width, по вертикали — 150 / 472 * height. Выбираем меньшее из двух.
       var projection = d3.geo.winkel3()            .scale(Math.min(150 / 772 * width, 150 / 472 * height));
Перемещаем проекцию в центр:
       var projection = d3.geo.winkel3()                .scale(Math.min(150 / 772 * width, 150 / 472 * height))                .translate([width / 2, height / 2]);
Результат, Исходники.
Всё, теперь можно добавлять интерактив. Как и положено, в таких библиотеках уже много всего придумано и реализовано за вас, остаётся только вызвать нужную функцию в нужный момент.
Создаём объект behavior.zoom, который будет отвечать за отслеживание событий:
       var zoom = d3.behavior.zoom()                .scaleExtent([1, 60])                .size([width, height])                .on('zoom', onZoom);
Присоединяем созданный объект к нашему элементу <svg>:
       svg.selectAll('.country').data(countries).enter()                .append('path')                .attr('class', 'country')                .attr('d', path)                .call(zoom);
И пишем обработчик для события zoom.
function onZoom () { var t = d3.event.translate; var s = d3.event.scale; t[0] = Math.max(Math.min(t[0], 0), width * (1 - s)); t[1] = Math.max(Math.min(t[1], 0), height * (1 - s)); zoom.translate(t); g.style("stroke-width", 1 / s) .attr('transform', 'translate(' + t + ')scale(' + s + ')'); }
В d3 параметры события сохраняются в специальном объекте d3.event, в случае события zoom нас интересуют два параметра: translate — смещение карты и scale — текущее увеличение. После получения этих параметров мы накладываем ограничение на смещение, чтобы пользователь не мог сдвинуть карту дальше её границ. Затем мы записываем новое смещение обратно в объект zoom: без этого он будет продолжать считать, что текущее смещение другое и сообразно обрабатывать новые события от мыши. И последнее действие — применить новые параметры смещения и увеличения к карте: нужно же, чтобы картинка менялась соответственно нашим действиям.
Кстати, именно для правильной работы масштабирования мы и создавали элемент <g> выше. Атрибут transform не работает с элементом <svg>.
Результат, Исходники.
Дополнительные данные
Идём дальше. Добавим к нашей карте немножко больше данных. Я создавал карту посещённых стран и городов, о чём и буду рассказывать. Я думаю, некоторые идеи можно применить и для других целей и наборов данных.
Такие совсем специфические данные, как список посещённых стран, взять негде, их придётся создавать самостоятельно. Я для этих целей создал файл data.json в таком формате:
{ // Список стран "AUT": { // Код страны "name": "Австрия", // Название страны по-русски "color": "turquoise", // Цвет подсветки: blue, green, orange, pink, purple, red, turquoise, yellow "cities": [ // Список городов внутри страны { "name": "Вена", // Название города по-русски "lat": 48.216667, // Широта "lon": 16.373333 // Долгота }, { "name": "Грац", "lat": 47.066667, "lon": 15.433333 } ] }, ... }
Чтобы вам не заморачиваться с созданием собственного файла, я предлагаю пока воспользоваться моим, потом переделаете всё так, как нравится. Скачать файлик можно по этой ссылке.
Загружаем данные из data.json сразу после загрузки карты и добавляем правильный фон к странам.
   var visitedData = {};    d3.json("world.json", function (error, world) {        if (error) {            console.log(error);            return;        }
       d3.json("data.json", function (error, data) {            if (error) {                console.log(error);            } else {                visitedData = data;            }
           var countries = topojson.feature(world, world.objects.countries).features;            g.selectAll('.country').data(countries).enter()                    .append('path')                    .attr('class', 'country')                    .attr('d', path)                    .style('fill', function (d) {                        var color = visitedData[d.id] && visitedData[d.id].color;                        return color && COLORS[color] || '#ffffdd';                    });        });    });
В d3, если в методы attr и style вторым параметром передать функцию, то значения атрибутов и стилей соответственно будут браться из результатов вызова этой функции. Первым параметром передаётся значение элемента массива, ранее заданного с помощью метода data.
Остаётся добавить массив констант с вариантами цвета фона где‑нибудь в начале файла:
   var COLORS = {        'blue': '#a3cec5',        'green': '#d3e46f',        'orange': '#fdc663',        'pink': '#f3c1d3',        'purple': '#ceb5cf',        'red': '#fdaf6b',        'turquoise': '#aadb78',        'yellow': '#fae364'    };
Запускаем и видим, что ничего не поменялось (Результат, Исходники). На самом деле причина проста: в файле world.json нет информации о кодах стран. Ошибка исправляется передачей дополнительного параметра в вызов topojson. Перегенерировать world.json нужно такой командой:
topojson -o world.json --id-property ADM0_A3 countries.json
Результат, Исходники
Теперь можно нарисовать города. Для этого сразу после кода, ответственного за рисование стран, добавляем код для рисования городов:
// Собираем все города в один массив. for (var i in visitedData) { if (visitedData.hasOwnProperty(i) && visitedData[i].cities) { cities.push.apply(cities, visitedData[i].cities); } } // Рисуем города g.selectAll('.city').data(cities).enter() .append('path') .attr('class', 'city') .attr('d', function (d) { return path({ 'type': 'Point', 'coordinates': [d.lon, d.lat] }); });
Обратите внимание, что координаты в path передаются в формате [широта, долгота].
Не забываем в начале объявить массив cities:
var cities = [];
И добавить стиль для городов:
.city { fill: #dd3d30; }
Смотрим результат:
Результат, Исходники
Да, точки для городов хотелось бы сделать поменьше. Добавляем правило рисования точек в path:
var path = d3.geo.path().projection(projection).pointRadius(1);
А ещё неплохо было бы сделать так, чтобы размер точек менялся с масштабом. Значит, добавляем код в конец функции onZoom.
path.pointRadius(Math.max(1/4, 1/s)); g.selectAll('.city') .attr('d', function(d) { return path({ 'type': 'Point', 'coordinates': [d.lon, d.lat] }) });
Результат, Исходники.
Подсветка названий
Теперь добавим подпись для объектов при наведении мышкой. Для этого сначала создаём в DOM элемент <div> с классом tooltip.
var tooltip = d3.select('body').append('div') .attr('class', 'tooltip') .style('display', 'none');
И создаём соответствующий ему стиль.
.tooltip { color: #222; background: #fff; padding: .5em; text-shadow: #f5f5f5 0 1px 0; border-radius: 2px; box-shadow: 0px 0px 2px 0px #a6a6a6; opacity: 0.9; position: absolute; }
Осталось написать обработчики событий мыши mousemove и mouseout. Для этого в операцию создания стран добавляем новые инструкции (новый код начинается с вызова метода on).
g.selectAll('.country').data(countries).enter() .append('path') .attr('class', 'country') .attr('d', path) .style('fill', function (d) { var color = visitedData[d.id] && visitedData[d.id].color; return color && COLORS[color] || '#ffffdd'; }) .on('mousemove', function (d) { var mouse = d3.mouse(svg.node()); var name = visitedData[d.id] && visitedData[d.id].name; if (!name) { return; } tooltip.style("display", "block") .style("left", mouse[0] + "px") .style("top", mouse[1] + "px") .html(name); }) .on('mouseout', function () { tooltip.style('display', 'none'); });
Из‑за того, что метод on вызван после вызова enter, события вешаются на каждый элемент <path> в отдельности, а в параметры передаётся соответствующий элемент из массива countries.
Метод d3.mouse возвращает текущие координаты мыши относительно контейнера, переданного в параметрах. В нашем случае это элемент <svg>. Дальше все просто: записываем в tooltip нужное содержимое и устанавливаем стили left, top и display.
В обработчике события mouseout прячем наш элемент с подписью. И всё работает как надо!
Добавим аналогичный код для отображения подписей к городам.
g.selectAll('.city').data(cities).enter() .append('path') .attr('class', 'city') .attr('d', function (d) { return path({ 'type': 'Point', 'coordinates': [d.lon, d.lat] }); }) .on('mousemove', function (d) { var mouse = d3.mouse(svg.node()); tooltip.style("display", "block") .style("left", mouse[0] + "px") .style("top", mouse[1] + "px") .html(d.name); }) .on('mouseout', function () { tooltip.style('display', 'none'); });
Тут всё абсолютно аналогично.
Результат, Исходники.
Исправление ошибок подсветки
Некоторые из вас, должно быть, заметили, что, например, Франция имеет территорию в Южной Америке, которая тоже подсвечивается. А от этого хочется избавиться, ведь нас там не было. Чтобы получить правильный результат, можно воспользоваться другим набором данных с Natural Earth. Снова идём в раздел 1:10m, Cultural и скачиваем карту с делением по subunits (Admin 0 — Details, Download map subunits).
Если мы просто заменим файл с исходными данным, то быстро заметим, что кроме Франции изменениям подверглись ещё несколько стран. Например, Бельгия оказалась разделена на три части: Фландрию, Валлонию и Брюссель, да и на Великобритании тоже появились границы между Англией, Шотландией и Уэльсом. Получается, чтобы получить желаемый результат, придётся составить карту из двух источников.
Возьмём Францию из ne_10m_admin_0_map_subunits. Обратите внимание на параметр -where, который накладывает нужные ограничения на выборку.
ogr2ogr -f GeoJSON subunits.json -where "ADM0_A3 = 'FRA'" ne_10m_admin_0_map_subunits/ne_10m_admin_0_map_subunits.shp
Вторая часть выборки:
ogr2ogr -f GeoJSON countries.json -where "ADM0_A3 != 'FRA'" ne_10m_admin_0_countries_lakes/ne_10m_admin_0_countries_lakes.shp
Теперь собираем это всё в один TopoJSON‑файл.
topojson -o world.json --id-property ADM_A3,SU_A3 -- countries.json subunits.json
Обратите внимание на то, как изменился вызов topojson, особенно параметр id-property. Все дело в том, что атрибут ADM_A3 содержит код страны, то есть у всех частей Франции код будет один и тот же. Поэтому для неё нужен другой атрибут в качестве идентификатора. Атрибуты в параметре id-property берутся в обратном порядке: сначала утилита пытается взять SU_A3, а в случае, если его нет, берет предыдущий, то есть ADM_A3.
Теперь для правильной отрисовки нужно добавить в массив countries новые элементы.
var countries = topojson.feature(world, world.objects.countries).features; countries.push.apply(countries, topojson.feature(world, world.objects.subunits).features);
Конструкция push.apply добавляет все элементы одного массива в другой. Более подробно про this, call и apply можно почитать в моей старой статье про ООП в JavaScript (раздел «Ключевое слово this»).
Осталось исправить в нашем файле с данными код Франции (новый код — «FXX») и наслаждаться результатом.
Результат, Исходники
Разбиение стран на регионы
Следующее пожелание: крупные страны, например, США и Россию, поделить на штаты и субъекты соответственно. Для этого нам понадобится новый источник данных. Снова идём на привычный адрес и скачиваем файл из раздела Admin 1 — States, Provinces.
Пересобираем файлы, не забыв предварительно удалить старые (org2org отказывается перезаписывать файлы, если вы ещё не заметили).
ogr2ogr -f GeoJSON subunits.json -where "ADM0_A3 = 'FRA'" ne_10m_admin_0_map_subunits/ne_10m_admin_0_map_subunits.shp ogr2ogr -f GeoJSON countries.json -where "ADM0_A3 != 'FRA' and ADM0_A3 != 'RUS' and ADM0_A3 != 'USA'" ne_10m_admin_0_countries_lakes/ne_10m_admin_0_countries_lakes.shp ogr2ogr -f GeoJSON regions.json -where "ADM0_A3 = 'RUS' or ADM0_A3 = 'USA'" ne_10m_admin_1_states_provinces_lakes/ne_10m_admin_1_states_provinces_lakes.shp topojson -o world.json --id-property ADM_A3,SU_A3,adm1_code -- countries.json subunits.json regions.json
Так же как и раньше, добавляем ��овые данные для рисования в массив countries.
var countries = topojson.feature(world, world.objects.countries).features; countries.push.apply(countries, topojson.feature(world, world.objects.subunits).features); countries.push.apply(countries, topojson.feature(world, world.objects.regions).features);
Вообще говоря, подсветку штатов и субъектов я писал отдельно, но можно просто добавить нужные идентификаторы в файл data.json.
Результат, Исходники
Атрибуты
В файлах, скачанных с Natural Earth, есть множество дополнительных данных, не только форма границ и код страны. Большая часть этих данных лежит в файле .dbf, который представляет собой файл базы данных dBase. И если у вас есть просмотрщик для этого формата, то можете смело его открывать. Если же нет, то можно воспользоваться Online‑конвертером из dbf в csv. Я использовал именно этот способ. После конвертации сsv‑файл можно открыть LibreOffice или же Microsoft Excel.
ogr2ogr тоже копирует все данные из файлов атрибутов внутрь результирующего файла, а topojson может копировать некоторые необходимые атрибуты в файл TopoJSON. Вот таким образом можно добавить атрибут NAME, который содержит английское название объекта:
topojson -o world.json --id-property ADM_A3,SU_A3,adm1_code --properties name,NAME -- countries.json subunits.json regions.json
Теперь можно использовать значение поля, например, для отображения названий непосещённых стран. Вот эту строчку нужно заменить в обработчике события mousemove для стран:
var name = visitedData[d.id] && visitedData[d.id].name || d.properties.name || d.properties.NAME;
Результат, Исходники.
Уменьшение размера файла с картой
Последний нерешенный вопрос: размер файла с картой. После всех наших манипуляций он стал весить 2.6 Мб, что, согласитесь, несколько многовато. topojson предоставляет несколько параметров для оптимизации. Один из них так и называется — simplify. Для получения оптимального результата придётся, конечно, немного поэкспериментировать с величиной, в нашем же случае вполне подойдёт 1e-6.
topojson -o world.json --id-property ADM_A3,SU_A3,adm1_code --properties name,NAME --simplify 1e-6 -- countries.json subunits.json regions.json
Получившийся файл имеет размер 444 Кб и всё ещё приемлемую детализацию.
Результат, Исходники.
Благодарности
Спасибо Mike Bostock за такую прекрасную библиотеку. И отдельное спасибо ему же за прекрасные записи в блоге, некоторые идеи из которых перекочевали в этот пост.
Спасибо всем тем, кто дочитал до конца. Надеюсь, этот пост поможет вам.
0 notes
garyck · 10 years ago
Text
Избавляемся от кракозябров
Отличная статья на хабре, о том как распознять кракозябры
Tumblr media
1 note · View note