Quantcast
Channel: Cool Software Blog
Viewing all 78 articles
Browse latest View live

VPN через Amazon EC2

$
0
0
Отличная инструкция по настройке VPN через Amazon EC2: https://dxdt.ru/2012/08/06/5063/.

Два замечания:

1. Если отсутствует файл /etc/VPNCA/CA/index.txt, то может вылезти ошибка на шаге выпуска сертификата:

# openssl ca -config openssl.vpn.cnf -policy policy_anything -out certs/vpn-node.crt -infiles vpn-node.csr

Чтобы ее не было надо создать пустой index.txt:

# touch /etc/VPNCA/CA/index.txt

2. Нужно обратить внимание на следующую строчку в конфигурационном файле named.conf:

listen-on port 53 { localhost; };

Должно быть именно localhost, а не 127.0.0.1, иначе DNS в OpenVPN-соединении работать не будет.

===
Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru

[Delphi XE2] Indy Parse Cookie Bug

$
0
0
В Delphi XE2 отыскался баг в TIdCookie.ParseServerCookie. Смотрим код:


functionGetLastValueOf(const AName:String;var VValue:String):Boolean;
var
I:Integer;
begin
Result:=False;
for I := CookieProp.Count-1downto0do
begin
if TextIsSame(CookieProp.Names[I], AName) then
begin
{$IFDEF HAS_TStrings_ValueFromIndex}
VValue := CookieProp.ValueFromIndex[I];
{$ELSE}
VValue :=Copy(CookieProp[I],Pos('=', CookieProp[I])+1, MaxInt);{Do not Localize}
{$ENDIF}
Result:=True;
Exit;
end;
end;
end;

...

if GetLastValueOf('MAX-AGE', S) thenbegin{Do not Localize}
FPersistent :=True;
FExpires :=StrToFloat(S);
end
elseif GetLastValueOf('EXPIRES', S) then{Do not Localize}
begin
FPersistent :=True;
FExpires :=StrToFloat(S);
endelse
begin
FPersistent :=False;
FExpires :=EncodeDate(9999,12,31) +EncodeTime(23,59,59,999);
end;

if GetLastValueOf('DOMAIN', S)then{Do not Localize}
begin

{
If the user agent is configured to reject "public suffixes" and
the domain-attribute is a public suffix:

If the domain-attribute is identical to the canonicalized
request-host:

Let the domain-attribute be the empty string.

Otherwise:

Ignore the cookie entirely and abort these steps.

NOTE: A "public suffix" is a domain that is controlled by a
public registry, such as "com", "co.uk", and "pvt.k12.wy.us".
This step is essential for preventing attacker.com from
disrupting the integrity of example.com by setting a cookie
with a Domain attribute of "com". Unfortunately, the set of
public suffixes (also known as "registry controlled domains")
changes over time. If feasible, user agents SHOULD use an
up-to-date public suffix list, such as the one maintained by
the Mozilla project at <http://publicsuffix.org/>.
}
end;

ifLength(S) >0then
begin
ifnot IsDomainMatch(AURI.Host, S) thenbegin
Exit;
end;
FHostOnly :=False;
FDomain := S;
endelse
begin
FHostOnly :=True;
FDomain := CanonicalizeHostName(AURI.Host);
end;

Ошибка происходит если строка S после вызова GetLastValueOf('EXPIRES', S) содержит что-нибудь (Length(S) > 0), а GetLastValueOf('DOMAIN', S) возвращает False.

Такое случается, если на вход TIdCookie.ParseServerCookie поступает строка ACookieText типа такой:

CookieName=CookieValue;Path=/;Expires=Wed, 20-Aug-2017 02:20:00 GMT;

Интересно, что ошибки бы не случилось, если бы параметр VValue у функции GetLastValueOf был объявлен как out, а не как var.

Fix. Для исправления этого бага я сделал класс TVCookieManager, который служит заменой для TIdCookieManager. Взять можно тут: https://github.com/coolsoftware/VCookieManager.
Использовать так:

var
FixedCookieManager: TVCookieManager;
IdHTTP: TIdHTTP;

...

FixedCookieManager := TVCookieManager.Create;
IdHTTP := TIdHTTP.Create;
IdHTTP.CookieManager := FixedCookieManager;


===
Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru

MiniDLNA: refresh files and folders structure

$
0
0
Как обновить структуру файлов и каталогов в MiniDLNA:

sudo service minidlna stop
sudo rm -rf /var/cache/minidlna/files.db
sudo service minidlna restart

UPD.

sudo /etc/init.d/minidlna restart
sudo /etc/init.d/minidlna force-reload

===
Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru

AHCI

$
0
0
Wiki: "Advanced Host Controller Interface (AHCI) — механизм, используемый для подключения накопителей информации по протоколу Serial ATA, позволяющий пользоваться расширенными функциями, такими, как встроенная очерёдность команд (NCQ) и горячая замена."

Как включить:

Windows 7

1. В реестре в разделе HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\msachi установить значение параметра "Start" (REG_DWORD) равным 0 (по-умолчанию Start=3).

2. В реестре в разделе HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\iaStorV установить значение параметра "Start" (REG_DWORD) равным 0 (по-умолчанию Start=3).

3. В BIOS включить режим AHCI вместо IDE.

Windows 10

1. В реестре в разделе HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\iaStorV установить значение параметра "Start" (REG_DWORD) равным 0.

2. В реестре в разделе HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\iaStorAV\StartOverride установить значение параметра "0" равным 0 (по-умолчанию значение этого параметра равно 3).

3. В реестре в разделе HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\storachi\StartOverride установить значение параметра "0" равным 0 (по-умолчанию значение этого параметра равно 3).

4. В BIOS включить режим AHCI вместо IDE.

CentOS 7

1. Выполнить:

sudo modprobe ahci
sudo cp /boot/initramfs-`uname -r`.img /boot/initramfs-`uname -r`.img.bak
sudo mkinitrd -f --with=ahci /boot/initramfs-`uname -r`.img `uname -r`

2. В BIOS включить режим AHCI вместо IDE.

===
Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru

[Delphi XE2] MD4/MD5 Bug on x64

$
0
0
В библиотеке Indy, которая поставляется с  Delphi XE2 под 64-битной платформой, имеется баг в вычислении MD4/MD5 (компоненты TIdHashMessageDigest4, TIdHashMessageDigest5 соответственно).

Вот код для вычисления MD5:

varmd5indy:TIdHashMessageDigest5;sMD5:String;beginmd5indy:=TIdHashMessageDigest5.Create;sMD5:=md5indy.HashStringAsHex('123456');md5indy.Free;end;

Под Win32 результат будет: 'e10adc3949ba59abbe56e057f20f883e' (правильно)
Под Win64 результат будет: '6e692400e5c684b74314252e341b92c7' (ошибка)

Этот баг был исправлен в более поздних версиях версиях Indy/Delphi (не скажу точно, в какой именно, в Delphi 10.2 Tokyo его нет).

Баг в asm-функциях ROL и ROR в модуле IdGlobalProtocols. Вот как они выглядят в XE2:

// Arg1=EAX, Arg2=DL functionROL(constAVal:LongWord;AShift:Byte):LongWord;assembler;asm mov cl, dl rol eax, cl end;functionROR(constAVal:LongWord;AShift:Byte):LongWord;assembler;asm mov cl, dl ror eax, cl end;{$ENDIF}

А вот так это выглядит в Delpgi 10.2 Tokyo:

// 32-bit: Arg1=EAX, Arg2=DL // 64-bit: Arg1=ECX, Arg2=DL functionROL(constAVal:UInt32;AShift:Byte):UInt32;assembler;asm{$IFDEF CPU64} mov eax, ecx {$ENDIF} mov cl, dl rol eax, cl end;functionROR(constAVal:UInt32;AShift:Byte):UInt32;assembler;asm{$IFDEF CPU64} mov eax, ecx {$ENDIF} mov cl, dl ror eax, cl end;

Чтобы можно было генерировать MD4/MD5 в XE2 под Win64 без установки новой версии Indy, я сделал модуль IdHashMessageDigestEx с "исправленными" классами TIdHashMessageDigest4Ex и TIdHashMessageDigest5Ex, которыми следует пользоваться вместо TIdHashMessageDigest4 и TIdHashMessageDigest5 соответственно. Замечу, что в XE2 не работает макрос CPU64 (как в более поздних версиях Delphi), а работает CPUX64.

unitIdHashMessageDigestEx;interfaceusesIdFIPS,IdHashMessageDigest;type{$IFDEF VER230}//XE2 TIdHashMessageDigest4Ex=class(TIdHashMessageDigest4)protectedprocedureMDCoder;override;end;TIdHashMessageDigest5Ex=class(TIdHashMessageDigest4Ex)protectedprocedureMDCoder;override;functionInitHash:TIdHashIntCtx;override;publicclassfunctionIsIntfAvailable:Boolean;override;end;{$ELSE}TIdHashMessageDigest4Ex=TIdHashMessageDigest4;TIdHashMessageDigest5Ex=TIdHashMessageDigest5;{$ENDIF}implementation{$IFDEF VER230}//XE2 {$IFDEF NO_NATIVE_ASM)}//XE2 usesIdGlobalProtocols;{$ELSE}// 32-bit: Arg1=EAX, Arg2=DL // 64-bit: Arg1=ECX, Arg2=DL functionROL(constAVal:LongWord;AShift:LongWord):LongWord;assembler;asm{$IFDEF CPUX64} mov eax, ecx {$ENDIF} mov cl, dl rol eax, cl end;{$ENDIF}{ TIdHashMessageDigest4Ex }{$Q-}// Arithmetic operations performed modulo $100000000 procedureTIdHashMessageDigest4Ex.MDCoder;varA,B,C,D,i:LongWord;buff:T16x4LongWordRecord;// 64-byte buffer beginA:=FState[0];B:=FState[1];C:=FState[2];D:=FState[3];fori:=0to15dobeginbuff[i]:=FCBuffer[i*4+0]+(FCBuffer[i*4+1]shl8)+(FCBuffer[i*4+2]shl16)+(FCBuffer[i*4+3]shl24);end;// Round 1 { Note: (x and y) or ( (not x) and z) is equivalent to (((z xor y) and x) xor z) -HHellstrцm }fori:=0to3dobeginA:=ROL((((DxorC)andB)xorD)+A+buff[i*4+0],3);D:=ROL((((CxorB)andA)xorC)+D+buff[i*4+1],7);C:=ROL((((BxorA)andD)xorB)+C+buff[i*4+2],11);B:=ROL((((AxorD)andC)xorA)+B+buff[i*4+3],19);end;// Round 2 { Note: (x and y) or (x and z) or (y and z) is equivalent to ((x and y) or (z and (x or y))) -HHellstrцm }fori:=0to3dobeginA:=ROL(((BandC)or(Dand(BorC)))+A+buff[0*4+i]+$5A827999,3);D:=ROL(((AandB)or(Cand(AorB)))+D+buff[1*4+i]+$5A827999,5);C:=ROL(((DandA)or(Band(DorA)))+C+buff[2*4+i]+$5A827999,9);B:=ROL(((CandD)or(Aand(CorD)))+B+buff[3*4+i]+$5A827999,13);end;// Round 3 A:=ROL((BxorCxorD)+A+buff[0]+$6ED9EBA1,3);D:=ROL((AxorBxorC)+D+buff[8]+$6ED9EBA1,9);C:=ROL((DxorAxorB)+C+buff[4]+$6ED9EBA1,11);B:=ROL((CxorDxorA)+B+buff[12]+$6ED9EBA1,15);A:=ROL((BxorCxorD)+A+buff[2]+$6ED9EBA1,3);D:=ROL((AxorBxorC)+D+buff[10]+$6ED9EBA1,9);C:=ROL((DxorAxorB)+C+buff[6]+$6ED9EBA1,11);B:=ROL((CxorDxorA)+B+buff[14]+$6ED9EBA1,15);A:=ROL((BxorCxorD)+A+buff[1]+$6ED9EBA1,3);D:=ROL((AxorBxorC)+D+buff[9]+$6ED9EBA1,9);C:=ROL((DxorAxorB)+C+buff[5]+$6ED9EBA1,11);B:=ROL((CxorDxorA)+B+buff[13]+$6ED9EBA1,15);A:=ROL((BxorCxorD)+A+buff[3]+$6ED9EBA1,3);D:=ROL((AxorBxorC)+D+buff[11]+$6ED9EBA1,9);C:=ROL((DxorAxorB)+C+buff[7]+$6ED9EBA1,11);B:=ROL((CxorDxorA)+B+buff[15]+$6ED9EBA1,15);Inc(FState[0],A);Inc(FState[1],B);Inc(FState[2],C);Inc(FState[3],D);end;{$Q+}{ TIdHashMessageDigest5Ex }constMD5_SINE:array[1..64]ofLongWord=({ Round 1. }$d76aa478,$e8c7b756,$242070db,$c1bdceee,$f57c0faf,$4787c62a,$a8304613,$fd469501,$698098d8,$8b44f7af,$ffff5bb1,$895cd7be,$6b901122,$fd987193,$a679438e,$49b40821,{ Round 2. }$f61e2562,$c040b340,$265e5a51,$e9b6c7aa,$d62f105d,$02441453,$d8a1e681,$e7d3fbc8,$21e1cde6,$c33707d6,$f4d50d87,$455a14ed,$a9e3e905,$fcefa3f8,$676f02d9,$8d2a4c8a,{ Round 3. }$fffa3942,$8771f681,$6d9d6122,$fde5380c,$a4beea44,$4bdecfa9,$f6bb4b60,$bebfbc70,$289b7ec6,$eaa127fa,$d4ef3085,$04881d05,$d9d4d039,$e6db99e5,$1fa27cf8,$c4ac5665,{ Round 4. }$f4292244,$432aff97,$ab9423a7,$fc93a039,$655b59c3,$8f0ccc92,$ffeff47d,$85845dd1,$6fa87e4f,$fe2ce6e0,$a3014314,$4e0811a1,$f7537e82,$bd3af235,$2ad7d2bb,$eb86d391);{$Q-}// Arithmetic operations performed modulo $100000000 functionTIdHashMessageDigest5Ex.InitHash:TIdHashIntCtx;beginResult:=GetMD5HashInst;end;classfunctionTIdHashMessageDigest5Ex.IsIntfAvailable:Boolean;beginResult:=IsHashingIntfAvailandIsMD5HashIntfAvail;end;procedureTIdHashMessageDigest5Ex.MDCoder;varA,B,C,D:LongWord;i:Integer;x:T16x4LongWordRecord;// 64-byte buffer beginA:=FState[0];B:=FState[1];C:=FState[2];D:=FState[3];fori:=0to15dobeginx[i]:=FCBuffer[i*4+0]+(FCBuffer[i*4+1]shl8)+(FCBuffer[i*4+2]shl16)+(FCBuffer[i*4+3]shl24);end;{ Round 1 }{ Note: (x and y) or ( (not x) and z) is equivalent to (((z xor y) and x) xor z) -HHellstrцm }A:=ROL(A+(((DxorC)andB)xorD)+x[0]+MD5_SINE[1],7)+B;D:=ROL(D+(((CxorB)andA)xorC)+x[1]+MD5_SINE[2],12)+A;C:=ROL(C+(((BxorA)andD)xorB)+x[2]+MD5_SINE[3],17)+D;B:=ROL(B+(((AxorD)andC)xorA)+x[3]+MD5_SINE[4],22)+C;A:=ROL(A+(((DxorC)andB)xorD)+x[4]+MD5_SINE[5],7)+B;D:=ROL(D+(((CxorB)andA)xorC)+x[5]+MD5_SINE[6],12)+A;C:=ROL(C+(((BxorA)andD)xorB)+x[6]+MD5_SINE[7],17)+D;B:=ROL(B+(((AxorD)andC)xorA)+x[7]+MD5_SINE[8],22)+C;A:=ROL(A+(((DxorC)andB)xorD)+x[8]+MD5_SINE[9],7)+B;D:=ROL(D+(((CxorB)andA)xorC)+x[9]+MD5_SINE[10],12)+A;C:=ROL(C+(((BxorA)andD)xorB)+x[10]+MD5_SINE[11],17)+D;B:=ROL(B+(((AxorD)andC)xorA)+x[11]+MD5_SINE[12],22)+C;A:=ROL(A+(((DxorC)andB)xorD)+x[12]+MD5_SINE[13],7)+B;D:=ROL(D+(((CxorB)andA)xorC)+x[13]+MD5_SINE[14],12)+A;C:=ROL(C+(((BxorA)andD)xorB)+x[14]+MD5_SINE[15],17)+D;B:=ROL(B+(((AxorD)andC)xorA)+x[15]+MD5_SINE[16],22)+C;{ Round 2 }{ Note: (x and z) or (y and (not z) ) is equivalent to (((y xor x) and z) xor y) -HHellstrцm }A:=ROL(A+(Cxor(Dand(BxorC)))+x[1]+MD5_SINE[17],5)+B;D:=ROL(D+(Bxor(Cand(AxorB)))+x[6]+MD5_SINE[18],9)+A;C:=ROL(C+(Axor(Band(DxorA)))+x[11]+MD5_SINE[19],14)+D;B:=ROL(B+(Dxor(Aand(CxorD)))+x[0]+MD5_SINE[20],20)+C;A:=ROL(A+(Cxor(Dand(BxorC)))+x[5]+MD5_SINE[21],5)+B;D:=ROL(D+(Bxor(Cand(AxorB)))+x[10]+MD5_SINE[22],9)+A;C:=ROL(C+(Axor(Band(DxorA)))+x[15]+MD5_SINE[23],14)+D;B:=ROL(B+(Dxor(Aand(CxorD)))+x[4]+MD5_SINE[24],20)+C;A:=ROL(A+(Cxor(Dand(BxorC)))+x[9]+MD5_SINE[25],5)+B;D:=ROL(D+(Bxor(Cand(AxorB)))+x[14]+MD5_SINE[26],9)+A;C:=ROL(C+(Axor(Band(DxorA)))+x[3]+MD5_SINE[27],14)+D;B:=ROL(B+(Dxor(Aand(CxorD)))+x[8]+MD5_SINE[28],20)+C;A:=ROL(A+(Cxor(Dand(BxorC)))+x[13]+MD5_SINE[29],5)+B;D:=ROL(D+(Bxor(Cand(AxorB)))+x[2]+MD5_SINE[30],9)+A;C:=ROL(C+(Axor(Band(DxorA)))+x[7]+MD5_SINE[31],14)+D;B:=ROL(B+(Dxor(Aand(CxorD)))+x[12]+MD5_SINE[32],20)+C;{ Round 3. }A:=ROL(A+(BxorCxorD)+x[5]+MD5_SINE[33],4)+B;D:=ROL(D+(AxorBxorC)+x[8]+MD5_SINE[34],11)+A;C:=ROL(C+(DxorAxorB)+x[11]+MD5_SINE[35],16)+D;B:=ROL(B+(CxorDxorA)+x[14]+MD5_SINE[36],23)+C;A:=ROL(A+(BxorCxorD)+x[1]+MD5_SINE[37],4)+B;D:=ROL(D+(AxorBxorC)+x[4]+MD5_SINE[38],11)+A;C:=ROL(C+(DxorAxorB)+x[7]+MD5_SINE[39],16)+D;B:=ROL(B+(CxorDxorA)+x[10]+MD5_SINE[40],23)+C;A:=ROL(A+(BxorCxorD)+x[13]+MD5_SINE[41],4)+B;D:=ROL(D+(AxorBxorC)+x[0]+MD5_SINE[42],11)+A;C:=ROL(C+(DxorAxorB)+x[3]+MD5_SINE[43],16)+D;B:=ROL(B+(CxorDxorA)+x[6]+MD5_SINE[44],23)+C;A:=ROL(A+(BxorCxorD)+x[9]+MD5_SINE[45],4)+B;D:=ROL(D+(AxorBxorC)+x[12]+MD5_SINE[46],11)+A;C:=ROL(C+(DxorAxorB)+x[15]+MD5_SINE[47],16)+D;B:=ROL(B+(CxorDxorA)+x[2]+MD5_SINE[48],23)+C;{ Round 4. }A:=ROL(A+((BornotD)xorC)+x[0]+MD5_SINE[49],6)+B;D:=ROL(D+((AornotC)xorB)+x[7]+MD5_SINE[50],10)+A;C:=ROL(C+((DornotB)xorA)+x[14]+MD5_SINE[51],15)+D;B:=ROL(B+((CornotA)xorD)+x[5]+MD5_SINE[52],21)+C;A:=ROL(A+((BornotD)xorC)+x[12]+MD5_SINE[53],6)+B;D:=ROL(D+((AornotC)xorB)+x[3]+MD5_SINE[54],10)+A;C:=ROL(C+((DornotB)xorA)+x[10]+MD5_SINE[55],15)+D;B:=ROL(B+((CornotA)xorD)+x[1]+MD5_SINE[56],21)+C;A:=ROL(A+((BornotD)xorC)+x[8]+MD5_SINE[57],6)+B;D:=ROL(D+((AornotC)xorB)+x[15]+MD5_SINE[58],10)+A;C:=ROL(C+((DornotB)xorA)+x[6]+MD5_SINE[59],15)+D;B:=ROL(B+((CornotA)xorD)+x[13]+MD5_SINE[60],21)+C;A:=ROL(A+((BornotD)xorC)+x[4]+MD5_SINE[61],6)+B;D:=ROL(D+((AornotC)xorB)+x[11]+MD5_SINE[62],10)+A;C:=ROL(C+((DornotB)xorA)+x[2]+MD5_SINE[63],15)+D;B:=ROL(B+((CornotA)xorD)+x[9]+MD5_SINE[64],21)+C;Inc(FState[0],A);Inc(FState[1],B);Inc(FState[2],C);Inc(FState[3],D);end;{$Q+}{$ENDIF}end.

===
Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru

ASUS Tinker Board

$
0
0





===
Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru

Первый Smart Contract

$
0
0
Годное введение здесь: Build Your First Ethereum Smart Contract with Solidity

Пара замечаний:

1. Для подсоединения к запущенной ноде надо использовать:

    geth attach ipc:\\.\pipe\geth.ipc

Если же просто выполнить geth attach, то получим ошибку: Unable to attach to remote geth: no known transport for URL scheme "c" (это верно для версии geth 1.8.23).

2. Mist лучше устанавливать 0.9.3, а не 0.11.1. В последнем при попытке вызвать методы созданного смарт контракта выводится ошибка: Couldn't estimate gas, resorting to default parameters. Transaction is likely cheaper than the estimate. И в дальнейшем состояние "counter" контракта из примера не изменяется (остается всегда 5). В версии Mist 0.9.3 все OK.

===
Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru

Связь GUI (web) и смарт-контракта.

$
0
0
Видео-туториал тут: https://www.youtube.com/watch?v=hcTPjpPvas8

Парочка замечаний:

1. Устанавливать надо версию web3 0.20.6 (в версии 0.20.7 можем получить ошибку: Access to XMLHttpRequest at 'http://localhost:8545/' from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.)

2. Чтобы установился dist\web3.min.js нужно при установке добавлять ключ --verbose.

Резюмируя: npm install web3@0.20.6 --save --verbose

===
Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru

Ethereum и PHP

$
0
0
Полезные ссылки:

API client lib for communication with geth (go-ethereum) node
https://github.com/petrhejna/geth-jsonrpc-php-client

PHP interface to Ethereum JSON-RPC API
https://github.com/digitaldonkey/ethereum-php

A php interface for interacting with the Ethereum blockchain and ecosystem
https://github.com/sc0Vu/web3.php

Устанавливаются библиотеки с пом. композера, брать его тут: https://getcomposer.org/

Подключается установленная с пом. композера либа так:

<?php require_once __DIR__ . '/vendor/autoload.php'; ?>

===
Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru

Request ETH (rinkeby)

OddEven Game (Smart Contract)

$
0
0
Для изучения смарт-контрактов и возможностей написания приложений с их использованием, написал простенькую игру: "Чет-Нечет" (Odd-Even).

Тут: http://oddeven.coolsoftware.ru/web3/

В игре участвуют двое: "банкир" и игрок. За банкира играет сервис на PHP.
Банкир загадывает число, и записывает в смарт-контракт хэш от него. Затем игрок вводит свое число, которое отправляется в смарт-контракт. Потом "банкир" сообщает смарт-контракту загаданное им число (которое должно совпасть с хэшем). В конце определяется победитель: если игрок и банкир  оба загадали четное число, или оба загадали нечетное число (иными словами: игрок угадал, загадал ли банкир четное число или нечетное), то выиграл игрок. Иначе выиграл банкир.

