Я не уверен, что кто‐то всерьёз думает, что это именно защита: при наличии документации всё понятно по разводке платы. С микросхемами в корпусе «капля» и без документации немного сложнее, но не сильно, если есть достаточное представление о том, что должно быть на Flash.
Но вообще если есть какая‐нибудь память с интерфейсом вида «подал адрес на параллельную шину, зажал CS и OE, подождал, получил результат на параллельной шине», и эта память имеет как минимум 2^n «слов» (шириной в параллельную шину данных), то у неё можно свободно переставить n нижних бит адреса (как правило — все биты, мне пока не встречалась такая память с объёмом‐не степенью 2) и все биты данных, чтобы упростить разводку. Я сам так как‐то с SRAM делал. (С SRAM это может быть особенно просто: если данные туда пишет сам микроконтроллер, то не нужно даже думать о каких‐либо перестановках при программировании. У меня было не так, но проблемной частью было «как перебить подключённый микроконтроллер», а не «как переставить биты».)
Про удаление лишнего припоя с ножек: тут уже рекомендовали оплётку, но есть ещё одна особенность: если лишнего припоя мало и вы не можете ткнуть в него паяльником или оплёткой — и, главное, он где‐то за ножками и паяльником с нормальной температурой не нагревается, иногда имеет смысл добавить больше припоя. Огромная капля удаляется оплёткой с ножек без проблем, мелкая капля едва касающаяся чего‐либо паяльником не удаляется без добавления припоя в принципе: либо вы поглощаете её лишним припоем, либо можно попробовать много флюса и фен. Нагревать паяльник выше той температуры, при которой вам комфортно паять ножки, для удаления мелкой капли не нужно. При использовании оплётки, если вы паяете на минимальной комфортной температуре, придётся добавить 20—30 ℃.
Я обычно паяю большим топориком (K) с 240 ℃ для микросхем с ножками, 250 ℃ для ёмкостей/… 0603—0805, подключающихся к огромным полигонам, 260—280 ℃ для танталовых конденсаторов и THD. Выше в специальных случаях. Если жало — не большой топорик, температура может потребоваться выше.
А относительно BGA: по‐моему вы ухудшили себе жизнь, не купив ИК станцию вместо столика с подогревом. У нас в компании BGA паяют без трафаретов и пасты: берём нормальный флюс (сейчас — Mechanic SD-360), мажем его очень тонким и ровным слоем по всем площадкам, ставим схему и греем ИК станцией. Работает как с золотым финишным покрытием (иммерсионное золото), так и с ПОС‐63 (или остатками шариков), но если ПОС‐63 появился после выпайки микросхемы, а не после завода, то его нужно аккуратно выровнять оплёткой (в плохих случаях: сначала паяльником смахнуть остатки шариков, а потом уже оплёткой), при этом не убрав этой оплёткой маску (что тем легче сделать, чем горячее паяльник) и не сорвав случайно площадки (что тем легче сделать, чем холоднее паяльник). Трафарет понадобится, если нужно будет перенакатывать шарики. Или если вы всё же решите поставить по одному 0402 конденсатору под каждый шарик питания и у вас есть ИК станция.
В качестве бюджетной ИК можно брать Puhui T-962, но её придётся доработать (у нас это запасная станция на случай поломки основной). Доработать — это обклеить термоскотчем, изменить прошивку, добавить дополнительный температурный сенсор.
Такие костыли я видел. Они хорошо заметны, и они точно не могут привести к идентичным $dir-fe (выводам git fast-export).
И в любом случае, напомню, что ветка началась с того, что я указал возможность сохранения информации о перемещениях в СКВ, хранящей слепки, и hg-git — это просто пример хранения этой информации в СКВ, хранящей слепки. Какими костылями он это делает неважно — это просто пример, что это сделать возможно, соответственно из «в гите как раз слепки хранятся» не может следовать, что гит «не умеет трекать перемещения» — он не умеет трекать перемещения, потому что его авторы решили не добавлять сохранение перемещений, а не потому что он хранит слепки.
Ваша ссылка относится к commit’ам, сделаным в git. У меня commit’ы, сделанные в mercurial, в которых уже есть информация о переименованиях и она должна быть частью commit’а и на стороне mercurial, и на стороне git, чтобы hg-git вообще работал: хэши commit’ов должны сохраняться при конвертации в любую сторону, чтобы можно было нормально работать, а не постоянно решать проблемы рассинхронизации. Можете проверить, например, так:
Скрипт
#!/bin/sh
set -e
# set -x
TGT=$1 ; shift
if test "$TGT" = "--help" ; then
echo "Usage: $0 NEWDIR"
exit 1
fi
export SCREENDIR="$(realpath "$TGT")/screen"
mkdir -p "$TGT"
mkdir -m 0700 -p "$SCREENDIR"
cd "$TGT"
for dir in mv nomv ; do
hg init "$dir"
cd "$dir"
echo abc > a
hg add a
hg commit -m 'Add a' --date=2000-01-01 --user=test
hg rm a
echo def > b
hg add b
if test "$dir" = mv ; then
hg mv -A a b
fi
hg commit -m 'Move a to b' --date=2000-01-01 --user=test
hg bookmark master
hg gexport
cd .hg/git
git fast-export master > "../../../$dir-fe"
git bundle create "../../../$dir-bundle" master
git log > "../../../$dir-log"
screen -d -m -S git-daemon git daemon --export-all --base-path=.
hg clone "git://127.0.0.1/" "../../../$dir-clone"
screen -X quit
cd ../..
hg log --follow b > "../$dir-log-follow"
cd ..
cd "$dir-clone"
hg log --follow b > "../$dir-clone-log-follow"
cd ..
diff --report-identical-files "$dir-log-follow" "$dir-clone-log-follow"
done
Здесь я клонировал репозиторий git «по сети» и сравнил вывод hg log --follow оригинального и склонированного репозитория. Они совпадают.
Вообще‐то хранение слепков/разностей и возможность сохранения информации о перемещении файлов несколько ортогональны. Git вполне мог сохранять информацию о факте перемещения отдельно от самих слепков. Более того, hg-git отлично сохраняет куда‐то информацию о перемещениях. Я у себя проверил вот таким скриптом:
#!/bin/sh
set -e
TGT=$1 ; shift
if test "$TGT" = "--help" ; then
echo "Usage: $0 NEWDIR"
exit 1
fi
mkdir -p "$TGT"
cd "$TGT"
for dir in mv nomv ; do
hg init "$dir"
cd "$dir"
echo abc > a
hg add a
hg commit -m 'Add a' --date=2000-01-01 --user=test
hg rm a
echo def > b
hg add b
if test "$dir" = mv ; then
hg mv -A a b
fi
hg commit -m 'Move a to b' --date=2000-01-01 --user=test
hg bookmark master
hg gexport
cd .hg/git
git fast-export master > "../../../$dir-fe"
git bundle create "../../../$dir-bundle" master
git log > "../../../$dir-log"
cd ../..
cd ..
done
Разница в том, что оказалось в git видна только в файлах $dir-bundle, $dir-log содержит только различающиеся хэши второго commit’а, а $dir-fe идентичны, так что как достать эту информацию из git и как она вообще сохраняется мне не очевидно. Возможно, hg-git просто нашёл какой‐то способ хранения своих метаданных и git понятия не имеет, что они означают. Код [hg-]git я сейчас как‐то смотреть не хочу. Но факт тот, что в git вполне возможно сохранять информацию о переименованиях, хранение слепков этому не мешает.
То, что обычно, зависит от того, что вы делаете. Я занимаюсь испытанием микросхем на радиационную стойкость и я почти никогда не округляю до ближайшего значения: это либо округление вверх (параметр‐критерий годности, должный быть «не больше» какого‐то значения; требуемый уровень воздействия, …), либо вниз (… «не меньше»; уровень стойкости), либо «от центра» (параметры, которые одновременно не больше и не меньше) — т.е. что в данном контексте «более консервативно».
У Excel, кстати, функции для округления вверх и вниз до множителя определённого значения есть. А в LabVIEW, который часто используется испытательными центрами, почему‐то есть только округление до целых.
Ruby и Python — да. В javascript похоже засунули в стандарт оптимизацию, используемую для таблиц lua (скорее не саму оптимизацию, но её последствия в части того, как удобнее всего реализовывать итерацию по object): MDN в документации for..in утверждает
The traversal order, as of modern ECMAScript specification, is well-defined and consistent across implementations. Within each component of the prototype chain, all non-negative integer keys (those that can be array indices) will be traversed first in ascending order by value, then other string keys in ascending chronological order of property creation.
Где это написано в собственно спецификации ECMAScript я не нашёл, но в этом тексте написано сначала цифровые индексы по порядку, потом строковые ключи таки в порядке добавления.
В C# Dictionary без Sorted не сортирует по ключам. Интерфейс Map в Java не требует определённого порядка. Если это более скриптовый язык, где словари являются частью основного синтаксиса, то внутри почти наверняка будет хэш‐таблица, которые с сортировкой по ключам не очень дружат.
Собственно под «обычно» я думал скорее про них — я обычно использую Rust или такие скриптовые языки и в Rust есть, к примеру, HashMap и BTreeMap, но у обоих название вида ImplementationMap и нельзя сказать, что есть какие‐то предпочтения на уровне языка или стандартной библиотеки. HashMap, впрочем, используется чаще, потому что за сортировку по ключам вы платите скоростью всех операций в данном случае.
Это где так? Обычно итерация происходит в одном из двух порядков:
В порядке добавления ключей.
В неопределённом порядке, оно же в порядке, в каком данные располагаются в map (т.е. по сути что‐то вроде «в порядке возрастания остатков от деления хэшей на размер map», если не учитывать коллизий).
Оба порядка — это «в каком порядке удобно делать итерацию при данной реализации map», и «в порядке возрастания ключей» удобно делать, только если map — это дерево вроде BTreeMap, а не хэш‐таблица.
Помимо этого есть lua, где таблицы одновременно ещё и массивы и другие языки со схожими идеями, где, в зависимости от ключа, значение окажется либо во внутреннем массиве, либо в хэш‐таблице, но даже у lua порядок никак не гарантируется даже для числовых индексов (вероятно, т.к. вы вполне можете засунуть числовой индекс в хэш‐таблицу, а не в массив).
Для того, чтобы показать на форуме, как вы можете написать рекурсивный макрос или ещё чего интересное, достаточно. Если нужно какой‐то доступ к сети, я бы смотрел так:
Есть ли готовые пакеты с решением проблемы? Я не уверен, как сформулировать такой запрос, но когда я искал, а что делают сервисы CI (а они по сути как раз запускают у себя недоверенный клиентский код, которому нужен интернет), я нашёл только что они либо закрытые, либо предполагают внутреннее использование (в смысле внутри компании (с закрытой регистрацией), разработчики не менее чем одного найденный OpenSource CI сервера вполне предполагает, что он будет торчать в интернет). Я ещё посмотрел в сторону OpenSource облаков, но они слишком сложные.
Если ничего не найдено, то можно попытаться сделать так:
Пускать контейнер «без сети». Нет сети — не нужны настройки firewall для контейнера, и соответственно, не нужно думать, как объяснить firewall’у, чего вы от него хотите, если вы хотите чего‐то вроде «не более N запросов в секунду от одного пользователя».
В контейнере подменить библиотеки, работающие с сетью, на что‐то, что будет заворачивать запросы в stdout/unix socket/…, что общается с сервером, запустившим контейнер. Если подменить библиотеки нельзя, можно сделать виртуальный сетевой интерфейс, который будет делать то же самое, но уже ниже уровнем.
На сервере уже реализовать собственно общение с интернетом, со сбором интересных метрик и со своими ограничениями — по сути firewall будет тут.
Мне кажется, такой вариант проще в реализации, потому что серверу, запускающему контейнер уже отлично известно, почему (по какому запросу) он его запустил, так легче собрать метрики с привязкой к контейнерам/пользователям/запускаемому в контейнере коду.
Пускать контейнеры с сетью, но разобраться, как с клиентским доступом к сети работают облачные провайдеры.
Контейнеры имеют тенденцию со временем становиться более безопасными и простыми в использовании. Тот же play.rust-lang.org просто запускает docker с --net none, здесь сложно что‐то забыть или неправильно настроить.
В МИФИ кажется подобный реостат стоит в пульте управления высотой АРСА (к счастью, не для собственно управления высотой, а для управления величиной смещения при отображении высоты — т.е. по сути для указания нуля). Очень неудобно: если проскочить нужное значение и сдвинуть барабан грубой подстройки, то с высокой вероятностью на обратном ходе вы опять проскочите. Проблема в том, что, во‐первых, я не знаю, когда именно точной подстройки станет не хватать и я начну крутить грубую. Во‐вторых, я достаточно хорошо представляю, насколько нужно повернуть, если подстройка только точная — но если я поверну именно настолько, я рискую нарваться на поворот грубой подстройки далеко за нужное значение, соответственно крутить приходится весьма осторожно — и я всё равно часто промахиваюсь в обратном направлении (грубая подстройка здесь очень грубая). В‐третьих, из‐за разной реакции на поворот и того, что реостат всегда находится в положении, близком к нужному, я не представляю, насколько нужно повернуть, чтобы грубая подстройка оказалась там, где нужно. Я подозреваю, было бы удобно, если бы точная подстройка охватывала бо́льший диапазон значений.
Ссылка точно актуальна не для всех, но (не)нормальность компиляторов тут не причём — компиляторы C будут реализовывать используемый в целевой системе C ABI, если только не смогут доказать, что компилируемая функция никогда не будет вызвана извне (включая из другой единицы компиляции того же проекта).
компилятор вполне проглотит if (1) {}. Следующее выражение в этом случае не станет условным, как в случае совсем без скобок, но вот, например, echo 'int main(void) { if (1) {} }' | clang -std=c99 -pedantic -Wall -Weverything -xc - даже не производит никаких предупреждений.
После некоторого размышления у меня появилось сильное подозрение, что семантика let foo = bar; — это «создать новое местоfoo и переместить в него объект из bar» (объект один и тот же, но его переместили), а не «создать новый объект foo и переместить в него данные из bar, bar удалить» (есть два разных объекта с непересекающимися временами жизни). Я не могу найти конкретных подтверждений в документации (но то, как про перемещения объектов значений рассказывает документация std::pin оставляет ощущение, что я скорее прав), но let foo = foo точно не запускает Drop::drop и при этом никаких конструкторов в Rust нет. Можете обосновать утверждение «let mut rect = rect создаёт новый объект»?
Это с точки зрения семантики языка. С точки зрения программиста это часто один и тот же объект, т.к. нет видимой разницы (разные адреса, если оптимизатор почему‐то не смог убрать перемещение, не считаются). Это особенно верно, если под rect у нас не простая структура данных, а что‐то вроде Box<Rectangle>: кого волнует, где в стеке указатель на Rectangle, если данные всё равно за указателем и никуда не двигаются?
Явно видно непонимание иммутабельности. К примеру,
let rect = Rectangle::new().set_width(10).set_height(20).build();
// rect.width = 15; // ошибка, так как rect неизменяемый после создания
Во‐первых, код не работает. Вы не можете скормить .build()&mut self вместо self, а именно первое возвращает .set_height. Во‐вторых, build полностью бесполезна. Иммутабельность относится к конкретному месту размещения, если вы владеете объектом, то вы всегда можете сделать его мутабельным. Реальная иммутабельность достигается инкапсуляцией и удалением из общего доступа методов, которые могут изменить состояние объектов. Соответственно в шаблоне создатель у вас должен был быть тип RectangleBuilder и тип Rectangle, и только первый должен иметь методы set_width. Соответственно, говорить «создадим иммутабельную структуру», не объясняя нигде, что она иммутабельная только пока в общем доступе нет методов, её изменяющих, некорректно. Напомню, что вот это вполне себе корректный код:
let mut rect = Rectangle::new();
rect.set_width(10);
let rect = rect.build();
let rect = rect; // То же, что и строчка выше.
// rect.set_width(20); // Не скомпилируется.
let mut rect = rect;
rect.set_width(30); // А теперь мы опять можем менять rect.
Остальная часть не лучше. Например:
Если создается экземпляр структуры с помощью let, все его поля будут неизменяемыми, если только каждое поле явно не объявлено как mut:
Можете показать, как вы объявляете поля структуры как mut? Только так, чтобы результат компилировался.
Или «создадим глобально доступный Arc»: «код, в котором Arc нигде не упоминается».
Иммутабельность в Rust в нескольких предложениях:
Если вы не объявили что‐то, как mut, то взятие исключающей (&mut) ссылки вам недоступно, как и всё, что требует её взятия.
Изменение значения требует такой ссылки (или возможности её взятия) или внутренней мутабельности в каком‐то виде.
Исключающая ссылка гарантирует только, что объект больше никому не доступен. Разделяемая ссылка (&) гарантирует только, что на объект нет исключающих ссылок. Иммутабельность здесь вообще не причём, ссылки исторически назвали неправильно, но большинство типов компилятор позволит менять только по исключающей ссылке.
Я не уверен, что кто‐то всерьёз думает, что это именно защита: при наличии документации всё понятно по разводке платы. С микросхемами в корпусе «капля» и без документации немного сложнее, но не сильно, если есть достаточное представление о том, что должно быть на Flash.
Но вообще если есть какая‐нибудь память с интерфейсом вида «подал адрес на параллельную шину, зажал CS и OE, подождал, получил результат на параллельной шине», и эта память имеет как минимум 2^n «слов» (шириной в параллельную шину данных), то у неё можно свободно переставить n нижних бит адреса (как правило — все биты, мне пока не встречалась такая память с объёмом‐не степенью 2) и все биты данных, чтобы упростить разводку. Я сам так как‐то с SRAM делал. (С SRAM это может быть особенно просто: если данные туда пишет сам микроконтроллер, то не нужно даже думать о каких‐либо перестановках при программировании. У меня было не так, но проблемной частью было «как перебить подключённый микроконтроллер», а не «как переставить биты».)
Про удаление лишнего припоя с ножек: тут уже рекомендовали оплётку, но есть ещё одна особенность: если лишнего припоя мало и вы не можете ткнуть в него паяльником или оплёткой — и, главное, он где‐то за ножками и паяльником с нормальной температурой не нагревается, иногда имеет смысл добавить больше припоя. Огромная капля удаляется оплёткой с ножек без проблем, мелкая капля едва касающаяся чего‐либо паяльником не удаляется без добавления припоя в принципе: либо вы поглощаете её лишним припоем, либо можно попробовать много флюса и фен.
Нагревать паяльник выше той температуры, при которой вам комфортно паять ножки, для удаления мелкой капли не нужно. При использовании оплётки, если вы паяете на минимальной комфортной температуре, придётся добавить 20—30 ℃.
Я обычно паяю большим топориком (K) с 240 ℃ для микросхем с ножками, 250 ℃ для ёмкостей/… 0603—0805, подключающихся к огромным полигонам, 260—280 ℃ для танталовых конденсаторов и THD. Выше в специальных случаях. Если жало — не большой топорик, температура может потребоваться выше.
А относительно BGA: по‐моему вы ухудшили себе жизнь, не купив ИК станцию вместо столика с подогревом. У нас в компании BGA паяют без трафаретов и пасты: берём нормальный флюс (сейчас — Mechanic SD-360), мажем его очень тонким и ровным слоем по всем площадкам, ставим схему и греем ИК станцией. Работает как с золотым финишным покрытием (иммерсионное золото), так и с ПОС‐63 (или остатками шариков), но если ПОС‐63 появился после выпайки микросхемы, а не после завода, то его нужно аккуратно выровнять оплёткой (в плохих случаях: сначала паяльником смахнуть остатки шариков, а потом уже оплёткой), при этом не убрав этой оплёткой маску (что тем легче сделать, чем горячее паяльник) и не сорвав случайно площадки (что тем легче сделать, чем холоднее паяльник).
Трафарет понадобится, если нужно будет перенакатывать шарики. Или если вы всё же решите поставить по одному 0402 конденсатору под каждый шарик питания и у вас есть ИК станция.
В качестве бюджетной ИК можно брать Puhui T-962, но её придётся доработать (у нас это запасная станция на случай поломки основной). Доработать — это обклеить термоскотчем, изменить прошивку, добавить дополнительный температурный сенсор.
Такие костыли я видел. Они хорошо заметны, и они точно не могут привести к идентичным
$dir-fe(выводамgit fast-export).И в любом случае, напомню, что ветка началась с того, что я указал возможность сохранения информации о перемещениях в СКВ, хранящей слепки, и hg-git — это просто пример хранения этой информации в СКВ, хранящей слепки. Какими костылями он это делает неважно — это просто пример, что это сделать возможно, соответственно из «в гите как раз слепки хранятся» не может следовать, что гит «не умеет трекать перемещения» — он не умеет трекать перемещения, потому что его авторы решили не добавлять сохранение перемещений, а не потому что он хранит слепки.
Ваша ссылка относится к commit’ам, сделаным в git. У меня commit’ы, сделанные в mercurial, в которых уже есть информация о переименованиях и она должна быть частью commit’а и на стороне mercurial, и на стороне git, чтобы hg-git вообще работал: хэши commit’ов должны сохраняться при конвертации в любую сторону, чтобы можно было нормально работать, а не постоянно решать проблемы рассинхронизации. Можете проверить, например, так:
Скрипт
Здесь я клонировал репозиторий git «по сети» и сравнил вывод
hg log --followоригинального и склонированного репозитория. Они совпадают.Вообще‐то хранение слепков/разностей и возможность сохранения информации о перемещении файлов несколько ортогональны. Git вполне мог сохранять информацию о факте перемещения отдельно от самих слепков. Более того,
hg-gitотлично сохраняет куда‐то информацию о перемещениях. Я у себя проверил вот таким скриптом:Разница в том, что оказалось в git видна только в файлах
$dir-bundle,$dir-logсодержит только различающиеся хэши второго commit’а, а$dir-feидентичны, так что как достать эту информацию из git и как она вообще сохраняется мне не очевидно. Возможно, hg-git просто нашёл какой‐то способ хранения своих метаданных и git понятия не имеет, что они означают. Код [hg-]git я сейчас как‐то смотреть не хочу. Но факт тот, что в git вполне возможно сохранять информацию о переименованиях, хранение слепков этому не мешает.Del
То, что обычно, зависит от того, что вы делаете. Я занимаюсь испытанием микросхем на радиационную стойкость и я почти никогда не округляю до ближайшего значения: это либо округление вверх (параметр‐критерий годности, должный быть «не больше» какого‐то значения; требуемый уровень воздействия, …), либо вниз (… «не меньше»; уровень стойкости), либо «от центра» (параметры, которые одновременно не больше и не меньше) — т.е. что в данном контексте «более консервативно».
У Excel, кстати, функции для округления вверх и вниз до множителя определённого значения есть. А в LabVIEW, который часто используется испытательными центрами, почему‐то есть только округление до целых.
Ruby и Python — да. В javascript похоже засунули в стандарт оптимизацию, используемую для таблиц lua (скорее не саму оптимизацию, но её последствия в части того, как удобнее всего реализовывать итерацию по object): MDN в документации for..in утверждает
Где это написано в собственно спецификации ECMAScript я не нашёл, но в этом тексте написано сначала цифровые индексы по порядку, потом строковые ключи таки в порядке добавления.
В C#
DictionaryбезSortedне сортирует по ключам. ИнтерфейсMapв Java не требует определённого порядка. Если это более скриптовый язык, где словари являются частью основного синтаксиса, то внутри почти наверняка будет хэш‐таблица, которые с сортировкой по ключам не очень дружат.Собственно под «обычно» я думал скорее про них — я обычно использую Rust или такие скриптовые языки и в Rust есть, к примеру, HashMap и BTreeMap, но у обоих название вида ImplementationMap и нельзя сказать, что есть какие‐то предпочтения на уровне языка или стандартной библиотеки. HashMap, впрочем, используется чаще, потому что за сортировку по ключам вы платите скоростью всех операций в данном случае.
Это где так? Обычно итерация происходит в одном из двух порядков:
В порядке добавления ключей.
В неопределённом порядке, оно же в порядке, в каком данные располагаются в map (т.е. по сути что‐то вроде «в порядке возрастания остатков от деления хэшей на размер map», если не учитывать коллизий).
Оба порядка — это «в каком порядке удобно делать итерацию при данной реализации map», и «в порядке возрастания ключей» удобно делать, только если map — это дерево вроде BTreeMap, а не хэш‐таблица.
Помимо этого есть lua, где таблицы одновременно ещё и массивы и другие языки со схожими идеями, где, в зависимости от ключа, значение окажется либо во внутреннем массиве, либо в хэш‐таблице, но даже у lua порядок никак не гарантируется даже для числовых индексов (вероятно, т.к. вы вполне можете засунуть числовой индекс в хэш‐таблицу, а не в массив).
Для того, чтобы показать на форуме, как вы можете написать рекурсивный макрос или ещё чего интересное, достаточно. Если нужно какой‐то доступ к сети, я бы смотрел так:
Есть ли готовые пакеты с решением проблемы? Я не уверен, как сформулировать такой запрос, но когда я искал, а что делают сервисы CI (а они по сути как раз запускают у себя недоверенный клиентский код, которому нужен интернет), я нашёл только что они либо закрытые, либо предполагают внутреннее использование (в смысле внутри компании (с закрытой регистрацией), разработчики не менее чем одного найденный OpenSource CI сервера вполне предполагает, что он будет торчать в интернет). Я ещё посмотрел в сторону OpenSource облаков, но они слишком сложные.
Если ничего не найдено, то можно попытаться сделать так:
Пускать контейнер «без сети». Нет сети — не нужны настройки firewall для контейнера, и соответственно, не нужно думать, как объяснить firewall’у, чего вы от него хотите, если вы хотите чего‐то вроде «не более N запросов в секунду от одного пользователя».
В контейнере подменить библиотеки, работающие с сетью, на что‐то, что будет заворачивать запросы в stdout/unix socket/…, что общается с сервером, запустившим контейнер. Если подменить библиотеки нельзя, можно сделать виртуальный сетевой интерфейс, который будет делать то же самое, но уже ниже уровнем.
На сервере уже реализовать собственно общение с интернетом, со сбором интересных метрик и со своими ограничениями — по сути firewall будет тут.
Мне кажется, такой вариант проще в реализации, потому что серверу, запускающему контейнер уже отлично известно, почему (по какому запросу) он его запустил, так легче собрать метрики с привязкой к контейнерам/пользователям/запускаемому в контейнере коду.
Пускать контейнеры с сетью, но разобраться, как с клиентским доступом к сети работают облачные провайдеры.
Контейнеры имеют тенденцию со временем становиться более безопасными и простыми в использовании. Тот же play.rust-lang.org просто запускает docker с
--net none, здесь сложно что‐то забыть или неправильно настроить.Чтобы это не было тоннелем можно, как написали выше, использовать контейнеры. Как пример успешной реализации: https://play.rust-lang.org (https://github.com/rust-lang/rust-playground), можете поискать уязвимости и сообщить разработчикам, если найдёте. Использует docker.
Изменение усилия заметно, но изменение не такое уж и большое, а грубая подстройка в этом приборе весьма грубая.
В МИФИ кажется подобный реостат стоит в пульте управления высотой АРСА (к счастью, не для собственно управления высотой, а для управления величиной смещения при отображении высоты — т.е. по сути для указания нуля). Очень неудобно: если проскочить нужное значение и сдвинуть барабан грубой подстройки, то с высокой вероятностью на обратном ходе вы опять проскочите.
Проблема в том, что, во‐первых, я не знаю, когда именно точной подстройки станет не хватать и я начну крутить грубую. Во‐вторых, я достаточно хорошо представляю, насколько нужно повернуть, если подстройка только точная — но если я поверну именно настолько, я рискую нарваться на поворот грубой подстройки далеко за нужное значение, соответственно крутить приходится весьма осторожно — и я всё равно часто промахиваюсь в обратном направлении (грубая подстройка здесь очень грубая). В‐третьих, из‐за разной реакции на поворот и того, что реостат всегда находится в положении, близком к нужному, я не представляю, насколько нужно повернуть, чтобы грубая подстройка оказалась там, где нужно.
Я подозреваю, было бы удобно, если бы точная подстройка охватывала бо́льший диапазон значений.
Ссылка точно актуальна не для всех, но (не)нормальность компиляторов тут не причём — компиляторы C будут реализовывать используемый в целевой системе C ABI, если только не смогут доказать, что компилируемая функция никогда не будет вызвана извне (включая из другой единицы компиляции того же проекта).
Не факт. Если вы пишете со скобками так:
то да, но вот так:
компилятор вполне проглотит
if (1) {}. Следующее выражение в этом случае не станет условным, как в случае совсем без скобок, но вот, например,echo 'int main(void) { if (1) {} }' | clang -std=c99 -pedantic -Wall -Weverything -xc -даже не производит никаких предупреждений.После некоторого размышления у меня появилось сильное подозрение, что семантика
let foo = bar;— это «создать новое местоfooи переместить в него объект изbar» (объект один и тот же, но его переместили), а не «создать новый объектfooи переместить в него данные изbar,barудалить» (есть два разных объекта с непересекающимися временами жизни).Я не могу найти конкретных подтверждений в документации (но то, как про перемещения
объектовзначений рассказывает документацияstd::pinоставляет ощущение, что я скорее прав), ноlet foo = fooточно не запускаетDrop::dropи при этом никаких конструкторов в Rust нет. Можете обосновать утверждение «let mut rect = rectсоздаёт новый объект»?Это с точки зрения семантики языка. С точки зрения программиста это часто один и тот же объект, т.к. нет видимой разницы (разные адреса, если оптимизатор почему‐то не смог убрать перемещение, не считаются). Это особенно верно, если под
rectу нас не простая структура данных, а что‐то вродеBox<Rectangle>: кого волнует, где в стеке указатель наRectangle, если данные всё равно за указателем и никуда не двигаются?Явно видно непонимание иммутабельности. К примеру,
Во‐первых, код не работает. Вы не можете скормить
.build()&mut selfвместоself, а именно первое возвращает.set_height.Во‐вторых,
buildполностью бесполезна. Иммутабельность относится к конкретному месту размещения, если вы владеете объектом, то вы всегда можете сделать его мутабельным. Реальная иммутабельность достигается инкапсуляцией и удалением из общего доступа методов, которые могут изменить состояние объектов. Соответственно в шаблоне создатель у вас должен был быть тип RectangleBuilder и тип Rectangle, и только первый должен иметь методыset_width.Соответственно, говорить «создадим иммутабельную структуру», не объясняя нигде, что она иммутабельная только пока в общем доступе нет методов, её изменяющих, некорректно. Напомню, что вот это вполне себе корректный код:
Остальная часть не лучше. Например:
Можете показать, как вы объявляете поля структуры как
mut? Только так, чтобы результат компилировался.Или «создадим глобально доступный
Arc»: «код, в котором Arc нигде не упоминается».Иммутабельность в Rust в нескольких предложениях:
Если вы не объявили что‐то, как
mut, то взятие исключающей (&mut) ссылки вам недоступно, как и всё, что требует её взятия.Изменение значения требует такой ссылки (или возможности её взятия) или внутренней мутабельности в каком‐то виде.
Исключающая ссылка гарантирует только, что объект больше никому не доступен. Разделяемая ссылка (
&) гарантирует только, что на объект нет исключающих ссылок. Иммутабельность здесь вообще не причём, ссылки исторически назвали неправильно, но большинство типов компилятор позволит менять только по исключающей ссылке.