Атмосферная история: как поплавать в газовом гиганте

Всякий раз, получая минус в статью за «не соответствует тематике Хабра», я воспринимаю эту оценку со смесью досады и удовлетворения. В целом считаю, что мне удаётся подбирать темы достаточно интересные и не слишком умозрительные, а также наталкивать читателей на размышления и необычные идеи. Однако я был удивлён, когда в поисковой выдаче мне попался удивительный материал с «Пикабу», тема которого значительно более приличествует Хабру. Пользователь shipilev86 задался вопросом: можно ли пролететь Юпитер насквозь? Иными словами, насколько газовый гигант похож на водородно-гелиевое круглое облако, и можно ли в самом деле пронизать такую планету на космическом корабле или хотя бы при помощи космического зонда? Давайте обсудим, какова современная научная точка зрения на этот вопрос, но сформулируем его шире: можно ли пролететь через газовый гигант, и какие осложнения при этом могут нас ожидать?

Краткий ответ на этот вопрос – «при современном уровне развития космонавтики – нет». Ранее в этом блоге я уже затрагивал вопросы классификации экзопланет, например, здесь и здесь. По наблюдениям современных космических телескопов, газовые гиганты гораздо разнообразнее скалистых планет, и делятся, как минимум, на четыре категории:

  1. холодные юпитеры (представители в Солнечной системе: Юпитер и Сатурн)

  2. горячие юпитеры (в Солнечной системе отсутствуют, типичный пример – X0-1 b в созвездии Северная Корона)

  3. горячие нептуны (в Солнечной системе отсутствуют, один из самых известных примеров – Дульсинея в системе звезды мю созвездия Жертвенник)

  4. холодные нептуны (представители в Солнечной системе: Уран и Нептун)

Кроме того, в одном из постов я обращался к некропланетологии – дисциплине в рамках исследования экзопланет, в рамках которой химический состав внесолнечных газовых гигантов пытаются анализировать, пока эти планеты сближаются с родительской звездой. Некропланетология подтверждает, что нептуны, как горячие, так, несомненно, и холодные, настоящими «газовыми гигантами» не являются. Нептун имеет твёрдое скалистое или ледяное ядро, окутанное мощной гелиево-водородной атмосферой. Именно поэтому многие из «суперземель» на самом деле могут быть недоразвившимися нептунами, либо нептунами, постепенно теряющими газовую оболочку, а не скалистыми планетами, подобными трёхкратно увеличенной Земле. Поэтому пролететь сквозь нептун насквозь нельзя. Его можно расценивать как твёрдую планету, покрытую газовым океаном и обычной газовой атмосферой. А с юпитероподобной планетой ситуация гораздо интереснее.

Во-первых, летом 1994 года удалось в режиме реального времени наблюдать, как в Юпитер врезалась и развалилась на части комета Шумейкеров-Леви 9. Во-вторых, NASA контролируемо утопила в атмосфере Юпитера зонд Galileo, работавшего в течение 1989-2003 года и изучавшего преимущественно Юпитер и его спутники. Аппарат вошёл в верхние слои атмосферы Юпитера со скоростью около 50 км/c и расплавился там, углубившись в верхние слои примерно на 158 километров. Сажать аппарат на один из спутников Юпитера (или разбивать его там) не решились, чтобы исключить риск загрязнения ледяных лун земными микроорганизмами.  Таким образом, уже известно, что:

  1. посадка на газовый гигант пока неосуществима, даже по принципу посадки гидросамолёта на воду

  2. развёртывание обитаемой космической станции в атмосфере Юпитера практически невозможно из-за высокого уровня радиации. 

Опустим проект вывода космической станции на орбиту Юпитера как пока совершенно фантастичный, нерациональный, притом, что принципиально возможный. Если наши пилотируемые экспедиции доберутся до орбиты Юпитера, то гораздо вероятнее, что мы попробуем колонизировать его спутники, а не орбиту. Интереснее обсудить, каков должен быть космический аппарат для многоразовой или долговременной работы в атмосфере Юпитера, какой практический интерес могут представлять её глубокие слои, а также – можно ли всё-таки пролететь Юпитер насквозь, если использовать для этого беспилотный зонд?

Зонд для проникновения в атмосферу Юпитера

Теперь попробуем переформулировать исходный вопрос: «Можно ли прострелить Юпитер пулей или снарядом»? Пуля сравнима по размеру с миниатюрным дроном, который мог бы иметь примерно такие же прочностные, аэродинамические и баллистические показатели, как и пуля. В данном случае ответ также отрицательный, но интересно разобрать – почему нельзя?

Первым аппаратом, запущенным в плотные слои атмосферы Юпитера именно с целью долговременного изучения её состава и свойств, была Юнона. Юнона работает на орбите гиганта с 2016 года и завершает основной объём работ в 2024 году. Именно по данным Юноны можно предположить, что под плотной атмосферой Юпитера находится мантия и магнитное ядро. Предполагается, что граница между мантией и ядром зыбкая, а ядро состоит из сжиженного или даже металлического водорода. Именно водород даёт мощное юпитерианское магнитное поле. Давление под атмосферой Юпитера очень велико и точно пока не известно, но в данном случае непринципиально, находится ли водород в жидком или (гипотетически) кристаллическом состоянии. Согласно имеющимся моделям, жидкий водород должен походить по свойствам на ртуть и быть примерно на 60% плотнее воды. Если все слои Юпитера под атмосферой находятся в (полу)жидком состоянии, то эта внутренняя часть может занимать до 80% всего объёма планеты и походить на металлический океан глубиной тысячи километров. На само ядро Юпитера приходится около 0,1 радиуса планеты.

Прострелить или проплыть такой массив металлического водорода не представляется возможным, однако возможно ли пронизать Юпитер в пределах атмосферы, не ныряя в океан? Метеорологию Юпитера изучала не только «Juno», но и более ранний зонд Galileo, а также наземные обсерватории. Согласно некоторым приближениям, даже чтобы оставаться на устойчивой орбите у самого края атмосферы Юпитера, нужно развивать скорость в 42,5 км/c. Для сравнения: максимальная начальная скорость пули при вылете из ствола превышает 1,1 км/с. Для сравнения: комета Шумейкеров-Леви 9 вошла в атмосферу Юпитера на скорости 61,4 км/c, и некоторые её фрагменты прослеживаются в атмосфере до сих пор. Судя по их движению, на Юпитере наблюдаются мощные стратосферные ветра, скорость которых может достигать 1450 км/ч, а сами турбулентные потоки могут образовывать воронки, сравнимые по диаметру с Землёй.

В пределах атмосферы давление и температура от входа в плотные слои быстро растут. Так, Galileo на входе в атмосферу Юпитера раскалился до 630°C. Ниже температура немного спадает, но быстро растёт давление и скорость (ускорение свободного падения на поверхности Юпитера равно около 24 м/с2 или 2,44 g). Galileo отказал при давлении в 23 атмосферы и при температуре 153°C, продержавшись в верхних слоях атмосферы чуть менее часа.

О запасах металлического водорода

Приведённые оценки с учётом роста температуры и давления позволяют сравнить погружение в газовый гигант с преодолением жидкой, а не газовой среды. Юпитер и Сатурн состоят преимущественно из водорода, и вот как в настоящее время мы представляем себе их структуру:

В 2017 году гарвардским учёным Ранге Диасу и Айзеку Сильвере удалось в лабораторных условиях получить металлический водород. Для этого использовались алмазные наковальни и давление 495 ГПа. По мере роста давления водород явственно менял агрегатное состояние:

На Хабре писали, как этот образец был потерян, но сам опыт не оставил сомнений в том, что водород может переходить в жидкометаллическое состояние. Также на Хабре выходила трёхчастная публикация уважаемого @eugeneb0«Температура и давление фантастики». В первой части этой публикации (рекомендую прочитать все три) приведена фазовая диаграмма водорода:

Таким образом, Юпитер является самым большим резервуаром металлического водорода в Солнечной системе, и свободное полётоплавание в атмосфере Юпитера возможно только в верхнем слое глубиной не более 1500 километров. Агрегатное состояние этого вещества и физические характеристики пока сложно представить, обзор современных гипотез приводится в этом обзоре МФТИ. С высокой вероятностью жидкий металлический водород может быть насыщен свободными электронами и поэтому обладать сильнейшей проводимостью вместе с магнитными свойствами. Поэтому в нём вряд ли можно будет управлять любым металлическим «судном» и задействовать обычную электронику.

По мнению Лейфа Флетчера из Лейчестерского университета, идеальный аппарат для глубокого проникновения в атмосферу газовых гигантов действительно должен иметь форму пули. Кроме того, аппарат должен быть сконструирован из химически инертных, тонких и лёгких материалов. В середине 2010-х в таком качестве рассматривали углеродные нанотрубки, но пока они не достигают нужной длины и толщины не только для полноценного исполнения корпуса из углерода, но и для заключения электроники в углеродный каркас. Для большей устойчивости и «плавучести» аппарата возможна и другая конструкция, предложенная в Лаборатории Реактивного Движения NASA в 2015 году:

Эта конструкция называется «виндбот» и, предположительно, могла бы не только подолгу находиться в атмосфере газового гиганта, но и извлекать из неё энергию. Ещё в 2004 году NASA проектировала марсоход, который мог бы двигаться по поверхности планеты подобно перекати-полю. Такая идея была логична с учётом ветреной погоды на Марсе, но, как показало моделирование, катающийся ровер должен слишком быстро изнашиваться. Но в атмосфере газового гиганта эта конструкция оказывается гораздо удобнее. В рамках программы NIAC был предложен роботизированный зонд, который мог бы долго работать как без крыльев, так и без аэростата. Виндбот должен автоматически ловить ветер и определять зоны турбулентности, а в идеале и использовать ветер как источник энергии. Такой аппарат было бы проще защитить от радиации и прочего электромагнитного воздействия, а также оперативно корректировать курс (аппарату не пришлось бы «разворачиваться»). Кроме того, виндботы могли бы распределяться в атмосфере, образуя мобильную сеть, а при необходимости стыковаться в более крупные формы, подобно тому, как я описывал здесь.

Заключение

По-видимому, из-за вышеописанных препятствий пилотируемая экспедиция в атмосферу газового гиганта никогда не будет возможна. Однако спутники газовых гигантов, например, Титан, являются приоритетными целями для внеземной колонизации, поэтому без некоторого постоянного присутствия в атмосферах этих планет, скорее всего, не обойтись. Зонды могут быть не только исследовательскими, но и метеорологическими, что позволило бы готовиться к магнитным бурям на гиганте, защищая электронику всей колонии. Кроме того, если металлический водород окажется перспективным ракетным топливом и жидким сверхпроводником, то его добыча на газовых гигантах по принципу «зачерпывания» может оказаться более выгодной (даже с энергетической точки зрения), чем синтетическое производство. Наконец, наши Юпитер и Сатурн наверняка существенно отличаются по физическим свойствам от горячих юпитеров. По-видимому, атмосфера горячих юпитеров значительно более разреженная, чем у Юпитера и Сатурна и теоретически лучше подходит для сквозного пролёта.


ссылка на оригинал статьи https://habr.com/ru/articles/752700/

«ЛитРес» подтвердил утечку данных своих клиентов и проводит в связи с этим внутреннее расследование

5 августа 2023 года сервис «ЛитРес» подтвердил утечку данных своих клиентов. Компания проводит в связи с этим инцидентом внутреннее расследование. Платёжные данные утечка не затронула, пользователям «ЛитРес» рекомендовано сменить пароли. В открытый доступ попала часть данных некоторых клиентов «ЛитРес», включая фамилии, имена, адреса электронной почты и хешированные пароли.

«Злоумышленники получили доступ к адресам электронной почты. Важно, что вся платёжная информация в безопасности, поскольку на нашей стороне мы не храним платёжные данные пользователей. «ЛитРес» направил уведомление об инциденте в Роскомнадзор, а также ужесточил контроль за хранением данных, усилил уровень защиты и мониторинг доступов к данным», — говорится в сообщении «ЛитРес».

«ЛитРес» проводит внутреннее расследование инцидента, сообщили в пресс-службе сервиса.

Нам важна безопасность и доверие наших пользователей, поэтому мы хотим рассказать, что произошло, и что Литрес делает, чтобы подобных ситуаций не повторялось.

Утечка данных пользователей Литрес действительно произошла. Злоумышленники получили доступ к адресам электронной почты. Важно, что вся платежная информация в безопасности, поскольку на нашей стороне мы не храним платежные данные пользователей.

Приносим искренние извинения за сложившуюся ситуацию. Безопасность данных клиентов Литрес – наш ключевой приоритет, и произошедшее, безусловно, недопустимо. Действия по защите ваших данных мы начали предпринимать еще до того, как информация об утечке появилась в интернете. Безусловно, все меры для предотвращения подобных ситуаций в будущем также предприняты. Мы ужесточили контроль за хранением данных, усилили уровень защиты и мониторинг доступов к данным. Также, как и принято в таких ситуациях, мы направили уведомление об инциденте в Роскомнадзор, где рассказали про предпринятые действия.

Но все-таки мы рекомендуем вам сменить пароль от Литрес, а также от всех сервисов, где вы использовали такой же или похожий пароль. В случае, если с вашими аккаунтами будут совершены какие-либо несанкционированные действия, все они будут отменены сервисом по вашему запросу.

Если у вас остались вопросы, напишите в нашу службу поддержки help@litres.ru

4 августа 2023 года неизвестный хакер выложил в открытый доступ данные некоторых пользователей сервиса «ЛитРес» (litres.ru). По его словам, после взлома платформы была получена база данных с информацией о 97 млн пользователей. В качестве доказательства хакер опубликовал около 3% данных.

Профильные эксперты сообщили, что выложенный файл размером 677 МБ (архив litres-part.zip занимает 133 МБ) содержит 3 млн строк в формате логин, хеш пароля, электронная почта (588 877 уникальных элементов), редко в строках встречается фамилия и имя. Большая часть строк содержит параметр NULL. Актуальность базы оценивается июнем-августом 2023 года.

Эксперты сервиса разведки утечек данных и мониторинга даркнета DLBI пояснили, что в опубликованном файле содержится 3 083 408 строк с данными пользователей. Они проверили случайные адреса электронной почты из этого файла через функцию восстановления пароля на сайте litres.ru и выяснили, что они действительные.


ссылка на оригинал статьи https://habr.com/ru/articles/752696/

RuGPT3XL. Примеры генерации на русском языке (zero-shot coding)

Давно известно, что Сбер разработал и опубликовал свою коллекцию генеративных текстовых моделей на русском языке — RuGPT3.

Демо-версия от Сбер ruGPT-3 XL для тестирования есть прямо на сайте:
Основная статья от Сбера с примерами и пояснениями здесь.

В предыдущей статье описано собственное тестирование генерации моделей rugpt3small_based_on_gpt2, rugpt3medium_based_on_gpt2, rugpt3large_based_on_gpt2 в colab на python. Модели отвечали на распространенные вопросы.

В данной статье тестируем ruGPT-3 XL прямо на демо-странице от Сбера.


Как проводится данное исследование:
даем RuGPT3 простые запросы.
«Простые» означает, что формулируем запрос естественным образом, на естественном русском языке, без затравочных примеров и определения ролей.
Такие же запросы даем ChatGPT.

Примеры для исследования такие:
1. придумай 10 названий для историй
2. придумай начальные фразы для 10 историй
3. придумай историю о том, как две маленькие девочки пошли в лес
4. Автомобили нужны для того, чтобы

придумай 10 названий для историй

ChatGPT

1. «Путь к забытой цивилизации»
2. «Тайна затерянного города»
3. «Охота на легендарное существо»
4. «Путешествие в неизвестность»
5. «Искупление за прошлое»
6. «Побег из тюрьмы смерти»
7. «Сражение за свободу»
8. «Поиск истины в мире лжи»
9. «Клятва верности королю»
10. «Битва за будущее мира»

RuGPT3

RuGPT3: придумай 10 названий для историй
Подсказываю. Какая история пропущена?

придумай начальные фразы для 10 историй

ChatGPT

  1. «Он уже давно не верил в легенды, но когда нашел карту, ведущую к забытой цивилизации, решил попробовать свою удачу.»

  2. «Молодой археолог отправился на экспедицию в поисках затерянного города, о котором слышал только в рассказах своего деда.»

  3. «Легендарное существо, живущее в глубине леса, было его последней надеждой на спасение от бандитов, преследующих его уже несколько дней.»

  4. «Он всегда мечтал отправиться в путешествие в неизвестность, и когда представилась возможность, не задумываясь, покинул свой дом и отправился в путь.»

  5. «Она совершила страшную ошибку в прошлом, и теперь ей необходимо искупить свою вину, чтобы наконец-то спокойно жить дальше.»

  6. «Он был обвинен в убийстве, которого не совершал, и теперь ему остается только одно — попытаться сбежать из тюрьмы смерти.»

  7. «Они были готовы сражаться до конца за свою свободу, ведь она была для них самым дорогим и ценным.»

  8. «Она всю жизнь искала истину, но когда наконец нашла ее, поняла, что иногда лучше жить в мире лжи, чем столкнуться с правдой.»

  9. «Он дал клятву верности королю и был готов выполнить любое его приказание, но когда узнал о том, что происходит в королевстве, начал задумываться о своем решении.»

  10. «Битва за будущее мира началась, и теперь каждый должен выбрать свою сторону и сражаться до конца.»

RuGPT3

RuGPT3: придумай начальные фразы для 10 историй

1. Я выбрала тебя потому, что в твоих глазах отражается свет, и я хотела смотреть на тебя.

2. Вот и отец, сегодня он на школьной экскурсии, смотрит на нас.

Продолжение (какая-то белиберда)

Если он видит нас, он помнит о нас. И если он меня вспомнит, он меня отблагодарит.
И я хотела просто смотреть на него.
Он всегда смотрит на меня, когда думает, что я не замечаю.
Для меня это очень важно.
Правда, на уроках я смотрю на него лишь изредка.
Постоянно только в эти минуты, когда она говорит:
«Господа, сегодня мы идем на экскурсию».
Она смотрит на отца, а отец говорит: «Замечательно».
И мы все идем.
Потому что всем страшно.
Все молча смотрят на учителя.
Она оборачивается.
Я за ее спиной.
Мы смотрим друг на друга.
Разглядываем.
Говорим, будто мы уже старые знакомые.
В его глазах читаю, что он тебя помнит и что тебе страшно. Он знает, что мне страшно. Только не знает, почему.
Смотрит на меня.
Но я не боюсь.
Лишь бы он помнил.
Однако он не помнит.
Не помнит, хотя ты мне расскажешь.
Его зовут Афонсо. Его зовут А-фонсо, и мы с ним еще встретимся.
А его зовут А.
Завтра.
1 сентября.
Что касается меня, то я шла сегодня в школу.
Пасмурно, но после обеда станет солнечно.
О-о-о, мой друг, как мне тебя не хватает, мой любимый.
Как я рада, что ты здесь.
Мне страшно. Но я пришла в школу и стою в школьном коридоре.
Учительствует мой друг.
Сколько ему лет?
Двенадцать?
Нет.
Одиннадцать?
Тоже нет.
Ему тридцать три.
Тридцать два?
Не знаю. Может, и он тоже думает, будто это предел?
Но он мне расскажет, как прошел первый день в школе.
Следующий учитель, может быть, А… (учитель)
Можешь идти, школьница.
Ну, беги же.
Вот и все.
Скоро вернусь.
Вернусь, когда уйдут все. Прежде всего, мой дорогой, мой Афонс.
Потом ты и другие.
Каждый принесет чт

придумай историю о том, как две маленькие девочки пошли в лес

ChatGPT

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

RuGPT3

RuGPT3: придумай историю о том, как две маленькие девочки пошли в лес и заблудились там: одна из них голодная, а другая хочет еще есть).

Продолжение (какая-то белиберда)

Работа на уровне подсознания.

Давай нарисуем, как мы будем жить. Не надо своих фантазий. Я буду рисовать круг, чтобы дома мы жили в кругу. Как круг выглядит? Давай определимся: будет 2 края – это с одной стороны лес, а с другой – сад. (Работа на уровне ассоциаций. Мы рисуем круг, в нем – домик, ручей, яблоня, собака, лес, травинка, солнце и т.п. Для задания обращаемся к тому, кто выполняет задание с вопросом: «Как ты думаешь, что это за дом?») Работа с переживанием. Я предлагаю тебе представить себя в этом домике и представить, что ты уже живешь в нем. Или нарисовать свой собственный домик и в нем домик для кукол, которые живут в доме. Мы будем заниматься дыхательными упражнениями для того, чтобы человек мог хорошо и глубоко дышать, чтобы живот был поджат, а живот – расслаблен. И так, приступим к упражнениям. Упражнение No 1. Мы будем стоять на месте. Тело должно быть расслаблено. Мы можем делать упражнение, стоя или сидя. И чтобы не было напряжения, мы должны подержать это напряжение очень долго. Одна девочка стоит, другая лежит. Кто будет первым? (Девочка, которая стоит). Встать! (Все, кто стоят, встают) Вторая девочка стоит. Теперь лягте. Я предлагаю всем лечь, так чтобы ягодицы касались пола, и полностью расслабить поясницу, а также ноги. Теперь, стоя так, мы можем почувствовать напряжение в нижней части живота и поднять ноги выше, чем плечи. После этого мы выпрямляем ноги, чтобы стоять прямо, и начинаем в какой-то момент дышать животом так глубоко, как только возможно. Или наоборот, сжимаем колени, а потом расслабляем ноги. Потом, стоя прямо, мы расслабляем живот и поджимаем ягодицы. И так делаем упражнение. После того, как все сделали упражнение, ты можешь сесть и положить одну руку на живот. А другую руку положить на живот справа. Обе руки лежат на животе. Теперь, пусть это упражнение посмотрит все, кто хочет. Это упражнение в школе дыхания, оно называется дхармасала. Оно очень хорошее, и его можно делать в любом удобном положении. Практика. Когда мы делали это упражнение, мы погружались в чувство

Автомобили нужны людям для того, чтобы

ChatGPT

Автомобили нужны людям для того, чтобы перемещаться на большие расстояния, быстро и удобно доставляться на работу, в школу или в другие места. Они также позволяют совершать поездки на отдых, деловые поездки и посещать родственников и друзей.

Кроме того, автомобили используются для перевозки грузов и товаров, что является необходимым для развития экономики и бизнеса. Они также используются для спасательных операций, доставки медицинской помощи и других служб общественной безопасности.

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

RuGPT3

RuGPT3: автомобили нужны людям для того чтобы ездить по нашим дорогам а не чтобы по ним летать. как по мне так лучше уж ездить на груженой телеге чем на таком чудовище.
А как по вашему?

Вывод

На примере ChatGPT видно, что генеративные модели «от производителя» могут давать вполне читабельные человекоподобные варианты, то есть сама концепция GPT работает. При этом адекватной генерации текста в случае RuGPT3 без дообучения и «затравочного программирования» пока не наблюдается.

Примечание

Абсолютно ничего не имею против Сбера. С точки зрения клиента и пользователя мне нравятся многие моменты — и быстрота переводов, и чистота в отделениях, и круглосуточные банкоматы. А вот по генерации RuGPT3 я пока в легком недоумении. Хотя возможно, что генерация на RuGPT3 с ходу не получается именно у меня, а у кого-то получается.

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

Для следующих шагов запланировано тестирование «затравочного программирования» в части задавания примеров — one-shot coding / few-shot coding, а также дообучение по какой-либо тематике.


ссылка на оригинал статьи https://habr.com/ru/articles/752672/

Sticky Header в SwiftUI

Всем привет!

В этой статье я бы хотел рассказать свой опыт создания липких заголовков или Sticky Header с использованием SwiftUI (в дальнейшем SUI).

Мы сделаем с вами такой кастомный хедер, а так же вы поймете как мы можем получать доступ к UIKit-овой изнанке SwiftUI.

Почему я решил написать эту статью?

  • При переходе с UIKit на SwiftUI мне не хватало чувства контроля. Я не понимал, как получить доступ к состоянию моих View и как тонко и точно настраивать их поведение. Статья может быть полезна людям с такими же проблемами.

  • Sticky Header – часть почти любого мобильного приложения, а в русскоязычном интернете (да и в англоязычном тоже) очень мало информации о том как сделать кастомный липкий заголовок на SUI.

  • В SUI нет нативного и удобного способа создания такого header-а (начиная с iOS 17 в SUI добавили .visualEffect модификатор, который позволяет получить доступ к офсету скрола.)
    Но когда мы поднимем свои таргеты в реальных проектах до iOS 17 — очень большой вопрос.