Смарт-контракт опубликован в тестовой сети rinkeby: https://rinkeby.etherscan.io/address/0x7a21ff65b1c509c2236aeaad47e1c938e6dd921c

Для игры игроку нужно установить MetaMask (https://metamask.io/) и завести аккаунт в сети rinkeby. Получить (бесплатно) ETH в этой тестовой сети можно тут: https://www.rinkeby.io/#faucet

===
Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru

Angular First App

Полезные ссылки (Администрирование Linux)

$
0
0

Install/Update Skype for CentOS 7

$
0
0

Install/Update Skype for CentOS 7

  1. wget https://go.skype.com/skypeforlinux-64.rpm
  2. sudo yum localinstall ./skypeforlinux-64.rpm
Если после обновления Skype не стартует, то выполняем в терминале:
  • /usr/share/skypeforlinux/skypeforlinux
Если видим результат типа такого:
  • [4154:1230/082038.483647:FATAL:setuid_sandbox_host.cc(157)] The SUID sandbox helper binary was found, but is not configured correctly. Rather than run without sandboxing I'm aborting now. You need to make sure that /usr/share/skypeforlinux/chrome-sandbox is owned by root and has mode 4755.
то выполняем:
  • sudo chmod 4755 /usr/share/skypeforlinux/chrome-sandbox 

В результате права будут изменены с -rwxr-xr-x на -rwsr-xr-x ("s" means "suid" - takes the rights of user or group when executed).

===
Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru

Дерево Интервалов (Отрезков)

$
0
0
Я уже несколько раз сталкивался с необходимостью решать следующую задачу: есть список интервалов и нужно найти один или все интервалы, в которые входит заданное значение. Пример: есть список диапазонов IP-адресов, каждому диапазону присвоен двух-буквенный код страны. Требуется для заданного IP-адреса определить страну.

Когда интервалов не много, то можно обойтись полным перебором (brute-force). Но когда их несколько десятков тысяч, а искать приходится часто, то нужна оптимизация.

Подходящая структура для быстрого поиска в списке интервалов называется "Дерево Интервалов" (Interval Tree) или "Дерево Отрезков". Хорошее описание (англ.), а также пример реализации я нашел тут: http://www.drdobbs.com/cpp/interval-trees/184401179.

Теория


Коротко описание структуры дерева отрезков и алгоритма поиска приведу на примере: пусть есть список именованных отрезков:

a=[75, 76], b=[75, 79], c=[75, 84],
d=[76, 80], e=[79, 80], f=[79, 83],
g=[79, 91], h=[80, 84], i=[80, 90],
j=[83, 84], k=[84, 85], l=[91, 92],
m=[91, 92]

Выпишем координаты вершин отрезков, отсортированные по-возрастанию:

X = {75, 76, 79, 80, 83, 84, 85, 90, 91, 92}

Массив X содержит 10 элементов: X[0], X[1], ..., X[9].
Возьмем среднее значение (медиану): 83 = X[m], m = (9-0) div 2.

Возможны три варианта расположения отрезков относительно медианы:
1. отрезки, которые содержат медиану.
2. отрезки, которые лежат слева от медианы.
3. отрезки, которые лежат справа от медианы.

Создадим узел дерева, который будет включать в себя значение медианы (дискриминант = 83) и список всех отрезков, которые содержат медиану:

R = {83, [c, f, g, h, i, j]}

Оставшиеся отрезки слева от R: {a, b, d, e}и справа от R: {k, l, m}.

Построим левый узел дерева для отрезков {a, b, d, e}, находящихся левее медианы, рассматривая вершины слева от медианы: {75, 76, 79, 80}. Получим: O = {76, [a, b, d]}.
Аналогично правый узел для отрезков {k, l, m}и вершин {84, 85, 90, 91, 92}: U = {90, []}. Обратите внимание на возможность существования узлов, не содержащих отрезков.
Продолжая процесс рекурсивно, получим следующие узлы:
N = {75, []}, P = {79, [e]}, S = {84, [k]}, V = {91, [l, m]}, Q = {80, []}, T = {85, []}, W = {92, []}.

      R
   /     \
  O       U
 / \     / \
N   P   S   V
     \   \   \
      Q   T   W

Висячие вершины N, Q, T и W можно убрать. Окончательно получим дерево:

     R
   /   \
  O     U
   \   / \
    P S   V

Алгоритм поиска выглядит следующим образом. Начинаем с вершины дерева. Сравниваем дискриминант текущего узла с искомым значением q. Если они равны (случай 1), то выводим все отрезки, на которые указывает текущий узел, и завершаем процесс. Если дискриминант текущего узла больше, чем q (случай 2), то перебираем все отрезки, на которые указывает текущий узел, и выводим такие, которые содержат q. Затем переходим к левому узлу. Если дискриминант текущего узла меньше, чем q (случай 3), то аналогично перебираем все отрезки текущего узла и выводим те, которые содержат q, а затем переходим к правому узлу.

В двух последних случаях (когда дискриминант узла не равен q) нужен перебор отрезков, на которые указывает узел. Этот перебор можно оптимизировать, если иметь два отсортированных массива отрезков: первый массив AL должен быть отсортирован по возрастанию левой (меньшей) координаты отрезка, а второй массив DH должен быть отсортирован по убыванию правой (большей) координаты отрезка. Для узла R из нашего примера:

AL = {c, f, g, h, i, j}
DH = {g, i, j, h, c, f}

Тогда, если дискриминант узла больше q (случай 2), то перебираем отрезки из массива AL до тех пор, пока левая координата отрезка  не будет больше q. Если дискриминант узла меньше q (случай 2), то перебираем отрезки из массива DH до тех пор, пока правая координата отрезка не будет меньше q.

Практика


Реализацию дерева интервалов можно взять на github: https://github.com/coolsoftware/ITree.
Класс itree в itree.h.

За основу я взял реализацию Yogi Dandass, в которую добавил некоторые недостающие (ommited) определения, исправил пару багов и существенно оптимизировал построение дерева (метод construct_tree).

Баг 1в методе itree::construct_tree. Код ниже вызывал выход за границы массива.

  1. std::sort(&(al[list_start]),
  2.     &(al[list_start + list_size]), comp_for_al);
  3. std::sort(&(dh[list_start]),
  4.     &(dh[list_start + list_size]), comp_for_dh);

Он заменен на следующее:

  1. std::sort(al.begin()+list_start,
  2.   al.begin()+list_start+list_size,
  3.   comp_for_al);
  4. std::sort(dh.begin()+list_start,
  5.   dh.begin()+list_start+list_size,
  6.   comp_for_dh);

Баг 2в методе query_iterator::init_node. Если value == cur_node->discrim, то требуется проверка, что cur_node->size != 0, а иначе возможен выход за границы массива.

  1. void init_node(void)
  2. {
  3.     index = 0;        
  4.     while (cur_node != NULL)
  5.     {
  6.         if (value < cur_node->discrim)
  7.         {
  8.             if ((cur_node->size != 0) &&
  9.                 ((*p_al)[cur_node->start]->low() <= value))
  10.                 return;
  11.             else
  12.                 cur_node = cur_node->left;
  13.         }
  14.         elseif (value > cur_node->discrim)
  15.         {
  16.             if ((cur_node->size != 0) &&
  17.                 ((*p_dh)[cur_node->start]->high() >= value))
  18.                 return;
  19.             else
  20.                 cur_node = cur_node->right;
  21.         }
  22.         else//(value == cur_node->discrim)
  23.         {
  24.             if (cur_node->size == 0) //VIT 2014 bugfix!
  25.             {
  26.                 cur_node = NULL;
  27.             }
  28.             return;
  29.         }
  30.     }
  31. }

===
Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru

vsftpd: 530 Login incorrect

$
0
0
Аккаунт для доступа по ftp лучше (imho) делать без доступа к шелу:

useradd ftpuser -s /sbin/nologin

или, если пользователь уже есть:

usermod -s /sbin/nologin ftpuser

Но при этом получаем ошибку: 530 Login incorrect

Причина: в соответствии с настройками в /etc/pam.d/vsftpd пользователь должен иметь шел, перечисленный в /etc/shells. /sbin/nologin, разумеется, в /etc/shells не содержится.

Фикс: комментируем следующую строчку в /etc/pam.d/vsftpd:

#auth       required    pam_shells.so

===
Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru

Run minidlna after mount external usb drive on Raspberry Pi

$
0
0
Предполагаю, что монтируется диск с UUID=a1234567 в /mnt/hdd1. Т.е. соответствующая строка в /etc/fstab выглядит так:

UUID=a1234567    /mnt/hdd1       ext4    defaults    0       0

Для получения UUID диска можно воспользоваться командой: sudo blkid

1. Удаляем (или комментируем) соотв. строку в fstab.

2. Создаем файл /etc/systemd/system/mnt-hdd1.mount со следующим содержанием:

[Unit]
Description=Mount HDD1

[Mount]
What=/dev/disk/by-uuid/a1234567
Where=/mnt/hdd1
Type=ext4
Options=defaults

[Install]
WantedBy=multi-user.target

3. Разрешаем сервис mnt-hdd1.mount:

sudo systemctl enable mnt-hdd1.mount

4. Проверяем статус:

sudo systemctl status mnt-hdd1.mount

5. Если не запущен, то запускаем:

sudo systemctl start mnt-hdd1.mount

6 Создаем файл /etc/systemd/system/minidlna.service. Добавляем в него следующие строки:

[Unit]
Description=Minidlna Daemon
After=mnt-hdd1.mount
Wants=mnt-hdd1.mount

[Service]
Type=forking
# Uncomment the line below for 60 seconds delay.
# ExecStartPre=/bin/sleep 60
ExecStart=/etc/init.d/minidlna start

[Install]
WantedBy=multi-user.target

7. Разрешаем сервис minidlna.service:

sudo systemctl enable minidlna

8. Перегружаемся, проверяем:

df -h
sudo systemctl status minidlna

===
Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru

Howto start avahi-daemon on WSL2

$
0
0
~$ sudo service dbus start
 * Starting system message bus dbus                              [ OK ]
~$ sudo service avahi-daemon start
 * Starting Avahi mDNS/DNS-SD Daemon avahi-daemon                [ OK ]

===
Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru

Mikrotik Multicast

$
0
0
У роутера MikroTik проявилась особенность: когда комп подключен в сеть по Wi-Fi, mDNS то работает, то не работает. Т.е. avahi-resolve то резолвит имя подключенного в той же сетке Raspberry Pi с установленным avahi, то нет. Сложилось впечатление, что теряются пакеты. В итоге выяснилось, что так оно и есть. Проблема решается включением Multicast Helper = "full" в настройках интерфейса wlan:




===
Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru

Cross-platform Development

Viewing all 78 articles
Browse latest View live