Нормализация баз данных - это процесс организации данных в базе данных для минимизации избыточности данных и обеспечения их целостности. Цель нормализации - структурировать таблицы таким образом, чтобы устранить аномалии обновления, вставки и удаления данных. Нормализация достигается путем разбиения больших таблиц на более мелкие, связанных между собой отношениями, что упрощает управление данными и делает их более логически связанными.
Нормализация позволяет минимизировать дублирование данных, что экономит пространство и упрощает управление базой данных.
Нормализация помогает поддерживать целостность данных, обеспечивая правильное и единообразное хранение данных.
Разделение данных на логические таблицы делает структуру базы данных более понятной и удобной для использования.
Нормализация предотвращает возникновение аномалий при обновлении, вставке и удалении данных.
Удаление повторяющихся групп в таблице. Каждый столбец должен содержать только атомарные (неделимые) значения. Все записи в таблице должны быть уникальными.
Таблица должна быть в 1NF. Удаление частичной функциональной зависимости: каждый неключевой атрибут должен быть полностью зависим от первичного ключа.
Таблица должна быть в 2NF. Удаление транзитивной зависимости: все неключевые атрибуты должны быть напрямую зависимы от первичного ключа, а не от других неключевых атрибутов.
Усиление 3NF: каждая детерминанта должна быть кандидатом на ключ, что означает, что в любой нетривиальной функциональной зависимости X -> Y, X должно быть суперключом.
Таблица должна быть в BCNF. Устранение многозначных зависимостей: таблица не должна содержать многозначных зависимостей, когда один атрибут зависит от нескольких значений другого атрибута.
Таблица должна быть в 4NF. Устранение соединительных зависимостей: данные должны быть разбиты так, чтобы каждая зависимость сохранялась.
Если у вас есть таблица с повторяющимися группами, такими как несколько телефонных номеров для одного клиента, вы создаете отдельную таблицу для телефонов и связываете ее с таблицей клиентов.
Если у вас есть таблица заказов с колонками "номер заказа", "название товара" и "цена товара", вы можете создать отдельные таблицы для заказов и товаров, чтобы цена товара зависела только от товара, а не от комбинации заказа и товара.
Если у вас есть таблица сотрудников с колонками "идентификатор сотрудника", "название отдела" и "имя начальника отдела", вы можете создать отдельные таблицы для сотрудников и отделов, чтобы имя начальника отдела зависело только от отдела, а не от сотрудника.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Один из основных принципов объектно-ориентированного программирования (ООП), наряду с наследованием и полиморфизмом. Смысл инкапсуляции заключается в объединении данных и методов, работающих с этими данными, в одном объекте, а также в ограничении доступа к этим данным из внешнего мира.
В инкапсуляции данные (свойства) объекта скрываются от внешнего доступа и защищаются от некорректных изменений. Это достигается путем использования модификаторов доступа (например,
private, protected, public).Вместо прямого доступа к данным, предоставляются методы (геттеры и сеттеры) для чтения и изменения значений свойств. Это позволяет контролировать, каким образом данные могут быть изменены или получены.
Инкапсуляция помогает защитить внутреннее состояние объекта от некорректных или неожиданных изменений, обеспечивая целостность данных и уменьшая вероятность ошибок.
На Java
public class Person {
private String name;
private int age;
// Конструктор
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// Геттер для имени
public String getName() {
return name;
}
// Сеттер для имени
public void setName(String name) {
this.name = name;
}
// Геттер для возраста
public int getAge() {
return age;
}
// Сеттер для возраста
public void setAge(int age) {
if (age > 0) {
this.age = age;
} else {
System.out.println("Возраст должен быть положительным числом.");
}
}
}На Python
class Person:
def __init__(self, name, age):
self._name = name
self._age = age
# Геттер для имени
@property
def name(self):
return self._name
# Сеттер для имени
@name.setter
def name(self, name):
self._name = name
# Геттер для возраста
@property
def age(self):
return self._age
# Сеттер для возраста
@age.setter
def age(self, age):
if age > 0:
self._age = age
else:
print("Возраст должен быть положительным числом.")
# Пример использования
person = Person("John", 30)
print(person.name) # John
person.age = -5 # Возраст должен быть положительным числом.
print(person.age) # 30
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Это два популярных метода управления проектами и процессами, используемых в Agile-разработке. Оба они помогают командам улучшать производительность и управление работой, но имеют различные подходы и принципы. Вот основные различия между Scrum и Kanban:
Фиксированные спринты: Работа делится на временные интервалы, называемые спринтами, обычно длительностью 2-4 недели.
Роли: В Scrum определены конкретные роли, такие как Scrum-мастер, Product Owner и команда разработки.
Планирование спринта: Каждому спринту предшествует планирование, где команда определяет, какие задачи будут выполнены.
Ежедневные Scrum-встречи: Короткие ежедневные встречи (Stand-ups) для обсуждения прогресса, препятствий и планов на день.
Ретроспектива спринта: В конце каждого спринта команда анализирует, что прошло хорошо, что можно улучшить, и как это сделать.
Product Backlog: Список всех задач и требований для продукта.
Sprint Backlog: Список задач, выбранных для выполнения в текущем спринте.
Burn-down Chart: График, показывающий оставшееся количество работы в спринте.
Изменения в задачах не допускаются после начала спринта. Все задачи должны быть зафиксированы до начала спринта.
Непрерывный поток работы: Kanban не имеет фиксированных временных интервалов или спринтов. Работа выполняется непрерывно.
Роли: В Kanban нет строгих определений ролей. Команда может включать любые роли по мере необходимости.
Визуализация работы: Kanban использует доску с колонками для визуализации рабочего процесса (например, "To Do", "In Progress", "Done").
Лимиты на количество задач в работе (WIP): Ограничивает количество задач, которые могут находиться в определенных колонках одновременно, чтобы предотвратить перегрузку и улучшить поток работы.
Kanban-доска: Основной инструмент для визуализации работы и контроля за её состоянием.
Карточки задач: Представляют отдельные задачи на Kanban-доске.
Изменения допускаются в любой момент времени. Задачи могут добавляться, изменяться и удаляться по мере необходимости.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Объектно-ориентированное программирование (ООП) базируется на нескольких ключевых принципах, которые помогают создавать гибкие, понятные и легко поддерживаемые программы.
Абстракция заключается в выделении значимых характеристик объекта и игнорировании незначимых. Это позволяет создавать упрощенные модели реальных объектов.
Инкапсуляция скрывает внутренние детали объекта и позволяет взаимодействовать с объектом только через определенные методы. Это защищает данные от некорректного использования и облегчает изменение и поддержку кода.
Наследование позволяет создавать новые классы на основе существующих. Новый класс (наследник) получает все свойства и методы родительского класса и может добавлять новые или изменять существующие.
Полиморфизм позволяет объектам разных классов обрабатывать запросы одинаковым образом. Это достигается через переопределение методов в наследуемых классах и интерфейсы.
Композиция предполагает создание объектов других классов внутри данного класса. Это позволяет использовать функциональность существующих классов, не создавая зависимостей через наследование.
Агрегация - это специальный вид композиции, который позволяет одному объекту быть частью другого с возможностью существования вне этого объекта. Агрегация описывает "имеет" отношения.
Принципы ООП позволяют создавать более понятный и структурированный код.
Наследование и полиморфизм способствуют использованию уже написанных классов в новых контекстах.
Инкапсуляция и абстракция делают код легче в сопровождении и модификации.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
В контексте CAP-теоремы(Consistency, Availability, Partition Tolerance) системы обычно делят на три группы: CP (Consistency + Partition Tolerance), AP (Availability + Partition Tolerance) и CA (Consistency + Availability).
Системы, которые обеспечивают согласованность данных и устойчивость к разделению сети, но могут временно отказаться от доступности при возникновении сетевых сбоев. Такие системы при сетевом разделении блокируют часть данных или операций, чтобы сохранить согласованное состояние.
Оба эти хранилища данных поддерживают согласованность при сетевых сбоях, но могут ограничивать доступность данных, блокируя операции до восстановления связи.
Система координации распределённых приложений, обеспечивающая согласованность, но жертвующая доступностью в случае сетевых проблем. Она часто используется для управления конфигурацией и синхронизацией данных.
Системы, которые фокусируются на доступности и устойчивости к разделению сети, но допускают временную неидеальную согласованность данных (например, данные могут быть не сразу синхронизированы между репликами).
Эта система обеспечивает доступность и устойчивость к разделению сети, но может допускать задержки в синхронизации данных между узлами.
Поддерживает доступность и устойчивость к разделению сети, за счёт возможного отклонения в согласованности. DynamoDB был разработан Amazon для обеспечения высокой доступности даже в условиях сбоя сети.
Распределённое хранилище, оптимизированное для доступности и устойчивости к разделениям сети. Оно допускает временные рассогласования данных, которые разрешаются позже.
Системы, обеспечивающие согласованность и доступность данных, но не гарантирующие устойчивости к разделению сети. В реальных распределённых системах подобный подход встречается редко, так как любая сеть может столкнуться с разделением, что нарушит работу.
Например, PostgreSQL или MySQL в традиционной конфигурации, работающей на одном сервере без распределения данных. Они поддерживают согласованность и доступность, так как нет сетевого разделения.
Такие системы, как Redis, при отсутствии распределённой конфигурации и работе в пределах одного узла, могут обеспечить согласованность и доступность.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
В PostgreSQL можно использовать различные методы для блокировки конкретных полей или строк таблицы, чтобы предотвратить их изменение или обеспечить управление конкурентным доступом к данным. Наиболее распространенные способы включают использование транзакционных блокировок и политик доступа.
PostgreSQL поддерживает блокировки уровня строки с помощью команд
SELECT FOR UPDATE и SELECT FOR SHARE. Эти команды позволяют заблокировать конкретные строки для изменения другими транзакциями, пока текущая транзакция не завершится.SELECT FOR UPDATE:BEGIN; -- Начало транзакции
-- Выбираем и блокируем строки для обновления
SELECT * FROM my_table WHERE id = 1 FOR UPDATE;
-- Выполняем необходимые операции
UPDATE my_table SET field = 'new_value' WHERE id = 1;
COMMIT; -- Завершение транзакции
SELECT FOR SHARE:BEGIN; -- Начало транзакции
-- Выбираем и блокируем строки для чтения
SELECT * FROM my_table WHERE id = 1 FOR SHARE;
-- Выполняем необходимые операции
-- Изменение данных будет заблокировано для других транзакций
-- Однако, можно выполнять SELECT
COMMIT; -- Завершение транзакции
Политики безопасности на уровне строк позволяют определить, кто и при каких условиях может видеть или изменять данные в таблице. Это обеспечивается с помощью функций и политик безопасности.
-- Включаем безопасность на уровне строк для таблицы
ALTER TABLE my_table ENABLE ROW LEVEL SECURITY;
-- Создаем роль, которая будет иметь доступ
CREATE ROLE limited_role;
-- Создаем политику, которая позволяет только чтение данных
CREATE POLICY read_only_policy ON my_table
FOR SELECT
USING (true); -- Условие для выполнения SELECT
-- Применяем политику для роли limited_role
GRANT SELECT ON my_table TO limited_role;
Триггеры позволяют автоматически выполнять определенные действия перед или после операции
INSERT, UPDATE, DELETE. Можно создать триггер, который будет блокировать изменение конкретных полей.CREATE OR REPLACE FUNCTION prevent_update()
RETURNS TRIGGER AS $$
BEGIN
IF NEW.field IS DISTINCT FROM OLD.field THEN
RAISE EXCEPTION 'Field "field" cannot be updated';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Применяем триггер к таблице
CREATE TRIGGER prevent_update_trigger
BEFORE UPDATE ON my_table
FOR EACH ROW
EXECUTE FUNCTION prevent_update();
Ограничения на уровне столбца могут использоваться для ограничения возможных значений или для создания выражений, которые должны быть выполнены для выполнения изменения.
ALTER TABLE my_table
ADD CONSTRAINT field_check CHECK (field IS NOT NULL);
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Celery поддерживает различные брокеры сообщений, включая RabbitMQ и Redis, для управления очередями задач.
Позволяет запускать длительные операции в фоновом режиме, освобождая основной поток выполнения приложения для других задач.
Поддержка периодических и плановых заданий, что позволяет автоматизировать повторяющиеся процессы.
Способен управлять задачами в распределенной системе, используя несколько рабочих узлов (workers) для параллельного выполнения задач.
Легко масштабируется, добавляя больше рабочих узлов для увеличения производительности.
Отправка электронной почты: Асинхронная отправка писем для улучшения производительности веб-приложений.
Обработка данных: Включает такие задачи, как анализ данных, обработка изображений или видео, преобразование форматов и другие ресурсоемкие операции.
Взаимодействие с API: Выполнение запросов к внешним API, которое может быть долгим или неэффективным при синхронном выполнении.
Обновление данных: Регулярное обновление кэшей, индексов поиска или других данных в базе данных.
Мониторинг и сбор метрик: Периодический сбор и обработка метрик для мониторинга состояния системы.
Очистка данных: Периодическая очистка устаревших или временных данных из базы данных.
Уведомления в реальном времени: Отправка уведомлений пользователям через различные каналы (email, SMS, push-уведомления).
Событийное оповещение: Реагирование на события и триггеры, такие как изменения в базе данных или действия пользователя.
Параллельная обработка данных: Выполнение параллельных вычислений для обработки больших объемов данных.
Машинное обучение: Асинхронное обучение моделей и выполнение предсказаний на больших наборах данных.
Веб-скрейпинг: Асинхронный сбор данных с веб-сайтов для агрегации или анализа.
Интеграция данных: Асинхронная интеграция данных из различных источников и API.
Улучшение производительности веб-приложений за счет выполнения долгих операций в фоне.
Обработка заказов, обновление статусов заказов и управление инвентарем в фоновом режиме.
Обработка пользовательских данных, отправка уведомлений и обновление лент новостей.
Выполнение сложных вычислений и обработка больших объемов данных в распределенной среде.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Это легкий формат обмена данными, который легко читается и пишется человеком, а также легко парсится и генерируется компьютером. Он используется для представления структурированных данных в текстовом формате и основан на подмножестве языка программирования JavaScript, но независим от него. JSON часто используется для передачи данных между сервером и веб-приложением в формате, который легко обрабатывается.
JSON имеет простой и понятный синтаксис, состоящий из двух основных структур: коллекций пар "ключ-значение" (объектов) и упорядоченных списков значений (массивов). Это делает его легким для понимания и работы как для людей, так и для машин.
В отличие от более сложных форматов, таких как XML, JSON занимает меньше места благодаря лаконичному синтаксису, что делает его идеальным для передачи данных по сети, особенно в веб-приложениях.
Хотя JSON основан на синтаксисе JavaScript, он поддерживается практически всеми языками программирования. В большинстве современных языков существуют библиотеки для парсинга и генерации JSON, что облегчает его интеграцию в различные системы.
JSON форматы легко читаются человеком благодаря своей структурированности и использованию простой текстовой нотации.
Представляют собой коллекции пар "ключ-значение", заключенные в фигурные скобки
{}. Ключи являются строками, а значения могут быть любыми допустимыми типами данных JSON (строки, числа, массивы, объекты, логические значения, null). {
"name": "John",
"age": 30,
"isStudent": false,
"address": {
"street": "123 Main St",
"city": "Anytown"
},
"courses": ["Math", "Science", "History"]
}Представляют собой упорядоченные списки значений, заключенные в квадратные скобки
[]. Значения могут быть любого типа данных JSON.["apple", "banana", "cherry"]
Включают строки, числа, логические значения (
true или false), и null. {
"stringExample": "Hello, World!",
"numberExample": 42,
"booleanExample": true,
"nullExample": null
}
JSON широко используется в веб-разработке для обмена данными между клиентскими приложениями и сервером через HTTP-запросы, обычно с использованием методов
GET или POST.JSON используется для хранения конфигурационных настроек в различных приложениях, поскольку его структура легко читаема и редактируема.
В некоторых базах данных, таких как MongoDB, JSON используется как формат для хранения документов.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Предполагает, что одновременно существуют две версии приложения: старая (синяя) и новая (зелёная). База данных при этом используется общая. Во время переключения трафика от синей версии к зелёной возникают потенциальные сложности, связанные с изменением структуры данных или логики работы с ними.
Если новая версия приложения требует изменений в структуре базы данных (например, добавление колонок, изменение типов данных или удаление полей), старая версия приложения может стать несовместимой с новой схемой.
Если новая версия изменяет способ обработки или хранения данных, это может вызвать проблемы при переключении трафика обратно на старую версию (например, в случае отката).
Выполнение миграции данных может занять время и потребовать блокировки таблиц, что может привести к снижению производительности или временному недоступности приложения.
Если переключение на новую версию произошло, но затем потребовался откат, структура или данные, изменённые новой версией, могут быть несовместимы со старой версией.
Изменения в индексации или структуре таблиц могут привести к временной деградации производительности базы данных, что затронет обе версии приложения.
Если новая версия меняет логику транзакций или порядок операций над данными, это может вызвать несогласованность в данных при выполнении параллельных операций обеими версиями.
Сначала добавить новые поля или таблицы, не удаляя старые. Убедиться, что новая версия поддерживает как старую, так и новую схему. Удалить устаревшие элементы только после полного перехода.
Обеспечить, чтобы новая версия приложения могла работать со старой схемой, а старая версия — с новой (на ограниченное время).
Тщательно тестировать миграции на копии данных в условиях, максимально близких к боевым.
Сначала внести изменения в базу данных, совместимые с обеими версиями. Затем задеплоить новую версию. Удалить устаревшие элементы только после убедительности в стабильности.
Использовать фичи-флаги, чтобы включать или отключать новую функциональность, связанной с изменениями в БД, без полной смены версии.
Выполнять резервное копирование базы данных перед началом миграции. Использовать мониторинг для раннего обнаружения проблем с производительностью или данными.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Это метод горизонтального разбиения базы данных на более мелкие, более управляемые сегменты, называемые шардов (shards). Каждый шард является независимой базой данных, содержащей подмножество всех данных. Шардирование используется для повышения производительности и масштабируемости базы данных, особенно при работе с большими объемами данных и высокими нагрузками.
Шардирование распределяет строки таблицы по нескольким базам данных, а не делит таблицы на части. Это позволяет уменьшить нагрузку на одну базу данных и распределить её между несколькими серверами.
Каждый шард является автономной базой данных и может находиться на отдельном сервере. Это позволяет шардированным системам эффективно масштабироваться, добавляя новые сервера для хранения и обработки данных.
Ключ шардирования (shard key) используется для определения, в каком шарде будут храниться данные. Выбор правильного ключа шардирования имеет решающее значение для равномерного распределения данных и нагрузки.
Шардирование позволяет горизонтально масштабировать базу данных, добавляя новые шардовые серверы по мере роста объема данных и нагрузки.
Распределение данных между несколькими серверами уменьшает нагрузку на каждый сервер, что может улучшить производительность запросов и операций записи.
Шардирование может повысить устойчивость системы к отказам, так как сбой одного шарда не влияет на доступность остальных.
Меньшие по объему базы данных (шарды) легче управлять, бэкапить и восстанавливать по сравнению с одной большой базой данных.
Настройка и управление шардированной базой данных сложнее, чем управление одной большой базой данных. Это требует дополнительного усилия для настройки и мониторинга.
Транзакции, охватывающие несколько шардов, становятся сложнее и могут требовать использования распределенных транзакционных механизмов, что может негативно сказаться на производительности.
Некоторые запросы, особенно те, которые требуют объединения данных из разных шардов, становятся сложнее и могут требовать дополнительной логики на уровне приложения.
Неправильный выбор ключа шардирования может привести к неравномерному распределению данных, где одни шарды перегружены, а другие остаются недозагруженными.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Media is too big
VIEW IN TELEGRAM
На программиста, тестировщика, аналитика, проджекта и другие IT профы.
Есть собесы от ведущих компаний: Сбер, Яндекс, ВТБ, Тинькофф, Озон, Wildberries и т.д.
🎯 Переходи по ссылке и присоединяйся к базе, чтобы прокачать свои шансы на успешное трудоустройство!
Please open Telegram to view this post
VIEW IN TELEGRAM
XSS (Cross-Site Scripting) — это тип атаки на веб-приложения, при котором злоумышленник внедряет вредоносный скрипт (обычно JavaScript) в веб-страницу, которую просматривает пользователь. Это позволяет атакующему выполнять произвольный код в контексте браузера жертвы, что может привести к краже данных, угону сессий или изменению содержимого страницы.
Вредоносный код сохраняется в базе данных или другом постоянном хранилище. Например, пользователь вводит в комментарий
<script>...</script>, который сохраняется в БД и выполняется при просмотре комментариев. Вредоносный код передаётся в запросе и немедленно отображается без обработки. Например, если строка запроса
?search=<script>alert('XSS')</script> отображается на странице без фильтрации, скрипт выполнится. Возникает, когда JavaScript на клиенте изменяет DOM, используя входные данные, не проверяя их безопасность. Например, если код
document.write(location.hash); вставляет содержимое URL-хэша (#<script>alert('XSS')</script>) в страницу, скрипт выполнится. Кража cookies и сессионных данных.
Фишинг-атаки (изменение содержимого страниц).
Выполнение произвольных действий от лица пользователя.
Перенаправление на вредоносные сайты.
Используйте
htmlspecialchars() (PHP), encodeURIComponent() (JS) или аналогичные методы для предотвращения исполнения HTML-кода. Проверяйте и ограничивайте вводимые пользователем данные (например, запрещайте
<script>). CSP ограничивает выполнение скриптов только из доверенных источников.
Флаг
HttpOnly запрещает доступ к cookie через JavaScript, а Secure требует HTTPS. Эти методы позволяют вставлять HTML и JavaScript без защиты.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Вакансии только с прямыми контактами в Telegram! Ноль автоотказов — живой диалог и быстрые объективные решения.
🤖 ML & DS
👨✈️ CyberSec
🔎 QA
💼 1C
👩💻 IT HR
Подпишись чтобы не упустить свой шанс получить лучший оффер!
Please open Telegram to view this post
VIEW IN TELEGRAM
Это порождающий шаблон проектирования, который гарантирует, что у класса есть только один экземпляр, и предоставляет глобальную точку доступа к этому экземпляру. Этот шаблон часто используется для управления ресурсами, такими как базы данных или логирование, где требуется, чтобы доступ был централизованным и единичным.
Класс Singleton создаёт только один экземпляр своего типа и предотвращает создание дополнительных экземпляров.
Singleton предоставляет глобальный доступ к своему экземпляру. Это может быть реализовано через статический метод, который возвращает экземпляр класса.
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls._instance
# Пример использования
singleton1 = Singleton()
singleton2 = Singleton()
print(singleton1 is singleton2) # True
public class Singleton {
private static Singleton instance;
private Singleton() {
// приватный конструктор предотвращает создание объектов вне класса
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
// Пример использования
Singleton singleton1 = Singleton.getInstance();
Singleton singleton2 = Singleton.getInstance();
System.out.println(singleton1 == singleton2); // TrueСтавь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM