Страницы

Поиск по вопросам

понедельник, 20 мая 2019 г.

Откуда берутся нули? и как их убрать

Есть запрос к базе данных на вычисление процентов:
SELECT group, count, ROUND(count*100.0/ (SELECT sum(count) from table) ,2) as [%] FROM table
count типа int
В результате выводятся числа округленные до двух знаков после запятой, но с кучей нулей после 2 цифр. Можно ли как то убрать эти нули?


Ответ

Вам надо привести результат к типу с 2 знаками после запятой, например - numeric(18,2), где вторая цифра как раз определяет количество знаков после запятой. Итоговый запрос будет выглядеть вот так:
SELECT group, count, CAST(count*100.0/ (SELECT sum(count) from table) as numeric(18,2)) as [%] FROM table

Стоит ли создавать новый класс для вариации алгоритма?

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


Ответ

На мой взгляд лучше создать новый класс под каждый алгоритм.
Т.е. вы создаете интерфейс допустим такой:
interface AlgoritmExecutor{ execute(); }
И для каждого класса алгоритмов его реализуете, и сам алгоритм пишите в нем. В этом случае при добавлении нового алгоритма Вам надо будет написать новый класс, а не лезть в старый, добавляя новые условия.
Но остается вопрос как выбирать нужный класс. Тут моё предложение не лучшее. Создать фабрику, которая будет принимать пачку boolean за каждый чекбокс.
class AlgoritmFactory{ static AlgoritmExecutor chooseAlgoritm(boolean... checkbox){ //тут исходя из включенных чекбоксов выбираете нужный класс алгоритма } }

Это удобно тем, что в слое вида вы обращаетесь к фабрике, передаете ей все чекбоксы и получаете выбранный алгоритм в виде интерфейса.
public void algoritmAction(){ AlgoritmExecutor algoritm = AlgoritmFactory(checkbox1.isEnabled(), checkbox2.isEnabled(), checkbox3.isEnabled()); algoritm.execute(); }
но фабрика становится не очень понятна для стороннего читателя из-за пачки булевых значений.

Как отправить @Html.HiddenFor(m => item.Id) в контроллер?

@if (item.UserId == User.Identity.GetUserId().AsInt()) { using (Html.BeginForm("Delete", "Home", FormMethod.Post)) { @Html.AntiForgeryToken() @Html.HiddenFor(m => item.Id) } }
Вот сам вид в html view
[HttpPost] [Authorize] public ActionResult Delete(int Id) { var session = NHibernateHelper.GetCurrentSession(); try { using (var transaction = session.BeginTransaction()) {
DBNewsItem newItem = new DBNewsItem(); newItem.Id = Id; session.Delete(newItem); transaction.Commit(); } } finally { NHibernateHelper.CloseSession(); } return RedirectToAction("Index", "Home"); }
А вот контроллер, который должен принимать id. Почему ему ничего не приходит?


Ответ

Переделал вьюшку под
@Html.Hidden("Id", item.Id)
Потом передал через пост в контроллер
public ActionResult Delete(int id){...}
На прямую, через имя, обращаюсь Item.Id

Ошибка в консоли throw er; // Unhandled 'error' event ^ при использовании gulp

Учусь пользоватся gulp, при импортировании свойств из SASS в CSS, в консоли возникает такая ошибка:
C:\Users\serge\Desktop\Gulp>gulp sass [18:06:21] Using gulpfile ~\Desktop\Gulp\gulpfile.js [18:06:21] Starting 'sass'...
events.js:136 throw er; // Unhandled 'error' event ^ Error: app\sass\_part.sass Error: Invalid CSS after " font-size:": expected pseudoclass or pseudoelement, was "25px {} }" on line 2 of app/sass/_part.sass >> font-size:25px {} } -------------^
at options.error (C:\Users\serge\Desktop\Gulp
ode_modules
ode-sass\lib\index.js:291:26)
Код из файла JS (подозреваю что в нём где-то ошибка):
var gulp = require('gulp'), sass = require('gulp-sass');
gulp.task('sass', function() { return gulp.src('app/sass/**/*.sass') .pipe(sass()) .pipe(gulp.dest('app/css')) });


Ответ

Добавьте пробел:
font-size: 25px
Без пробела SASS воспринимает :25px как стейт (:hover) или как псевдокласс (::before)

Как растянуть svg маску по высоте?

Изображение обрезается, как растянуть svg маску по высоте?
Оригинал
.item { height: 500px; } .svg-mask { width: 100%; overflow: hidden; } .image-with-mask { width: 100%; height: auto; mask: url(#mask-wrapper); }



Ответ

Решил добавить новый ответ, чтобы не смешивать два разных подхода.
В первом ответе я обращал ваше внимание, что браузеры неодинаково рассчитывают позиционирование. Поэтому в хроме была лишняя обрезка.
Второй момент - в Firefox'e были заметны ступеньки, так происходит при сильном увеличении растровой картинки. Этот эффект возник потому-что вы натягивали маску шириной 200px на картинку шириной 1500px. Чтобы избавиться от этих двух нежелательных дефектов сделаем следующее.
Решение:
Перерисуем маску сравнимую по размерам с изображением
Открываем в векторном редакторе нужное изображение,
но не встраиваем его, а связываем, то есть в файле на выходе будет ссылка на это изображение:

Рисуем путь, который обеспечивает нужную форму маски:

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

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

Изображение адаптивно к разному размеру экрана.
Если необходимо будет, как-то изменить размеры изображения, то изменяйте width height в процентах шапке svg
width="100%" height="100%" viewBox="0 0 1500 843"

Как сделать ЧПУ через .htaccess или другим способом

Здравствуйте, подскажите как сделать ЧПУ через .htaccess или другим способом. На данный момент пытаюсь реализовать через .htaccess, но что-то не так.
Ситуация такая что использую одну точку входа через index.php, может это как-то влияет.
Вот .htaccess
RewriteEngine On RewriteBase / RewriteCond %{HTTPS} !=on RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] RewriteRule ^([a-z]+)/([a-z]+)/$ ?country=$1®ion=$2&city=$3 [QSA,L] RewriteRule .* index.php [L]


Ответ

Если у вас уже единая точка входа (это хорошо) и нет зависимости от .htaccess (это хорошо), то не надо добавлять зависимость от .htaccess и терять достоинства единой точки входа: весь роутинг в одном месте, независимость от сервера.
Разбирайте ваш URL прямо в index.php.
Подробнее: Как сделать всё и сразу в mod_rewrite?
P. S. Не могу закрыть как дубликат вопрос под конкурсом.
P. P. S. Уже ничего не помню про .htaccess, но в вашем коде, вроде, проблема в том, что все преобразования повешены на одно условие.

Агрегация и наследование

Можно ли два класса одновременно связать путем агрегации и наследования?


Ответ

Конечно, можно:
class Base { };
class Derived: public Base { Base b; };
int main(int argc, const char * argv[]) { Derived d; }

Декремент постфиксный как правильно его использовать

Объясните пожалуйста почему данный код, при использование постфиксного декремента
int a = 5;//Тут 4 int b = a-- - (a + 2);//Выполняем сначала в скобках так как приоритет //в скобках 7 и потом отнимает 4 + 7 = (-3) //Где я припустил
Console.WriteLine($"Var a: {a}
Var b: {b}"); string key = Console.ReadLine();
Выдает в переменной b результат -1
Когда при такой записи
int a = 5;//Тут после операции 6 int b = a++ + (a + 2); //Здесь 6 + (5+2) = 13
Console.WriteLine($"Var a: {a}
Var b: {b}"); string key = Console.ReadLine();
Результат a=6 b=13


Ответ

Операнды вычисляются в том порядке, в каком они идут в выражении:
int a = 5; int b = a-- - (a + 2);
a -> 5 - первый член в выражении a-- -> a становится 4 (a+2) -> 6 - второй член в выражении 5 - 6 -> -1 - результат

int a = 5; int b = a++ + (a + 2);
a -> 5 - первый член в выражении a++ -> a становится 6 (a+2) -> 8 - второй член в выражении 5 + 8 -> 13 - результат

C# интерфейсы и абстрактные классы

Доброго!
Есть интерфейс IInterface,
Есть абстрактный класс его реализующий AClass
И есть абстрактный класс
AClasses { List Elements;
void SomeMethod() { T _el = new T(); _el.Some(); Elements.Add(_el); } }
Вот в методе SomeMethod() проблема так как это сделать нельзя. T должен наследоваться от IInterface ну или на крайний случай от AClass.
Так вот вопрос. Как заполнить List Elements в абстрактном классе


Ответ

Например, при помощи ограничений на T
class AClasses where T : IInterface, new() { ...
Это будет работать, если у ваших классов есть пустой конструктор.
Если пустого конструктора нет, то создание экземпляров нужно делать как-нибудь по-другому, например, через фабрику или создающий делегат.

Optional и OptionalInt

В чём отличие Optional и OptionalInt, и в каких случаях какой из этих типов лучше применять?


Ответ

Отличие в том, что при наличии значения Optional.get вернет объект (Integer), а OptionalInt.getAsInt — примитивное значение (int).
Соответственно, чтобы избежать лишнего обертывания примитивных значений при работе с int применяется OptionalInt , а при работе с объектами Integer — Optional
Рассмотрим на примере интерфейса с двумя методами:
interface Test { int getInt(); Integer getInteger(); }
При обработке значений имеет смысл использовать соответствующие классы (на примере Stream API):
List list = //получаем список OptionalInt intFirst = list.stream().mapToInt(Test::getInt).findFirst(); Optional integerFirst = list.stream().map(Test::getInteger).findFirst();
Использование IntStream и OptionalInt для поля типа Integer потенциально приведет к NullPointerException. Использование Optional и Stream для int приведет к лишнему обертыванию значений.
Необходимость специальных классов обусловлена тем, что в Java примитивные типы не могут использоваться в качестве параметров обобщенных типов. Из за этого классы Stream и Optional не могут быть использованы для работы с примитивными значениями.
Использовать вместо примитивов классы-обертки непозволительно из-за затрат производительности на упаковку значений в объекты. Поэтому для часто используемых примитивных типов создан набор специальных классов: IntStream, LongStream, DoubleStream и OptionalInt, OptionalLong, OptionalDouble

Pandas при чтении CSV файла не парсит числа, содержащие запятую в качестве десятичного разделителя

Файл csv сохранен в LibreOffice из excel файла. При стандартной загрузке:
map_data = pd.read_csv('map.csv', sep=';')
в нужном столбце получаются данные типа - dtype: object Если попытаться их перевести в числовые:
pd.to_numeric(map_data['Dist_Loc'])
выдается следующая ошибка:
ValueError: Unable to parse string "3,095" at position 0
Если попытаться перевести в числовые другим способом:
map_data['Dist_Loc'].astype(np.float)
Тоже возникает ошибка:
ValueError: could not convert string to float: '6,157'


Ответ

Если 6,157 - это 6.157, т.е. - десятичный разделитель, то можно воспользоваться параметром decimal
df = pd.read_csv('map.csv', sep=';', decimal=',')
если это разделитель разрядов и 6,157 - это 6157, то можно воспользоваться параметром thousands
df = pd.read_csv('map.csv', sep=';', thousands=',')
Ссылка на документацию...
Pandas также замечательно читает напрямую из Excel
df = pd.read_excel(filename)

`+` (смежный селектор) и `>` (селектор непосредственного потомка) не работают вместе

Почему не работает селектор:
.parent > .child + .parent > .child { ... }
Сниппет:
.parent > .child + .parent > .child { color: green; }

текст

текст (почему не зелёный?)


Чтобы заработало можно заменить на .parent > .child + .child, но вопрос именно в том почему не работает исходная версия.


Ответ

В CSS нет никаких группировок, селекторы просто интерпретируются последовательно слева направо. Плюсик в вашем селекторе означает «следующий элемент после элемента .parent > .child»
.parent > .child + .parent > .child { color: green; }

Это .parent > .child
Это .parent > .child + .parent
Это .parent > .child + .parent > .child (зелёный!)

Авторизация в Steam на Delphi

Добрый день, есть желание из своей программы, написанной на Delphi, авторизоваться в Steam. Посмотрев исходники программы Steam Desktop Authenticator, пришел к выводу, что нам нужно сделать 2 POST-запроса к серверу Steam, первый вернет нам модуль и экспоненту открытого ключа RSA, которым мы должны зашифровать свой пароль и отправить его во втором запросе. Решил попробовать реализовать это с помощью функций Microsoft CryptoAPI: Next Generation. Набросал функцию, которая на входе получает 3 строки: пароль от Стима, открытые модуль и экспоненту в виде строк, состоящих из шестнадцатеричных символов (их нам присылает сервер). На выходе должны получить пароль, зашифрованный открытым ключом по алгоритму RSA и закодированный в BASE64.

unit uRSA;
interface uses WinAPI.Windows, System.SysUtils, VCL.Dialogs, System.NetEncoding;
//БЛОБ открытого ключа RSA, описание структуры есть на MSDN type TPublicKeyBLOB = packed record Magic: ULONG; BitLength: ULONG; cbPublicExp: ULONG; cbModulus: ULONG; cbPrime1: ULONG; cbPrime2: ULONG; exponent: array[0..2] of byte; modulus: array[0..255] of byte; end; pPublicKeyBLOB = ^TPublicKeyBLOB;
//прототипы функций из библиотеки BCRYPT.DLL TBCryptOpenAlgorithmProvider = function (phAlgorithm: pHandle; pszAlgId: LPCWSTR; pszImplementation: LPCWSTR; dwFlags: DWORD): ULONG; stdcall; //-- TBCryptImportKeyPair = function (hAlgorithm: THandle; hImportKey: THandle; pszBlobType: LPCWSTR; phKey: pHandle; pbInput: pPublicKeyBLOB; cbInput: ULONG; dwFlags: ULONG): ULONG; stdcall; //-- TBCryptEncrypt = function (hKey: THandle; pbInput: PUCHAR; cbInput: ULONG; pPaddingInfo: POINTER; pbIV: PUCHAR; cbIV: ULONG; pbOutput: PUCHAR; cbOutput: ULONG; pcbResult: PULONG; dwFlags: ULONG): ULONG; stdcall; //-- TBCryptCloseAlgorithmProvider = function (hAlgorithm: THandle; dwFlags: ULONG): ULONG; stdcall;
//сама функция шифрования type TRSA = class public function RSA_Encrypt(DataStr: string; modulusStr: string; exponentStr: string): string; end;
const BCRYPT_RSAPUBLIC_MAGIC = $31415352; // RSA1 BCRYPT_PAD_PKCS1 = $00000002;
implementation
function HexToByte(Str: string): Byte; begin result := Byte(StrToInt('$' + (Str))); end;
function TRsa.RSA_Encrypt(DataStr: string; modulusStr: string; exponentStr: string): string; var PublicKeyBLOB: TPublicKeyBlob; i: word; status: ULONG; hLib: THandle; hAlg: THandle; hKey: tHandle; Password: TBytes; EncryptedPassword: TBytes; EncryptedSize: ULONG; BCryptOpenAlgorithmProvider: TBCryptOpenAlgorithmProvider; BCryptImportKeyPair: TBCryptImportKeyPair; BCryptEncrypt: TBCryptEncrypt; BCryptCloseAlgorithmProvider: TBCryptCloseAlgorithmProvider; begin //преобразовываем входные данные в массив байтов; Password := TEncoding.ASCII.GetBytes(DataStr); hLib := LoadLibrary('BCRYPT.DLL'); //загрузка функций из библиотеки //функция инициализации провайдера @BCryptOpenAlgorithmProvider := GetProcAddress(hLib, 'BCryptOpenAlgorithmProvider'); //функция импорта ключа @BCryptImportKeyPair := GetProcAddress(hLib, 'BCryptImportKeyPair'); //функция шифрования @BCryptEncrypt := GetProcAddress(hLib, 'BCryptEncrypt'); //функция освобождения провайдера @BCryptCloseAlgorithmProvider := GetProcAddress(hLib, 'BCryptCloseAlgorithmProvider'); //собираем ключ with PublicKeyBLOB do begin Magic := BCRYPT_RSAPUBLIC_MAGIC; // RSA1; BitLength := SizeOf(Modulus)*8;//размер модуля в битах cbPublicExp := SizeOf(Exponent);//размер экспоненты в байтах cbModulus := SizeOf(Modulus);//размер модуля в байтах //(необязательно) проверим, что в переданных параметрах - четное количество символов if (length(exponentstr) mod 2) 0 then exponentstr := '0' + exponentstr; if (length(modulusstr) mod 2) 0 then modulusstr := '0' + modulusstr; for i := Low(exponent) to High(exponent) do exponent[i] := HexToByte(copy(exponentstr,i*2+1,2)); for i := Low(modulus) to High(modulus) do modulus[i] := HexToByte(copy(modulusstr,i*2+1,2)); end; //инициализация провайдера status := BCryptOpenAlgorithmProvider(@halg,'RSA',nil,0); //импорт ключа status := BCryptImportKeyPair(hAlg,0,'RSAPUBLICBLOB', @hKey, @PublicKeyBLOB, SizeOf(PublicKeyBLOB),0); //шифрование сообщения. Первый проход - получаем размер выходного буфера, второй - шифруем текст status := BCryptEncrypt(hKey, @Password[0], Length(Password), nil, nil, 0, nil, 0, @EncryptedSize, BCRYPT_PAD_PKCS1); SetLength(EncryptedPassword,EncryptedSize); status := BCryptEncrypt(hKey, @Password[0], Length(Password), nil, nil, 0, @EncryptedPassword[0], Length(EncryptedPassword), @EncryptedSize, BCRYPT_PAD_PKCS1); //кодируем зашифрованное сообщение в Base64 Result := TNetEncoding.Base64.EncodeBytesToString(EncryptedPassword); //освобождаем память status := BCryptCloseAlgorithmProvider(hAlg,0); FreeLibrary(hLib); end;
end.

Вроде бы все успешно отрабатывает, но, когда делаю POST-запрос с зашифрованным паролем к серверу STEAM - получаю в ответ: {"success":false,"requires_twofactor":false, "message":"The account name or password that you have entered is incorrect.", "clear_password_field":true,"captcha_needed":false,"captcha_gid":-1} На вход функции подаются строки в виде
"publickey_mod":"c152954756c74aee68ca1e6ac77bc71af6a93660bd56f1517e8141436b8fda4e32cc123ced02c0421a6a8d505dd25d07c4df9a25cf682799ea87ceb0eeaef7c7e71a8a30ec6c60d4dcfa8006a193f0b99958655894147b13d4f15285f9d7dc75baaa61b1b12265a303324c6b5e648bb272d87e0003295ca124e6e7a8a5ec45b9d2f1399e3ffbd0d9aec012afe1fbe65bfc9bd4c2087e7b7a73d2f9286e311e77341113f4cbde9a2a94141252e395e36bc2bf135ef38be90458090d6cd2c419e293a5dcf93bff3df2ca641edfb38ff85f6c9f8864f2905015cf34bd35d74e324f4a6a156c2462cfdd1c1fafb15567047a59b188c9f2a4f78157f2ec120ce09b5d", "publickey_exp":"010001"
Буду очень признателен, если кто-нибудь укажет на ошибку или даст совет: как в Delphi можно зашифровать сообщение, имея экспоненту и модуль открытого ключа RSA.


Ответ

Проблема была в некорректной работе
//кодируем зашифрованное сообщение в Base64 Result := TNetEncoding.Base64.EncodeBytesToString(EncryptedPassword);
Эта функция не убирает переносы строки, так что придется получившийся результат обработать дополнительно:
//кодируем зашифрованное сообщение в Base64 Result := TNetEncoding.Base64.EncodeBytesToString(EncryptedPassword); //удалим переносы строки Result := StringReplace(Result, #13#10, '',[rfReplaceAll]);
Либо же можно использовать аналогичную функцию из пакета Indy, которая работает верно:
uses IdCoderMIME, idcoder, idglobal; ... function MyFunc(): string; var Temp: TIdBytes; begin ... Result := TIdEncoderMIME.EncodeBytes(Temp); end;

Рабочий код :
unit uRSA;
interface uses WinAPI.Windows, System.SysUtils, VCL.Dialogs, System.NetEncoding;
//БЛОБ открытого ключа RSA, описание структуры есть на MSDN type TPublicKeyBLOB = packed record Magic: ULONG; BitLength: ULONG; cbPublicExp: ULONG; cbModulus: ULONG; cbPrime1: ULONG; cbPrime2: ULONG; exponent: array[0..2] of byte; modulus: array[0..255] of byte; end; pPublicKeyBLOB = ^TPublicKeyBLOB;
//прототипы функций из библиотеки BCRYPT.DLL TBCryptOpenAlgorithmProvider = function (phAlgorithm: pHandle; pszAlgId: LPCWSTR; pszImplementation: LPCWSTR; dwFlags: DWORD): ULONG; stdcall; //-- TBCryptImportKeyPair = function (hAlgorithm: THandle; hImportKey: THandle; pszBlobType: LPCWSTR; phKey: pHandle; pbInput: pPublicKeyBLOB; cbInput: ULONG; dwFlags: ULONG): ULONG; stdcall; //-- TBCryptEncrypt = function (hKey: THandle; pbInput: PUCHAR; cbInput: ULONG; pPaddingInfo: POINTER; pbIV: PUCHAR; cbIV: ULONG; pbOutput: PUCHAR; cbOutput: ULONG; pcbResult: PULONG; dwFlags: ULONG): ULONG; stdcall; //-- TBCryptCloseAlgorithmProvider = function (hAlgorithm: THandle; dwFlags: ULONG): ULONG; stdcall;
//сама функция шифрования type TRSA = class public function Encrypt(DataStr: string; modulusStr: string; exponentStr: string): string; end;
const BCRYPT_RSAPUBLIC_MAGIC = $31415352; // RSA1 BCRYPT_PAD_PKCS1 = $00000002; BCRYPT_RSA_ALGORITHM = 'RSA'; BCRYPT_RSAPUBLIC_BLOB = 'RSAPUBLICBLOB';
implementation
function HexToByte(Str: string): Byte; begin result := Byte(StrToInt('$' + (Str))); end;
function TRsa.Encrypt(DataStr: string; modulusStr: string; exponentStr: string): string; var PublicKeyBLOB: TPublicKeyBlob; i: word; status: ULONG; hLib: THandle; hAlg: THandle; hKey: tHandle; Password: TBytes; EncryptedPassword: TBytes; EncryptedSize: ULONG; BCryptOpenAlgorithmProvider: TBCryptOpenAlgorithmProvider; BCryptImportKeyPair: TBCryptImportKeyPair; BCryptEncrypt: TBCryptEncrypt; BCryptCloseAlgorithmProvider: TBCryptCloseAlgorithmProvider; begin //преобразовываем входные данные в массив байтов; Password := TEncoding.ASCII.GetBytes(DataStr); hLib := LoadLibrary('BCRYPT.DLL'); if hLib < 32 then begin ShowMessage('Error while loading BCRYPT.DLL!'); exit; end; //загрузка функций из библиотеки //функция инициализации провайдера @BCryptOpenAlgorithmProvider := GetProcAddress(hLib, 'BCryptOpenAlgorithmProvider'); //функция импорта ключа @BCryptImportKeyPair := GetProcAddress(hLib, 'BCryptImportKeyPair'); //функция шифрования @BCryptEncrypt := GetProcAddress(hLib, 'BCryptEncrypt'); //функция освобождения провайдера @BCryptCloseAlgorithmProvider := GetProcAddress(hLib, 'BCryptCloseAlgorithmProvider'); //собираем ключ with PublicKeyBLOB do begin Magic := BCRYPT_RSAPUBLIC_MAGIC; // RSA1; BitLength := SizeOf(Modulus)*8;//размер модуля в битах cbPublicExp := SizeOf(Exponent);//размер экспоненты в байтах cbModulus := SizeOf(Modulus);//размер модуля в байтах //(необязательно) проверим, что в переданных параметрах - четное количество символов if (length(exponentstr) mod 2) <> 0 then exponentstr := '0' + exponentstr; if (length(modulusstr) mod 2) <> 0 then modulusstr := '0' + modulusstr; for i := Low(exponent) to High(exponent) do exponent[i] := HexToByte(copy(exponentstr,i*2+1,2)); for i := Low(modulus) to High(modulus) do modulus[i] := HexToByte(copy(modulusstr,i*2+1,2)); end; //инициализация провайдера status := BCryptOpenAlgorithmProvider(@halg,BCRYPT_RSA_ALGORITHM,nil,0); if status <> 0 then begin ShowMessage('BCryptOpenAlgorithmProvider error, status: ' + IntToStr(status) + ', ' + SysErrorMessage(GetLastError())); exit; end; //импорт ключа status := BCryptImportKeyPair(hAlg,0,BCRYPT_RSAPUBLIC_BLOB, @hKey, @PublicKeyBLOB, SizeOf(PublicKeyBLOB),0); if status <> 0 then begin ShowMessage('BCryptImportKeyPair error, status: ' + IntToStr(status) + ', ' + SysErrorMessage(GetLastError())); exit; end; //шифрование сообщения. Первый проход - получаем размер выходного буфера, второй - шифруем текст status := BCryptEncrypt(hKey, @Password[0], Length(Password), nil, nil, 0, nil, 0, @EncryptedSize, BCRYPT_PAD_PKCS1); if status <> 0 then begin ShowMessage('BCryptEncrypt error 1, status: ' + IntToStr(status) + ', ' + SysErrorMessage(GetLastError())); exit; end; SetLength(EncryptedPassword,EncryptedSize); status := BCryptEncrypt(hKey, @Password[0], Length(Password), nil, nil, 0, @EncryptedPassword[0], Length(EncryptedPassword), @EncryptedSize, BCRYPT_PAD_PKCS1); if status <> 0 then begin ShowMessage('BCryptEncrypt error 2, status: ' + IntToStr(status) + ', ' + SysErrorMessage(GetLastError())); exit; end; //освобождаем занятые ресурсы status := BCryptCloseAlgorithmProvider(hAlg,0); if status <> 0 then begin ShowMessage('BCryptCloseAlgorithmProvider error, status: ' + IntToStr(status) + SysErrorMessage(GetLastError())); exit; end; //кодируем зашифрованное сообщение в Base64 Result := TNetEncoding.Base64.EncodeBytesToString(EncryptedPassword); //удалим переносы строки Result := StringReplace(Result, #13#10, '',[rfReplaceAll]); //выгружаем библиотеку FreeLibrary(hLib); end;
end.
На вход функции подаются строки в виде:
"publickey_mod":"c152954756c74aee68ca1e6ac77bc71af6a93660bd56f1517e8141436b8fda4e32cc123ced02c0421a6a8d505dd25d07c4df9a25cf682799ea87ceb0eeaef7c7e71a8a30ec6c60d4dcfa8006a193f0b99958655894147b13d4f15285f9d7dc75baaa61b1b12265a303324c6b5e648bb272d87e0003295ca124e6e7a8a5ec45b9d2f1399e3ffbd0d9aec012afe1fbe65bfc9bd4c2087e7b7a73d2f9286e311e77341113f4cbde9a2a94141252e395e36bc2bf135ef38be90458090d6cd2c419e293a5dcf93bff3df2ca641edfb38ff85f6c9f8864f2905015cf34bd35d74e324f4a6a156c2462cfdd1c1fafb15567047a59b188c9f2a4f78157f2ec120ce09b5d", "publickey_exp":"010001"

Таблица или ConstraintLayout?

Делаю первое приложение. Мне нужно, чтобы два таймера снизу - всегда находились в серединах двух половинок (по горизонтали). Иначе говоря, будто они в серединах двух столбцов таблицы. А черточки должны начинаться снизу, как на картинке. Пока работал только с ConstraintLayout, и уже замучился. У него привязка идет к краю элемента. Т.е. если размер элемента меняется, то все двигается, да и он сам не остается на месте. А у меня, например 01 час меняется на 1. В сторону чего мне смотреть?


Ответ

Для верстки такого макета на понадобятся опорные линии (guidline).
На макет размещаем три опорных линии (правый клик на визуальном редакторе разметки: Helpers -> Add vertical\horizontal guidelines): две вертикальных (1 и 2) и одну горизонтальную (3). Вертикальные делят экран на 3 равные части (33% и 66%), горизонтальная - верхнюю четверть (25%). Чтобы изменить позицию опорной линии на проценты нужно щелкать на кружок.

Теперь закрепляем виджеты. Левые счетчики крепим правым краем к первой опорной линии,левым краем к краю экрана (чтобы можно было провести черту до конца экрана). При этом верхний низом к 3 опорной линии, а нижний верхом к ней же. Этим виджетам ставим атрибут android:gravity="right", чтобы текст начинался от правого края. Правый счетчик крепим левой стороной ко второй опорной линии, правой стороной к краю экрана, а верхом и низом к верху и низу левого нижнего счетчика - так они будут располагаться на одном уровне по горизонтали. Кнопку и текст равномерно распределяем на оставшееся пространство по вертикали через инструмент chains (правая кнопка мыши: Center -> Center Verticaly).
Линии под счетчиками можно сделать, просто указав этим виджетам в качестве фона изображение 9-path с чертой снизу - это самый простой вариант (в примере я делать этого не буду).
Вот что в итоге получилось:

Разметка:







Как правильно задать тип chart-а c помощью delphi

Есть часть кода на Delphi:
chart:=sheet.chartobjects.add(270,205,397,220); chart.chart.charttype:=4; chart.Chart.SetSourceData(Sheet.Range['A3:B34']);
который выводит в Excel график (диаграмму):

Мне нужен другой тип графика, через макрос (excel-vba) он выглядит так:
ActiveSheet.Shapes.AddChart2(332, xlLineMarkersStacked).Select
Вопрос: какой код на Delphi должен выполняться вместо этой строчки, чтоб он вывел мне вот такой тип графика:


Ответ

Вам достаточно заменить
chart.chart.charttype:=4;
на
chart.chart.charttype:=66; // xlLineMarkersStacked = 66
чтобы сменить тип диаграммы на нужный.
Если часто приходится использовать построение диаграмм в Excel внутри Delphi-программ, стоит завести модуль, где будут перечислены основные константы. Вот все константы энумерации для диаграмм Excel, скопируйте их в новый юнит, оформите как const и вам проще будет транслировать макросы Excel в код Delphi.

Домены приложений и безопасность

В доменах приложений есть такая штука, как политики, которые позволяют ограничить домен в правах.
Например, запретить доступ к файловой системе.
Однако, работает ли это на практике?
Разве, когда делается Unwarp, то сборка из домена не загружается в основной домен?
=> если сборка вредоносная, то можно запихать в статический конструктор какую-то гадость, например format c => безопасность рушится, даже если домен был ограничен в правах.
Или не все так просто, или с доменами работают по другому?


Ответ

Да, Unwrap загрузит сборку и в основной домен тоже. Поэтому правильно делается по-другому:
создается в основной, доверенной, сборке класс-наследник MarshalByRefObject; экземпляр этого класса загружается в новом домене, и ему (доверенному экземпляру) делается Unwrap; все дальнейшее взаимодействие с объектами в новом домене делается через этот объект.

Для ситуации плагинов имеет смысл для каждого интерфейса, который может быть плагином реализован, подготовить свой кросс-доменный прокси для загрузки в домене плагина. В простейшем случае такой прокси будет просто делегировать все вызовы:
class FooCrossDomainProxy: MarshalByRefObject, IFoo { private readonly IFoo target;
public void FooCrossDomainProxy(IFoo target) { this.target = target; }
public void Bar() => target.Bar(); }
В более сложном случае этому прокси можно поручить адаптацию интерфейса к кросс-доменному взаимодействию. К примеру, поскольку вызовы между доменами медленные - имеет смысл снижать их число путем объединения методов:
class FooCrossDomainProxy: MarshalByRefObject { private readonly IFoo target;
public void FooCrossDomainProxy(IFoo target) { this.target = target; }
public bool TryBar() { if (!target.CanBar) return false;
target.Bar(); return true; } }

Оптимизация приложения под разные экраны (drawable)

Сразу извиняюсь за вопрос т.к. тема давно не новая, но всё же. Как подготовить drawable для разных экранов? Ведь диагональ может быть разной, а плотность пикселей одна и та же. И те рисунки что на экране 4.7-5 дюймов кажутся нормальными на экранах 7+ совсем мелкие. И еще вопрос можно ли квалификаторы указывать так (drawable-xlarge-xhdpi)?? Заранее спасибо за ответ!


Ответ

Для начальной подготовки drawable я бы посоветовал использовать ImageAsset в самой студии, это облегчит генерацию и вы увидите разницу на разных устройствах.
drawable-xlarge-xhdpi
Так можно использовать, так как это разные квалификаторы. Первый - отвечает за размер/диагональ экрана, второй - за плотность.
Тема, очень хорошо описана во многих источниках, а лучше сразу оф доки читать, там очень хорошо всё разъясняется. https://developer.android.com/guide/practices/screens_support.html

Как правильно получить все комбинации чисел в Python

Есть код:
import itertools
for i in itertools.combinations_with_replacement('0123456789', 4): print(''.join(i))
Мне нужно получить все комбинации цифр по 4 с повторениями. Часть вывода программы:
0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 0011 0012 0013 0014 0015 0016 0017 0018 0019 0022 0023 0024 0025
Скажите, почему после 0009 идет 0011, а не 0010 ? Также и с 0022


Ответ

Потому что для вашей задачи вам нужно брать не combinations_with_replacement, а product
import itertools
for i in itertools.product('0123456789', repeat=4): print(''.join(i))
Комбинации в комбинаторике не учитывают порядка элементов. Поэтому набор тех же элементов будет считаться одной и той же комбинацией, даже если элементы в другом порядке. Ваш код один раз уже напечатал комбинацию из трёх нулей и одной единицы (0001), поэтому он не будет уже печатать другие варианты этой комбинации - 0010, 0100 и 1000. Аналогично и с другими числами.

Гарантированнная доставка сообщения по протоколу TCP

Всем привет. Уже несколько дней ломаю голову над одной проблемой. Как то раз нашёл пример многопользовательского клиент-серверного консольного TCP чата. И если я не ошибаюсь, то протокол TCP не гарантирует доставку сообщения. И в случае если сообщение не будет доставлено полностью или доставлено вообще, то надо предпринять какие-то меры. Данная программа если я не ошибаюсь, не предпринимает никаких действий если сообщения не будет доставлено полностью. Вопрос: Какие меры надо предпринять чтобы обеспечить гарантированную доставку сообщения или же, что надо делать если сообщения не будет доставлено полностью? Или может быть программа принимает какие либо меры, если сообщение не будет доставлено полностью? Если не трудно, то покажите,что надо добавить в программу. Программа имеет 2 проекта Клиент и Сервер. Код Клиента: Класс Program:
using System; using System.Net.Sockets; using System.Text; using System.Threading;
namespace ChatClient { class Program { static string userName; private const string host = "192.168.0.107"; private const int port = 20113; static TcpClient client; static NetworkStream stream; // Создаём объект NetworkStream, через него можно отправлять сообщения серверу или наоборот получать
static void Main(string[] args) { Console.Write("Введите свое имя: "); userName = Console.ReadLine(); client = new TcpClient(); try { client.Connect(host, port); //подключение клиента stream = client.GetStream(); // возвращает объект NetworkStream
string message = userName; byte[] data = Encoding.Unicode.GetBytes(message); //Присваиваем массиву data перекодированное сообщение stream.Write(data, 0, data.Length); // Передаем массив data
// запускаем новый поток для получения данных Thread receiveThread = new Thread(new ThreadStart(ReceiveMessage)); receiveThread.Start(); //старт потока Console.WriteLine("Добро пожаловать, {0}", userName); SendMessage(); } catch (Exception ex) { Console.WriteLine(ex.Message); } finally { Disconnect(); } } // отправка сообщений static void SendMessage() { label1: Console.WriteLine("
Введите сообщение: "); while (true) { string message = Console.ReadLine(); byte[] data = Encoding.Unicode.GetBytes(message); if (message != "exit") { stream.Write(data, 0, data.Length); } else { message = "exit"; label2: Console.WriteLine("Вы действительно хотите выйти из чата Y / N:"); switch (Console.ReadKey().Key) { case ConsoleKey.Y: stream.Write(data, 0, data.Length); Disconnect(); break; case ConsoleKey.N: goto label1; default: Console.WriteLine("Введите Y / N
"); goto label2; } } } } // получение сообщений static void ReceiveMessage() { while (true) { try { byte[] data = new byte[64]; // буфер для получаемых данных StringBuilder builder = new StringBuilder(); int bytes = 0; do { bytes = stream.Read(data, 0, data.Length); builder.Append(Encoding.Unicode.GetString(data, 0, bytes)); } while (stream.DataAvailable);
string message = builder.ToString(); Console.WriteLine(message);//вывод сообщения } catch { Console.WriteLine("Подключение прервано!"); //соединение было прервано Console.ReadLine(); Disconnect(); } } } static void Disconnect() { Console.WriteLine("disconect"); if (stream != null) stream.Close();//отключение потока if (client != null) client.Close();//отключение клиента Environment.Exit(0); //завершение процесса } } }
Код Сервера: Класс ServerObject:
using System; using System.Collections.Generic; using System.Linq; using System.Net.Sockets; using System.Net; using System.Text; using System.Threading;
namespace ChatServer { public class ServerObject { static TcpListener tcpListener; // сервер для прослушивания List clients = new List(); // все подключения protected internal void AddConnection(ClientObject clientObject) { clients.Add(clientObject); } protected internal void RemoveConnection(string id) { // получаем по id закрытое подключение ClientObject client = clients.FirstOrDefault(c => c.Id == id); // и удаляем его из списка подключений if (client != null) clients.Remove(client); } // прослушивание входящих подключений protected internal void Listen() { try { tcpListener = new TcpListener(IPAddress.Any, 8888); tcpListener.Start(); Console.WriteLine("Сервер запущен. Ожидание подключений..."); while (true) { TcpClient tcpClient = tcpListener.AcceptTcpClient(); //Приём ожидающего запроса на подключение ClientObject clientObject = new ClientObject(tcpClient, this); Thread clientThread = new Thread(new ThreadStart(clientObject.Process)); clientThread.Start(); } } catch (Exception ex) { Console.WriteLine(ex.Message); Disconnect(); } } // трансляция сообщения подключенным клиентам protected internal void BroadcastMessage(string message, string id) { byte[] data = Encoding.Unicode.GetBytes(message); for (int i = 0; i < clients.Count; i++) { if (clients[i].Id != id) // если id клиента не равно id отправляющего { clients[i].Stream.Write(data, 0, data.Length); //передача данных } } } // отключение всех клиентов protected internal void Disconnect() { tcpListener.Stop(); //остановка сервера
for (int i = 0; i < clients.Count; i++) { clients[i].Close(); //отключение клиента } Environment.Exit(0); //завершение процесса } } }
Класс ClientObject:
using System; using System.Net.Sockets; using System.Text;
namespace ChatServer { public class ClientObject { protected internal string Id { get; private set; } protected internal NetworkStream Stream { get; private set; } string userName; TcpClient client; ServerObject server; // объект сервера
public ClientObject(TcpClient tcpClient, ServerObject serverObject) { Id = Guid.NewGuid().ToString(); client = tcpClient; server = serverObject; serverObject.AddConnection(this); }
public void Process() { try { Stream = client.GetStream(); // получаем имя пользователя string message = GetMessage(); userName = message; string s = new String('*', 6); message = userName + " вошел в чат"; // посылаем сообщение о входе в чат всем подключенным пользователям server.BroadcastMessage(message, this.Id); Console.WriteLine(message); // в бесконечном цикле получаем сообщения от клиента while (true) { try { message = GetMessage(); if (message == "exit") { message = String.Format($"{s}{userName}: покинул чат{s}"); Console.Write(message); server.BroadcastMessage(message, this.Id); break;
} else { message = String.Format($"{userName}: {message}"); Console.WriteLine(message); server.BroadcastMessage(message, this.Id); } } catch { message = String.Format($"{s}{userName}: покинул чат{s}"); Console.Write(message); server.BroadcastMessage(message, this.Id); break; } } } catch (Exception e) { Console.WriteLine(e.Message); } finally { // в случае выхода из цикла закрываем ресурсы server.RemoveConnection(this.Id); Close(); } }
// чтение входящего сообщения и преобразование в строку private string GetMessage() { byte[] data = new byte[64]; // буфер для получаемых данных StringBuilder builder = new StringBuilder(); int bytes = 0; do { bytes = Stream.Read(data, 0, data.Length); builder.Append(Encoding.Unicode.GetString(data, 0, bytes)); } while (Stream.DataAvailable);
return builder.ToString(); }
// закрытие подключения protected internal void Close() { if (Stream != null) Stream.Close(); if (client != null) client.Close(); } } }
Класс Program:
using System; using System.Threading;
namespace ChatServer { class Program { static ServerObject server; // сервер static Thread listenThread; // потока для прослушивания static void Main(string[] args) { try { server = new ServerObject(); listenThread = new Thread(new ThreadStart(server.Listen)); listenThread.Start(); //старт потока } catch (Exception ex) { server.Disconnect(); Console.WriteLine(ex.Message); } } } }
Пытался сделать так как посоветовал PashaPash, но всё без результатно. Как мне посоветовал PashaPash я добавил признак окончания сообщения '/'
do { } while (bytes==(byte)'/');
Если я правильно понял данные должны считываться как-то с помощью StreamReader Но как накапливать данные в MemoryStream не очень понятно?


Ответ

TCP гарантирует доставку.
Проблема в вашем коде в том, что он предполагает, что то, что передано в один вызов Write, будет вычитано одним вызовом Read на другой стороне. А это не так.
Write не "отправляет пакет". Он просто пишет данные в сокет.
А Read не "читает пакет". Он вычитывает из буфера сокета то, что успело дойти.
Если вы сделали два вызова Write, подождали, и сделали один Read - вычитаются данные обоих вызовов.
Если вы сделали вызов Write, и данные не успели дойти - Read вычитает только начало (начало строки, в вашем случае).
Обработка в цикле с builder.Append - ненадежна, т.к. ваш код читает из локального буфера, очень быстро (быстрее, чем данные идут по сети!), и достигает состояния !Stream.DataAvailable где-то на середине сообщения. Кроме того, он считает, что каждый результат Read может быть преобразован в Unicode строку. И никак не учитывает, что может получить фрагмент с половиной символа в конце или начале.
Надежные способы, на выбор:
Передавать перед каждым сообщением его длину. Не читать напрямую из Stream - обернуть его в BinaryReader, и читать длину (reader.ReadInt32()), потом - ровно столько байт, сколько нужно (reader.GetBytes(messageLength) будет ждать, пока не придет нужное количество байт). Или использовать binaryWriter.Write(message) / binaryReader.ReadString(), который автоматически делают то же самое за вам. Ввести признак окончания сообщения, например символ переноса строки. Читать до тех пор, пока в прочитанном фрагмент нет соответствующего байта (а не по Stream.DataAvailable). И при этом накапливать вычитанное в MemoryStream, в виде байт чтобы избежать проблем с половиной юникодового символа. В конце преобразовывать в строчку все сообщение целиком.
Пример на коде из вопроса (с минимальными изменениями):
Клиент - просто заменяете работу со stream на работу с reader / writer:
using System; using System.IO; using System.Net.Sockets; using System.Text; using System.Threading;
namespace ChatClient { class Program { static string userName; private const string host = "127.0.0.1"; private const int port = 8888; static TcpClient client; static BinaryReader reader; static BinaryWriter writer;
static void Main(string[] args) { Console.Write("Введите свое имя: "); userName = Console.ReadLine(); client = new TcpClient(); try { client.Connect(host, port); //подключение клиента var stream = client.GetStream(); // возвращает объект NetworkStream reader = new BinaryReader(stream, Encoding.Unicode, true); writer = new BinaryWriter(stream, Encoding.Unicode, true);
writer.Write(userName);
// запускаем новый поток для получения данных Thread receiveThread = new Thread(new ThreadStart(ReceiveMessage)); receiveThread.Start(); //старт потока Console.WriteLine("Добро пожаловать, {0}", userName); SendMessage(); } catch (Exception ex) { Console.WriteLine(ex.Message); } finally { Disconnect(); } }
// отправка сообщений static void SendMessage() { label1: Console.WriteLine("
Введите сообщение: "); while (true) { string message = Console.ReadLine(); if (message != "exit") { writer.Write(message); } else { message = "exit"; label2: Console.WriteLine("Вы действительно хотите выйти из чата Y / N:"); switch (Console.ReadKey().Key) { case ConsoleKey.Y: writer.Write(message); Disconnect(); break; case ConsoleKey.N: goto label1; default: Console.WriteLine("Введите Y / N
"); goto label2; } } } } // получение сообщений static void ReceiveMessage() { while (true) { try { string message = reader.ReadString(); Console.WriteLine(message);//вывод сообщения } catch { Console.WriteLine("Подключение прервано!"); //соединение было прервано Console.ReadLine(); Disconnect(); } } } static void Disconnect() { Console.WriteLine("disconect"); if (client != null) client.Close();//отключение клиента Environment.Exit(0); //завершение процесса } } }
Сервер - то же самое, с указанием той же кодировки:
using System; using System.Collections.Generic; using System.Linq; using System.Net.Sockets; using System.Net; using System.Text; using System.Threading;
namespace ChatServer { public class ServerObject { static TcpListener tcpListener; // сервер для прослушивания List clients = new List(); // все подключения protected internal void AddConnection(ClientObject clientObject) { clients.Add(clientObject); } protected internal void RemoveConnection(string id) { // получаем по id закрытое подключение ClientObject client = clients.FirstOrDefault(c => c.Id == id); // и удаляем его из списка подключений if (client != null) clients.Remove(client); } // прослушивание входящих подключений protected internal void Listen() { try { tcpListener = new TcpListener(IPAddress.Any, 8888); tcpListener.Start(); Console.WriteLine("Сервер запущен. Ожидание подключений..."); while (true) { TcpClient tcpClient = tcpListener.AcceptTcpClient(); //Приём ожидающего запроса на подключение ClientObject clientObject = new ClientObject(tcpClient, this); Thread clientThread = new Thread(new ThreadStart(clientObject.Process)); clientThread.Start(); } } catch (Exception ex) { Console.WriteLine(ex.Message); Disconnect(); } } // трансляция сообщения подключенным клиентам protected internal void BroadcastMessage(string message, string id) { for (int i = 0; i < clients.Count; i++) { if (clients[i].Id != id) // если id клиента не равно id отправляющего { clients[i].SendMessage(message); //передача данных } } } // отключение всех клиентов protected internal void Disconnect() { tcpListener.Stop(); //остановка сервера
for (int i = 0; i < clients.Count; i++) { clients[i].Close(); //отключение клиента } Environment.Exit(0); //завершение процесса } } }
using System; using System.IO; using System.Net.Sockets; using System.Text;
namespace ChatServer { public class ClientObject { protected internal string Id { get; private set; } string userName; TcpClient client; ServerObject server; // объект сервера BinaryWriter writer;
public ClientObject(TcpClient tcpClient, ServerObject serverObject) { Id = Guid.NewGuid().ToString(); client = tcpClient; server = serverObject; serverObject.AddConnection(this); }
public void Process() { try { var stream = client.GetStream();
this.writer = new BinaryWriter(stream, Encoding.Unicode, false); var reader = new BinaryReader(stream, Encoding.Unicode, false); // получаем имя пользователя string message = reader.ReadString();
userName = message; string s = new String('*', 6); message = userName + " вошел в чат"; // посылаем сообщение о входе в чат всем подключенным пользователям server.BroadcastMessage(message, this.Id); Console.WriteLine(message); // в бесконечном цикле получаем сообщения от клиента while (true) { try { message = reader.ReadString(); if (message == "exit") { message = String.Format($"{s}{userName}: покинул чат{s}"); Console.Write(message); server.BroadcastMessage(message, this.Id); break;
} else { message = String.Format($"{userName}: {message}"); Console.WriteLine(message); server.BroadcastMessage(message, this.Id); } } catch { message = String.Format($"{s}{userName}: покинул чат{s}"); Console.Write(message); server.BroadcastMessage(message, this.Id); break; } } } catch (Exception e) { Console.WriteLine(e.Message); } finally { // в случае выхода из цикла закрываем ресурсы server.RemoveConnection(this.Id); Close(); } }
internal void SendMessage(string message) { this.writer.Write(message); }
public void Close() { if (client != null) client.Dispose(); } } }

Расхождение результата с верным при вычислении среднего из ряда чисел

Задача состоит в том, чтобы вывести среднее из ряда чисел. Дается несколько рядов чисел, каждый из которых оканчивается нулем, и этот ноль не должен использоваться в решении (видимо, ноль в конце добавляют, чтобы удобно было разделять строки).
Проблема у меня в том, что значение, которое получаю в своем решении, незначительно отличается от верного ответа для каждого ряда чисел (у меня значение получается больше).
Т.е. я упустил какую-то мелочь в своем алгоритме решения:
public static void main(String[] args) { Scanner scanner = new Scanner(System.in); LinkedList list = new LinkedList<>(); int result = 0; int a; for (int i = 0; i < 2; i++) { do { a = scanner.nextInt(); list.add(a); for (Integer element : list) { //получаю сумму всех элементов result += element; } result = result / list.size() - 1; // пытаюсь вычислить среднее
} while (a != 0); System.out.print(result + " "); list.clear(); result = 0; } }
P.S. Если в строке, где я пытаюсь вычислить среднее, list.size - 1 заключить в скобки, то выдаст ArithmeticException
Пример вводных данных :
401 1766 40 1011 313 1038 1346 2002 1966 335 55 679 0 348 468 214 286 221 169 363 490 1 358 265 0


Ответ

Для получения среднего арифметического группы чисел нужно их сумму разделить на их количество. Причем делить нужно итоговую сумму на итоговое количество, а не после ввода каждого числа.
В итоге код получается такой:
Scanner scanner = new Scanner(System.in); for (int i = 0; i < 2; i++) { int sum = 0; int count = 0; int number = scanner.nextInt(); while (number != 0) { sum += number; count++; number = scanner.nextInt(); } System.out.print((sum / count) + " "); }
Если нужно только среднее арифметическое, то сохранять все числа в список смысла нет.
Если результат должен быть не целочисленным, то можно рассчитать его как double, например так:
System.out.print((1.0 * sum / count) + " ");
И наконец, если результат должен быть округлением точного значения до ближайшего целого числа, то можно воспользоваться Math.round
System.out.print(Math.round(1.0 * sum / count) + " ");

Если же числа нужны для чего-то ещё, то можно добавлять их в список, а среднее арифметическое считать с использованием Stream-ов из Java 8:
Scanner scanner = new Scanner(System.in); for (int i = 0; i < 2; i++) { List numbers = new ArrayList<>(); int number = scanner.nextInt(); while (number != 0) { numbers.add(number); number = scanner.nextInt(); } System.out.print(numbers.stream().mapToInt(e -> e).average().orElse(0) + " "); }
И целочисленный вариант:
System.out.print((int)numbers.stream().mapToInt(e -> e).average().orElse(0) + " ");

Насчет java.lang.ArithmeticException: / by zero: на первой итерации у вас один элемент в списке. Соответственно, list.size() равен 1, и деление значения result на 1 с последующим вычитанием 1 проходит вполне успешно. Чего не сказать о случае result / (list.size() - 1), ибо в этом случае сначала из 1 вычитается 1, а потом происходит попытка разделить значение result на получившийся 0

Группировка с зависимой максимизацией двух столбцов (без подзапросов)

Есть задача вывести все строки, группируя таблицу по столбцу t_name, при этом максимизируя по двум столбцам t_date и t_num, так что
вначале максимизируя по столбцу t_num затем оставшаяся выборка максимизируется по t_date
Вопрос: можно ли это организовать без подзапросов (например, оконными функциями или другими способами), и будет ли это работать быстрее?
Для примера
t_name t_date t_num 1 aaa 20.01.2018 3 2 aaa 03.01.2018 10 3 aaa 01.01.2018 10 4 aaa (null) 10 5 bbb 19.01.2018 1 6 bbb (null) 10
в результате максимизации по столбцу t_num останутся значения
t_name t_date t_num 2 aaa 03.01.2018 10 3 aaa 01.01.2018 10 4 aaa (null) 10 6 bbb (null) 10
затем выборку максимизируется по столбцу t_date и останутся значения
t_name t_date t_num 2 aaa 03.01.2018 10 6 bbb (null) 10
Это легко можно сделать через подзапросы
SELECT T.T_NAME, MAX(T.T_DATE) AS T_DATE, G.T_NUM FROM TEST_GROUPING T INNER JOIN ( SELECT T_NAME, MAX(T_NUM) AS T_NUM FROM TEST_GROUPING GROUP BY T_NAME ) G ON G.T_NAME = T.T_NAME AND G.T_NUM = T.T_NUM GROUP BY T.T_NAME, G.T_NUM


Ответ

Да, оконными функциями делается элементарно:
with t (t_name, t_date, t_num) as ( select 'aaa', to_date('20.01.2018', 'dd.mm.yyyy'), 3 from dual union all select 'aaa', to_date('03.01.2018', 'dd.mm.yyyy'), 10 from dual union all select 'aaa', to_date('01.01.2018', 'dd.mm.yyyy'), 10 from dual union all select 'aaa', null, 10 from dual union all select 'bbb', to_date('20.01.2018', 'dd.mm.yyyy'), 1 from dual union all select 'bbb', null, 10 from dual) select t_name, t_date, t_num from (select t_name, t_date, t_num, row_number() over (partition by t_name order by t_num desc, t_date desc nulls last) rn from t) where rn = 1
Работать тоже должно быстро, особенно если у вас есть индекс по t_num, а лучше даже по (t_num, t_date).

Uniform initialization

В С++11 появился новый синтаксис инициализации. Вот что по этому поводу пишет Скотт Майерс в книге Effective Modern C++:
class Widget { public: Widget(); // default ctor Widget(std::initializer_list il); // std::initializer_list ctor … // no implicit conversion funcs };
Widget w1; // calls default ctor Widget w2{}; // also calls default ctor Widget w3(); // most vexing parse! declares a function!
Widget w4({}); // calls std::initializer_list ctor with empty list Widget w5{{}}; // ditto
Если взять его пример, выкинуть лишнее, и добавить печать в конструктор Widget, то окажется что Widget w4({}); и Widget w5{{}}; это не одно и то же:
#include #include
class Widget{ public: Widget(){
} Widget(std::initializer_list l){ std::cout << "l.size = " << l.size() << std::endl; } };
int main(){ Widget w4({}); //l.size = 0 Widget w5{{}}; //l.size = 1 }
Пример
У меня два вопроса:
Скотт нас обманывает? Что происходит на самом деле?


Ответ

Widget(std::initializer_list l)//Это initializer-list constructor
Следуя стандарту, он имеет приоритет над другими конструкторами в list-initialization
Initializer-list constructors are favored over other constructors in list-initialization (16.3.1.7)
Widget w4({});
Это direct-initialization. Инициализатор - пустой std::initializer_list
Widget w4{{}};
Это уже list-initialization. В данном случае direct-list-initialization
Если список инициализации пуст, то выбирается конструктор по-умолчанию. Если же список инициализации не пуст, то конструктор выбирается в две фазы:
Initially, the candidate functions are the initializer-list constructors (11.6.4) of the class T and the argument list consists of the initializer list as a single argument If no viable initializer-list constructor is found, overload resolution is performed again, where the candidate functions are all the constructors of the class T and the argument list consists of the elements of the initializer list.
Начинаем первую фазу "ручного" поиска подходящего конструктора. В первой фазе все аргументы рассматриваются как один initializer list
Если рассмотреть скобочки в инициализаторе как создание std::initializer_list, то можно ли создать std::initializer_list, передав ему {}? Да, можно
std::initializer_list{{/*вот он наш единственный int со значением 0*/}}`
Всё, подходящий конструктор найден.
То есть в нашем случае
Widget w5{{}}; //приведет к такому --> Widget w5(std::initializer_list{int{}});
Или еще примеры:
Widget w5{{1}, {2}};//--> Widget w6(std::initializer_list{int{1}, int{2}}); Widget w7{{1, 2}};//--> Widget w8(std::initializer_list{std::initializer_list{1, 2}});
Старался объяснить как можно проще, поэтому, изложение "своими словами" может быть не совсем точным.

Общие параметры

Можно ли задать параметры для всех Button/text/Label одной функцие, чтобы не писать к каждой кнопке одинаковые параметры? К примеру, я создал много однотипных кнопок для ввода данных калькулятора:
bttn1_1 = Button(root, text='MC', font='Arial 15', width=3, height=1, bd=4, background='SkyBlue2', activebackground='green yellow')


Ответ

Примерно так можно:
buttons = {}
for button_text in map(str, range(10)): button = Button(root, text=button_text, font='Arial 15', width=3, height=1, bd=4, background='SkyBlue2', activebackground='green yellow') buttons[button_text] = button
Кнопка с текстом 1
buttons['1']

Еще можно создать функцию которая обрезает/исправляет параметры:
def create_button(text): return Button(root, text=text, font='Arial 15', width=3, height=1, bd=4, background='SkyBlue2', activebackground='green yellow')

Как сделать бэкграунд

Не могу понять каким образом создавать подобные бэкграунды не используя заранее заготовленное изображение.


Ответ

Что-то похожее
.variant1,.variant2{ height:50vh; border:1px solid; } .variant1{ background:repeating-linear-gradient(-45deg, #6ac4e6 200px,#61c0e7 250px); } .variant2{ background:linear-gradient(-45deg,#6ac4e6 47%,#61c0e7 50%); background-size:50px 50px; }


Лямбда-выражения и управляемый код

Имеется класс C++, написанный с применением управляемого кода. И вот нелегкая привела меня вызвать в данном классе в одном из методов любой из std::algorithm. Так вот, студия любезно указала, что лямбда - выражения использовать нельзя. Пришлось написать класс, и сделать его функтором. Так вот вопрос - почему запрещены лямбды?
Код:
public ref class edit_base { public: void test() { std::string line("abcdefg"); std::string lineNew; std::copy_if(line.begin(), line.end(), std::back_inserter(lineNew), [](const char& s) { if (s > 10 && s < 100) return true; return false; }); } }
Пишу через 17 студию. Компилятор: 19.11.25547
Error: E2093 локальное лямбда-выражение не допускается в функции-члене класса управляемый


Ответ

Да, это так. Лямбды компилируются как нативный локальный класс/структура, а такого не может быть внутри управляемого класса.
Поэтому придётся вынести нужный метод наружу:
ref class edit_base;
void test(edit_base^ self) { // тут можно обращаться к полям класса (если надо, объявите эту функцию friend'ом) std::string line("abcdefg"); std::string lineNew; std::copy_if(line.begin(), line.end(), std::back_inserter(lineNew), [](const char& s) { if (s > 10 && s < 100) return true; return false; }); }
public ref class edit_base { public: void test() { ::test(this); } };

Можно ли установить `inputType` для клавиатуры в WebView?

В апплекации есть реализация WebView в котором есть поля для заполнения. Так вот вопрос в том, можно ли, чтоб при нажатии юзером на поле с указанием номера телефона открывалась клавиатура с типом android:inputType="number" ?


Ответ

Попробуйте так
Создайте подкласс WebView и переопределите метод onCreateInputConnection. Этот метод вызывается при выборе поля ввода в WebView и дает возможность настроить способ обработки события.
@Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { BaseInputConnection ic = new BaseInputConnection(this, true); outAttrs.inputType = InputType.TYPE_CLASS_NUMBER; // Tells the keyboard to show the number pad return ic; }
Источник

Как сделать блок ссылкой?

Тернарный оператор вместо конструкции if-else

Можно ли улучшить(упростить) данную конструкцию тернарным оператором?
if (isLeftLetter && isRightLetter) { swap(chars, leftElementIndex, rightElementIndex); leftElementIndex++; rightElementIndex--;
} else { if (!isLeftLetter) { leftElementIndex++; }
if (!isRightLetter) { rightElementIndex--; } }


Ответ

Я бы написал так:
if (isLeftLetter && isRightLetter) { swap(chars, leftElementIndex, rightElementIndex); leftElementIndex++; rightElementIndex--;
} else { leftElementIndex=(!isLeftLetter) ? leftElementIndex+1 : leftElementIdex; rightElementIndex=(!isRightLetter) ? rightElementIndex+1 : rightElementIdex; }
Update
Тернарный оператор удобно использовать для однострочных присвоений, а ля:
var=(condition) ? expression1 : expression2;
в остальных вариантах, я лично не рекомендую (верю, что некоторые не согласятся)

Перенаправление стандартного потока вывода процессу в другом терминале

Надо перенаправить поток вывода какой-нибудь команды процессу в другом терминале, например cat. В свою очередь, он должен перенаправить свой вывод в следующий терминал. Пути решения нашел, например, здесь
Пробую. Запускаю процесс:
~$ tty /dev/pty1 ~$ cat > /dev/pty2
Посылаю сообщение:
~$ tty /dev/pty0 ~$ echo "Hi from $(tty)" > /dev/pty1
Но моё сообщение я вижу в первом терминале, а не во втором как ожидал:
~$ tty /dev/pty1 ~$ cat > /dev/pty2 Hi from /dev/pty0
~$ tty /dev/pty2 ~$
Почему второе перенаправление не работает?


Ответ

У меня так: Первый терминал /dev/pts/0, второй - /dev/pts/1
На втором запускаю cat:
# cat < /dev/pts/0
На первом:
# echo “hi” > /dev/pts/1
В результате hi появляется во втором терминале. А в приведенной вами ссылке лучше работать через proc и дескрипторы, так как задача передать вывод процессу, а не просто в терминал.
Update
Все, что написано выше решает только задачу "отобразить вывод в другом терминале" и не решает "перенаправить поток вывода процессу в другом терминале". Соответственно, и никакие дальнейшие передачи (по другим терминалам) не получатся.
Как быть?
Мне кажется проще всего это делать через named-pipe (mkfifo) (через несколько каналов, например). Но если хочется через стандартные редиректы-каналы, то есть вариант написать немного трэша.
Для примера пишем скрипт echo.sh
#!/bin/bash
while read std do echo "$std +" done
и запускаем его в одном из терминалов (например, в /dev/pts/4) следующим образом:
$ cat - | ./echo.sh
В другом терминале (пусть будет /dev/pts/0) ищем pid процесса echo.sh, пусть он равен 23441. И в этом же терминале делаем так:
$ echo "Hi again" > /proc/23441/fd/0
Смотрим результат в терминале /dev/pts/4:
Hi again +
и это означает, что скрипт принял таки вывод с другого терминала и добавил к сообщению "+".
По этой схеме можно передавать в следующий терминал. Возможно есть и более элегантное решение.
Update 2. Три терминала
Сделаем тоже самое с тремя терминалами pts/0, pts/1, pts/2. Сначала делаем копию echo.sh с именем echo2.sh. echo2.sh запускаем в pts/2:
$ cat - | ./echo2.sh
затем идем в pts/1 и находим pid процесса echo2.sh, пусть будет 31677. Теперь в pts/1 запускаем команду:
$ cat - | ./echo.sh | tee >/proc/31677/fd/0 >(cat)
в этой конструкции я использовал tee только ради наглядности примера, чтобы отобразить будущий вывод в данном терминале. Если задачи отображения нет, то и tee не надо. И наконец идем в первый терминал pts/0. В нем ищем pid процесса echo.sh, пусть будет 31715, и запускаем команду:
$ echo "Hello world" > /proc/31715/fd/0
Проверяем результат в остальных терминалах. Во втором будет Hello world +, в третьем - Hello world + +

Форматирование дат и чисел в тексте

Суть задачи: Есть текст в котором есть даты разного формата 12/9/2010, 15.09.10, 16-09-10, также есть суммы формата 2 300 530 belarusian roubles, 2 351 dollars, 232 500 blr. Нужно все даты привести к виду September 12, 2010, а из сумм, где есть belarusian roubles или blr убрать пробелы, суммы dollars оставить как есть. И вывести весь текст с форматированными датами и суммами. Для разбора текста использовать регулярные выражения. Вот что есть:
public void convertingText (String fileName){ try (BufferedReader reader = new BufferedReader( new InputStreamReader( new FileInputStream(fileName), StandardCharsets.UTF_8))){ String line; Pattern p = Pattern.compile("\\d?\\d[-/.]\\d?\\d[-/.]\\d\\d\\d?\\d?"); Pattern p1 = Pattern.compile("(\\d[\\d ]*\\d|\\d+) *(bel|blr)");
while ((line = reader.readLine()) != null) { Matcher m = p.matcher(line); Matcher m1 = p1.matcher(line); if (m.find()) { //Тут должно быть форматирование даты } if (m1.find()) { //Тут форматирование суммы } System.out.println(line); } } catch (FileNotFoundException e) { System.out.println("File not found."); } catch (IOException e){ e.printStackTrace(); } }
– correct dates in the format: dayXmonthXyear, where the day – one or two digits, month – one or two digits, year – two or four digits, X – the delimiter character (point, forward slash or hyphen);
Initial file in.txt I was 2 300 530 belarusian roubles and 2 351 dollars 12/9/2010. After shopping 15.09.10 I was left with 1 700 250 blr and 2 000$. After shopping 16.09.10 I was left with 1 7 00 2 500 blr. 232 500 blr and 10 blr.
Result file in.txt I was 2300530 belarusian roubles and 2 351 dollars September 12, 2010. After shopping September 15, 2010 I was left with 1700250 blr and 2 000$. After shopping September 16, 2010 I was left with 17002500 blr. 232500 blr and 10 blr. Не могу разобраться как сразу все даты привести к одному виду и как убрать пробелы.


Ответ

Исхожу из того, что проблем в поиске дат и валют в тексте у вас не возникло, это следует из вопроса.
Для того , чтобы даты привести к одному виду лично я бы сделал так:
Найденную в тексте дату передаем в такое выражение в переменной stringDate.
LocalDate parse = LocalDate.parse(stringDate, DateTimeFormatter.ofPattern("dd/M/yyyy")); После этого в переменной parse получаем дату, которую с помощью тех же паттернов легко преобразовываем в нужный нам вид с помощью такого кода
String result = parse.format(DateTimeFormatter.ofPattern("MMMM dd, yyyy", Locale.ENGLISH));
Теперь в переменной result получаем дату в нужном формате.
Соответственно, вы напишите разные регулярные выражения для разных форматов дат. При парсе даты будете также использовать разные паттерны "dd.MM.yy", "dd-MM-yy" и т.д. Я думаю, что идея Вам понятна.
Что касается дат, последнее замечание... Паттерн "dd/M/yyyy" не сработает с датой 12/11/2013, потому как месяц указан здесь двумя цифрами, а не одной. Решение проблемы - написание разных регулярных выражений. Альтернатива - оценивать длину переменной типа стринг, передаваемой в паттерн, исходя из чего использовать два разных паттерна - "dd/M/yyyy" и "dd/MM/yyyy".
Что касается замены пробелов, то тут все проще. Находите нужное значение, вызываете у стринговой переменной, в которой записано найденное занчение, метод replace (" ", ""); и получаете запись без пробела.
Вот альтернатива. После выявления даты с помощью регулярки вызываете нижеописаный метод.
private String parseDate (String textDate){ String[] split = textDate.split("\\.|\\-|\\/"); Integer year = Integer.valueOf(split[2].trim()); if (year > 20 && year<1900) year = 1900 + year; else if (year < 20) year = 2000 + year; LocalDate parse =LocalDate.of(year, Integer.valueOf(split[1].trim()), Integer.valueOf(split[0].trim())); return parse.format(DateTimeFormatter.ofPattern("MMMM dd, yyyy", Locale.ENGLISH)); }
Если хотите анализировать строку на наличие пробелов и т.д., то, скорее всего, проще пройтись по массиву чаров. Не очень лаконично, но есть полный контроль над результатом. Примерно так
private String convertText (String data){ StringBuilder sb = new StringBuilder(); boolean firstLatter = true; for (char ch : data.toCharArray()) { if (Character.isDigit(ch)) sb.append(ch); if (Character.isLetter(ch)) { if (firstLatter) { sb.append(" ").append(ch); firstLatter = false; } else sb.append(ch); } } return sb.toString(); }

Signed Int32 из двух байт

Есть строка из Java приложения, которая формирует signed INT из двух байт массива:
final int size = array[0] & 0x00FF | array[1] << 8;
где, array[0] равно 0x08, array[1] равно 0xEE. Этот код формирует число -4600
Но C# формирует совсем иное число из аналогичного кода:
int size = array[0] & 0x00FF | array[1] << 8;
Но этот код формирует число 60936
Подскажите, в чём соль между этими языками и как решить такую проблему.


Ответ

В этой строке
final int size = array[0] & 0x00FF | array[1] << 8;
значение выражения записывается в int (4 байта). Это значит, что все операнды преобразовываются в четырехбайтовые значения.
Расширение разрядности в Java происходит путем копирования старшего бита в исходном числе на расширяемые биты.
Итого у Вас было
final int size = 0x08 & 0x00FF | 0xEE << 8;
или в двоичном виде
final int size = 0000_1000b & 0000_0000_0000_0000_0000_0000_1111_1111b | 1110_1110b << 8;
теперь, что получается при расширении
final int size = 0000_0000_0000_0000_0000_0000_0000_1000b & 0000_0000_0000_0000_0000_0000_1111_1111b | 1111_1111_1111_1111_1111_1111_1110_1110b << 8;
В c# такого копирования старшего бита не происходит. (скорее всего там приводится к типу не операнды, а итоговый результат)
Если Вы хотите на Java избежать такого расширения, то применяйте к каждой байтовой переменной операцию побитового И с 0xFF
final int size = array[0] & 0xFF | (array[1] & 0xFF) << 8;
тогда при расширении получится
final int size = 0000_0000_0000_0000_0000_0000_0000_1000b & 0000_0000_0000_0000_0000_0000_1111_1111b | ( 1111_1111_1111_1111_1111_1111_1110_1110b & 0000_0000_0000_0000_0000_0000_1111_1111b ) << 8; final int size = 0000_0000_0000_0000_0000_0000_0000_1000b | 0000_0000_0000_0000_0000_0000_1110_1110b << 8;

Правильный тип для String int double boolean

Задача стоит в проектировании БД для интернет магазина.
У каждого товара есть набор характеристик (связь многие ко многим разбивается через промежуточную табличку). У сущности "характеристика" есть кроме id еще String name и ??? value
Вопрос в том, какой лучше тип выбрать для value ?? пока склоняюсь к типу String, в который можно писать все вышеперечисленные типы. Еще есть мысли по поводу не заморачиваться и написать туда Object или Serializible.
С точки зрения проектирования какое решение будет правильнее?
Spring Boot (Spring JPA)


Ответ

Еще есть мысли по поводу не заморачиваться и написать туда Object или Serializible.
А заморочиться придется...
Это ровно та задача, которая стоит перед любым разработчиком универсальной структуры данных. Путь известен и проторен не одним десятком прогеров, включая и меня самого. Основные положения:
Типизация (без него никуда), с основными типами: целое, с плавающей точкой, булевая, дата, строка. Ну может еще что-то. Реализация типа на уровне класса
Если подробнее то примерно так (простейшая реализация для двух типов строка и целое число):
abstract class MyType { abstract void setValue(int value); abstract void setValue(String value); abstract String getValue(); } class MyTypeString extends MyType { private String valueString=null;
@Override void setValue(int value) { valueString=new StringBuilder().append(value).toString(); }
@Override void setValue(String value) { valueString=value; }
@Override String getValue() { return value; } }
class MyTypeInt extends MyType { private Integer valueInt=null;
@Override void setValue(int value) { valueInt=value; }
@Override void setValue(String value) { try { int val=Integer.parseInt(value); valueInt=new Integer(val); } catch(Exception ex) { valueInt=null; } }
@Override String getValue() { return new StringBuilder().append(valueInt).toString(); } }

как замерить время выполнения функции Android Studio?

есть ряд процедур как выявить самую долгую?
сейчас делаю так
long p0 = System.currentTimeMillis(), p1,p2,p3; proc1(); pt1 = System.currentTimeMillis()-p0; proc2(); pt2 = System.currentTimeMillis()-p0-p1; proc3(); pt3 = System.currentTimeMillis()-p0-p1-p2;
в Android Studio может есть встроенный функционал?


Ответ

Попробуйте с помощью TimingLogger
TimingLogger timings = new TimingLogger(TAG, "methodA"); // ... do some work A ... timings.addSplit("work A"); // ... do some work B ... timings.addSplit("work B"); // ... do some work C ... timings.addSplit("work C"); timings.dumpToLog();
На выходе
D/TAG ( 3459): methodA: begin D/TAG ( 3459): methodA: 9 ms, work A D/TAG ( 3459): methodA: 1 ms, work B D/TAG ( 3459): methodA: 6 ms, work C D/TAG ( 3459): methodA: end, 16 ms

Не меняется курсор в FireFox

По событию mousedown создаётся под указателем новый элемент со своим набором стилей, в том числе собственный вид курсора.
$(document).ready(function() { $("input").on("mousedown", function() { $("body").append("

") }); $(document).on("mouseup", function() { $("div.resizable").remove(); }); }); .resizable { width: 100px; height: 100px; position: absolute; top: 5px; left: 5px; cursor: move; background: #eee; }
В Chrome и IE всё работает как надо, а вот Firefox вредничает: курсор остаётся тем же, что был до mousedown


Ответ

Судя по всему, FF показывает курсор input'а до тех пор, пока нажата кнопка. Можно попробовать исправить так (но код с mouseup кривой - надеюсь, он тут для примера):
$(document).ready(function() { $("input").on("mousedown", function() { $(this).addClass("move-cursor") $("body").append("

") }); $(document).on("mouseup", function() { $(this).removeClass("move-cursor") $("div.resizable").remove(); }); }); .resizable { width: 100px; height: 100px; position: absolute; top: 5px; left: 5px; cursor: move; background: #eee; } .move-cursor { cursor: move; }

Префикс не связан c пространством имён SVG

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


А вот в EDGE && IE просто пустота без всяких ошибок. Не смотря на ошибку, я вопрос в любом случае хотел написать, так как хотел спросить помощи в разъяснении логики построение координат атрибута d элемента path, но тут получается два вопроса в одном...

Коллеги, вопрос, что эта за ошибка у меня и как ее исправить, с утра не могу справиться с ней?

И может кто разъяснить хотя бы приблизительно какая координата атрибута d элемента path за что отвечает?
Lorem ipsum dolor sit amet consectetur.


Ответ

#1.
Немного уточню вопрос. Сообщение об ошибке появляется при открытии файла с расширением *.svg Если точно такой же код SVG сохранить с расширением *.html то сообщения об ошибке не будет.
В современных браузерах html парсер, если есть ошибки в svg коде пропускает их и выполняет код дальше. В вашем коде не указано пространство имен XML. Парсер svg считает это ошибкой и останавливает выполнение файла.
Необходимо добавить в шапку svg файла строчки определяющие namespace xml:
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
и тогда ваш код будет работать в любом окружении. Lorem ipsum dolor sit amet consectetur.
Отсюда вытекает практический совет,- делать отладку svg кода в его родном окружении, то есть в файле с расширением *.svg и только потом добавлять код в html страничку.
#2.
И может кто разъяснить хотя бы приблизительно какая координата атрибута d элемента path за что отвечает?
d="M0.057,0.024c0,0,10.99,51.603,102.248,51.603c91.259,0,136.172,53.992,136.172,53.992" />
M (moveto) - переместить перо в точку с координатами (X,Y) 0.057,0.024 c с этого символа начинается формула кубической кривой Безье – The cubic Bezier curve

Как перемещать приложение, если шапка с кнопками управления окна (закрыть/свернуть/расширить) скрыта

Как скрыть верхнюю шапку где находятся кнопки управления приложения (закрыть/свернуть/расширить), но в тоже время можно было бы перемещать приложение.
Как саму шапку скрыть я понял, но как сделать чтобы можно было бы при этом перемещать приложение
import sys from PyQt5 import QtWidgets, QtCore
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QMainWindow() w.setWindowFlags(QtCore.Qt.FramelessWindowHint) w.show() sys.exit(app.exec_())


Ответ

Пример:
from PyQt5.QtWidgets import QWidget, QApplication from PyQt5.QtCore import Qt
class Widget(QWidget): def __init__(self): super().__init__()
self.setWindowFlags(Qt.FramelessWindowHint)
self.old_pos = None
def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self.old_pos = event.pos()
def mouseReleaseEvent(self, event): if event.button() == Qt.LeftButton: self.old_pos = None
def mouseMoveEvent(self, event): if not self.old_pos: return
delta = event.pos() - self.old_pos self.move(self.pos() + delta)
if __name__ == '__main__': app = QApplication([])
w = Widget() w.show()
app.exec()

Равенство 4 текстовых значений

Почему 1 == 1 == 1 == 1 выдает результат true, а 'knx' == 'knx' == 'knx' == 'knx' выдает результат false


Ответ

потому что 1 это ещё и true. попробуйте так 2 == 2 == 2 == 2 - будет false
работает примерно так:
(1 == 1) == 1 == 1 итого (true) == 1 == 1 далее ((true) == 1 ) == 1 - тоже true (так как 1 это true). Ну и так далее...
'knx' == 'knx' == 'knx' == 'knx' : 'knx' == 'knx' == 'knx' == 'knx' -> (true) == 'knx' == 'knx' -> (true == 'knx') - false