Из чего же состоит экран с липким заголовком?

Предупрежу что сама реализация такого header-а в SUI отходит от парадигмы этого фреймворка (декларативность) и выполняется в императивном стиле.

Что бы наш header стал по настоящему sticky, нам надо получать состояние прокрутки (смещение по оси Y) ScrollView и смещать на такое же количество поинтов наш header, создавая эффект неподвижности.

Базовый принцип работы липкого хедера

Базовый принцип работы липкого хедера

Как в SUI можно получать смещение по оси Y ScrollView?

Те кто больше слышал о SwiftUI, чем с ним работал подумают что это супер просто, в SUI куча реактивщины, скорее всего есть какой нибудь модификатор куда можно передать Binding<CGFloat> и дело с концом.

Ответ: НЕТ! До iOS 17 такого модификатора не существует, а наши пользователи с iOS 14 также хотят себе липких хедеров в приложении!

Значит будем выкручиваться костылями!

Сочетаем скорость SwiftUI и возможности UIKIt

Сочетаем скорость SwiftUI и возможности UIKIt

Разработчики, которые не пишут или почти не пишут на SUI удивятся, ведь получать состояние скролла в UIKit очень легко, достаточно просто… 

Реализовать методы делегата UIScrollView!

Существует целая пачка методов для UIScrollView которые покрывают практически все что мы можем пожелать.

Осталось только каким то образом заиметь нашему ScrollView такого же делегата как и UIScrollView и реализовать его методы.

К счастью, ScrollView под капотом и есть UIScrollView! 

Далее без всяких доп библиотек мы получим доступ к ScrollVIew как к UIScrollView 

struct ScrollDetector: UIViewRepresentable {          //Замыкание в которое будет передаваться текущий offset     var onScroll: (CGFloat) -> Void          //Замыкание которое вызывается когда пользователь отпускает палец     var onDraggingEnd: (CGFloat, CGFloat) -> Void               //Класс-делегат нашего ScrollView     class Coordinator: NSObject, UIScrollViewDelegate {                  var parent: ScrollDetector          var isDelegateAdded: Bool = false                  init(parent: ScrollDetector) {             self.parent = parent         }                  //методы UIScrollViewDelegate         func scrollViewDidScroll(_ scrollView: UIScrollView) {             parent.onScroll(scrollView.contentOffset.y)         }                  func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {             parent.onDraggingEnd(targetContentOffset.pointee.y, velocity.y)         }                  func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {             parent.onDraggingEnd(scrollView.contentOffset.y, 0)         }                  //тут могли бы быть другие методы UIScrollViewDelegate         //так как у нас в распоряжении ПОЛНОЦЕННЫЙ ДЕЛЕГАТ от UIKit-ового UIScrollView!     }          func makeCoordinator() -> Coordinator {         Coordinator(parent: self)     }          //При создании пустой UIView находим UIScrollView и назначаем ему в делегаты наш coordinator     func makeUIView(context: Context) -> UIView {         let uiView = UIView()         DispatchQueue.main.async {             if let scrollView = recursiveFindScrollView(view: uiView), !context.coordinator.isDelegateAdded {                 scrollView.delegate = context.coordinator                 context.coordinator.isDelegateAdded = true             }         }         return uiView     }          //рекурсивно перебираем родителей нашей пустой UIView в поисках ближайшего UIScrollView     func recursiveFindScrollView(view: UIView) -> UIScrollView? {         if let scrollView = view as? UIScrollView {             return scrollView         } else {             if let superview = view.superview {                 return recursiveFindScrollView(view: superview)             } else {                 return nil             }         }     }          func updateUIView(_ uiView: UIView, context: Context) {} } 

Мы создали переиспользуемый ScrollDetector откуда мы получаем доступ к делегату UIScrollView!

Приведу пример его использования в нашем случае:

struct MainScreen: View {     var size: CGSize     var safeArea: EdgeInsets          @State private var offsetY: CGFloat = .zero          var body: some View {                  ScrollViewReader { proxy in             ScrollView(showsIndicators: false) {                 VStack {                     createHeaderView()                         .zIndex(1)                                          createMainContent()                 }                 .id("mainScrollView")                 .background {                     ScrollDetector { offset in                         offsetY = -offset                     } onDraggingEnd: { offset, velocity in                         if needToScroll(offset: offset, velocity: velocity) {                             withAnimation(.default) {                                 proxy.scrollTo("mainScrollView", anchor: .top)                             }                         }                     }                 }             }         }     }

Имея полный доступ к состоянию ScrollView, мы ограничены только нашей фантазией.

Код для создания эффекта инерции и расчета положения/размера скролла:

    //данная функция создает эффект "инерции"     private func needToScroll(offset: CGFloat, velocity: CGFloat) -> Bool {         let headerHeight = (size.height * 0.25) + safeArea.top         let minimumHeaderHeigth = 64 + safeArea.top                  let targetEnd = offset + (velocity * 45)                  return targetEnd < (headerHeight - minimumHeaderHeigth) && targetEnd > 0     }          //тут вся математика по расчету текущего положения/размера хедера и его контента     @ViewBuilder     private func createHeaderView() -> some View {         let headerHeight = (size.height * 0.25) + safeArea.top         let minimumHeaderHeigth = 64 + safeArea.top         let progress = max(min(-offsetY / (headerHeight - minimumHeaderHeigth), 1), 0)              GeometryReader { _ in             ZStack {                 Rectangle()                     .fill(Color("habrColor").gradient)                                  VStack(spacing: 15) {                     GeometryReader {                         let rect = $0.frame(in: .global)                                                  let halfScaledHeight = (rect.height * 0.2) * 0.5                         let midY = rect.midY                                                  let bottomPadding: CGFloat = 16                         let reseizedOffsetY = (midY - (minimumHeaderHeigth - halfScaledHeight - bottomPadding))                                                  Image("habr")                             .resizable()                             .renderingMode(.template)                             .frame(width: rect.width, height: rect.height)                             .clipShape(Circle())                             .foregroundColor(Color(.white))                             .scaleEffect(1 - (progress * 0.5), anchor: .leading)                             .offset(x: -(rect.minX - 16) * progress, y: -reseizedOffsetY * progress - (progress * 16))                     }                     .frame(width: headerHeight * 0.5, height: headerHeight * 0.5)                                          Text("Привет, Хабр👋")                         .font(.title)                         .fontWeight(.bold)                         .foregroundColor(.white)                         .scaleEffect(1 - (progress * 0.1))                         .offset(y: -2 * progress)                                      }                 .padding(.top, safeArea.top)                 .padding(.bottom)                              }             .shadow(color: .black.opacity(0.2), radius: 25)             .frame(height: max((headerHeight + offsetY), minimumHeaderHeigth), alignment: .bottom)                      }         .frame(height: headerHeight, alignment: .bottom)         .offset(y: -offsetY)     }

Если вас заинтересовал данный способ и вы хотите сделать что то похожее, добро пожаловать на мой GitHub за исходным кодом.

Если остались дополнительные вопросы, пишите в комментариях, обязательно отвечу.


ссылка на оригинал статьи https://habr.com/ru/articles/752670/

IronZen: как мы решили боль тысяч тревожных людей, разработав собственное мобильное приложение

Кейс о том, как компания друзей с опытом в IT и digital на досуге начала разрабатывать приложения, и в первом же проекте закрыла острую проблему людей с повышенной тревожностью и ОКР, дав старт собственной кузнице аппок.

С чего всё началось

У вас есть телеграм-чат с друзьями, где вы 80% времени забавно флудите, и пишете шутки, которые понимают только внутри компании? Вот и у нас есть такой.

В начале 2023 года мы осознали: у большинства друзей из чата есть опыт в разных айти и диджитал сферах: разработка, дизайн, тестирование, маркетинг, копирайтинг, SEO, ASO. Готовая команда для стартапа. У всех есть амбиции, знания, навыки, и желание создавать что-то новое. Так мы решили проводить свободное время с пользой, разрабатывая приложения.

Поиск идеи

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

В один обычный день, уходя из дома, наш тестировщик Дима проверял стандартные вещи: выключен ли газ на плите, закрыты ли окна, с собой ли всё необходимое. В тот момент Дима вспомнил про людей, которые чересчур тревожатся или вовсе страдают ОКР (обсессивно-компульсивное расстройство). Такие могут вернуться посреди рабочего дня домой проверить выключен ли утюг. Они же дёргают ручку двери сразу же после того, как закрыли её на ключ. Быть может, и вы в этом узнали себя?

Мы поняли, что можем помочь таким людям меньше тревожиться, сделав приложение, которое подарит им спокойствие вне дома.

Концепт и первые шаги

Дима быстро понял перспективность идеи, презентовал её команде на словах, и, получив одобрение, пошёл развёртывать теорию в концепт.

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

Мы приняли решение реализовывать идею в виде чего-то похожего на умный чек-лист. В нём создаются сценарии вроде «Ухожу из дома», которые в свою очередь наполняются действиями. Например: «Выключить утюг», «Перекрыть кран в ванной», «Насыпать корм псу».

Запустил сценарий → выполнил действие → поставил галочку → завершил сценарий → спокойно пошёл по делам.

По желанию всё это можно подкреплять фотографиями помимо отмеченных галочек. Фотографировать — рекомендация докторов, консультирующих людей с ОКР.

Пройденные сценарии собираются во вкладке «История», чтобы в любой момент можно было перепроверить, что дома всё в порядке.

Важный нюанс: все данные хранятся локально, на устройстве пользователя. Поэтому с точки зрения утечки данных приложение полностью безопасно.

Первоначальный концепт основных экранов приложения.

Первоначальный концепт основных экранов приложения.

У всех резко вырос энтузиазм, глаза загорелись, а вечерние созвоны в Discord наполнились фразами «Кайф!», «Клёво!», «Делаем!». Процесс был запущен окончательно.

Разработка и оформление

Далее идея и концепт стали реализовываться в виде строчек кода. Разрабатывалось приложение на кроссплатформенном фреймворке Flutter.

Параллельно искали дизайн иконки, накидывали варианты названий, подбирали ключевые фразы. Работа кипела.

Каждый участник команды придумал несколько вариантов названий. Путём голосования определили победителя — IronZen.

Каждый участник команды придумал несколько вариантов названий. Путём голосования определили победителя — IronZen.

Мы определили главный триггер — (не)выключенный утюг. В статьях про опыт людей с ОКР это встречалось чаще всего, прямо в заголовках. У людей именно утюг был первой ассоциацией. Вокруг него и начали строить концепцию оформления.

Так определился победитель в нейминге — IronZen. Iron — утюг, Zen — дзен/спокойствие.

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

Было интересно и сложно, когда мы сталкивались с фундаментально разными видениями, на, казалось бы, простые вещи. Порой 1.5-2 часа рабочего созвона тратили на споры по поводу одной функции или кнопки. Тем не менее мы каждый раз находили компромисс, учась более эффективно работать друг с другом.

Большую часть времени заняло производство дизайна для онбординга и скринов в AppStore и Google Play. Долго искали компромиссы между информативностью и красотой. Множество раз меняли тексты. Каждый пропускал это через собственную призму и имел своё видение. Было непросто, но очень интересно.

Первые сборки и тестирование

Вскоре мы уже могли пощупать первые версии приложения IronZen. Естественно, обнаружилось большое количество ошибок и багов, которые тут же оформлялись в тикеты в Jira, а затем оперативно фиксились.

Приложение обрело близкий к финальному вид.

Финальный вид основных экранов IronZen. Слева направо: список сценариев, экран внутри сценария с действиями, история.

Финальный вид основных экранов IronZen. Слева направо: список сценариев, экран внутри сценария с действиями, история.

Понадобилось более 20 обновлений первоначальной версии, чтобы привести всё в порядок перед релизом. Параллельно доделывали скрины для магазинов и тексты, переводили приложение на несколько языков.

Кстати, в работе мы использовали ChatGPT. Он довольно успешно справился со значительной частью дескрипшенов, и даже придумал нам очень крутой слоган!

Leave anxiety at home, not a working iron — оставь дома тревогу, а не включённый утюг — слоган, придуманный ChatGPT.

Leave anxiety at home, not a working iron — оставь дома тревогу, а не включённый утюг — слоган, придуманный ChatGPT.

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

Релиз и первые отзывы

К концу апреля всё было готово к релизу. Было весьма волнительно.

На первых порах очень нужны установки, чтобы App Store получил сигнал о том, что приложение интересно людям. Поэтому мы делали посты об IronZen в соцсетях, скидывали друзьям, знакомым и коллегам, запустили небольшую рекламу в Facebook.

Основной трафик удалось привлечь с помощью треда в Твиттере, который получил неплохой охват.

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

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

В нашем безумном мире тревожность очень распространённое явление. А ОКР совсем нередкое заболевание. IronZen действительно избавляет от навязчивых тревожных мыслей, что в доме что-то горит или течёт.

Но это не только про забывчивых и неспокойных людей. Пространство для использования аппки гораздо шире. Например, один пользователь Twitter написал: «Сделал себе сценарий для сбора вещей на тренировку — очень удобно!». А другой человек в личной беседе поделился, как собирался в путешествие и, благодаря IronZen, ничего не забыл: «Это была самая спокойная поездка в аэропорт, так как я был максимально уверен, что всё необходимое у меня с собой».

Ожидаемая проблема

На данный момент всего мы имеем 350 установок и 60% из них активных пользователей, которые регулярно пользуются приложением. Каждый день органически приходит 1-2 новых юзера.

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

Перед тем, как собраться в стартап мы изучали множество успешных кейсов, среди которых часто встречалось успешное ASO, за счёт которого приложение выстреливало. Надеется на такое было наивно, но очень хотелось верить в чудо.

Один из креативов для рекламной кампании в Facebook.

Один из креативов для рекламной кампании в Facebook.

Приложение IronZen полностью бесплатное. Если наша разработка показалась вам ценной и полезной — добро пожаловать в сторы. В комментариях будем благодарны конструктивному фидбеку.

App Store →
Google Play →
Landing Page →


После релиза первого продукта мы не остановились, а сразу же принялись за новый проект. В данный момент мы уже выпустили второе приложение — калькулятор банковских и рабочих дней BizDay. А прямо сейчас в разработке третий продукт, который мы оцениваем как очень перспективный и амбициозный.


ссылка на оригинал статьи https://habr.com/ru/articles/752688/