printf(" SaltwaterC ");

Developer blog

“Prostia nu este un proces, ci o stare de fapt”

  Archive for the ‘Programare’ Category


Parole aleatoare în Linux, “extended ASCII”

Deși în teorie problema din titlu este una rezolvată, în practică de multe ori mi-am dorit o parolă de o complexitate mai mare față de ce-mi oferă majoritatea uneltelor ce nu ies din standard ASCII. Prin metoda subsemnatului, se ia următoarea funcție și se trântește în .bashrc:

function urandompass()
{
	cat /dev/urandom | tr -dc '[\41-\176\241-\254\256-\376]' | fold -w $1 | head -n 1
}

Apelul este cretin de simplu: urandompass 12 va genera o parolă de 12 caractere. Sau cheie, am zis-o și pe asta. Funcția poate fi folosită pentru a genera chei pentru un “block cipher”.

Cu toate acestea, pentru cei cu terminalul setat pe UTF-8, caracterele dincolo de range-ul celui de-al 7-lea bit (aka cele ce intră în extended ASCII) nu vor fi printate corect. Teoria spune faptul că UTF-8 este compatibil doar cu setul ASCII, ăla standard. În prealabil este nevoie să se seteze terminalul pe un char encoding single-byte ce implementează vreo formă de extended ASCII gen ISO-8859-x, unde x = 1 este Western, x = 2 = Central European, etc. Personal prefer Western. Pentru cei cu Gnome Terminal, “Terminal » Set Character Encoding » Add or Remove …” dacă e pentru prima dată, dacă nu, atunci ar trebui să poată fi ales din meniu un encoding diferit de cel implicit. Buba este faptul că Gnome Terminal are memorie destul de proastă deci va da reset la UTF-8 dacă terminalul este închis sau se execută reset, deci operația trebuie repetată înainte de a genera orice parolă / cheie.

Acum urmează partea pentru obsedații de detalii aka cei după chipul și asemănarea subsemnatului. “Limitarea” la extended ASCII, ce oricum oferă o complexitate mai bună decât majoritatea generatoarelor, provine de fapt din tr. Un info coreutils ‘tr invocation’ în shell specifică destul de clar: “Currently `tr’ fully supports only single-byte characters.”, deci suportă multi-byte din jumătatea lui cinci. Pentru amatorii de detalii, acele range-uri din funcția mea au fost documentate, oarecum, în prealabil.

În DEC:

33-126
161-172
174-254

În OCT:

41-176
241-254
256-376

Evident, cu ochiul liber se poate vedea că tr primește octal, precum zice manualul. Pentru a le determina am încercat cu encoding ISO-8859-1 și ISO-8859-2 o aplicație ce printează tot range-ul single-byte (mă rog, fără ultimul caracter).

Pentru PHP-iști:

for ($i = 0; $i < 256; $i++)
{
	echo $i.': '.chr($i)."\n";
}

Iar pentru snobii cu C, avem alternativă :D :

#include 
 
int main()
{
        for (int i = 0; i < 256; i++)
        {
                printf("%d: %c\n", i, i);
        }
        return 0;
}

gcc -std=c99 -o chars chars.c

Inițial m-am inspirtat dintr-o versiune *sh de pe linuxquestions.org, dar arată cretin, nu dau paste la așa ceva. Mă cam strânge octalul de dinți. O versiune rescrisă pentru DEC junkies:

#!/bin/bash
 
chr()
{
	printf \\$(printf '%03o' $1)
}
 
i=0
while [ $i -lt 256 ]; do
	echo "$i: `chr $i`"
	let "i++"
done

Pentru cei ce preferă alte encoding-uri single-byte, dacă range-urile de mai sus nu sunt potrivite, atunci se poate rula oricând vreo aplicație de mai sus pentru a face un test de char printing.

Pentru cei ce nu s-au născut cu "DEC to OCT converter" în cap, așa ca subsemnatul, Calculator din Gnome (gcalctool) are și un mod Programming (Ctrl+P).

  • Share/Bookmark

Căi UNIX corecte în PHP

Se dă următoarea problemă, aparent mai simplă decât zice titlul: să se determine dacă o cale de tip UNIX este corectă. Buba este faptul că această cale poate să fie către un fișier ce nu există, spre exemplu o cale de UNIX socket ce va fi creat într-un director ce va conține un pool de socket-uri. Deci funcțiile la nivel de filesystem nu vor ajuta, cel puțin nu în primă fază. În cazul  în care există vreo încercare de intuiție a scopului, da, scriu server scripting și în PHP. *sh este prea limitat pentru anumite chestii mai avansate, sau are nevoie de prea mult “boilerplate code”, pe când în Perl nu sunt încă fluent. Pentru cei ce au pierdut știrile de la ora 5, PHP nu mai este de mult un limbaj strict “web oriented”, funcționează bine merci și pentru “general purpose”.

Să revin la problema inițială. Practic se pot identifica două probleme: a) validarea unei căi inexistente – deci apelăm la regex; b) validarea directorului – deși fișierul poate să nu existe în timpul execuției de validare, directorul e musai să fie acolo. De regulă aplicațiile care creează câte un UNIX socket nu verifică aceasta și vor eșua să pornească.

Rezumat, codul arată cam așa:

$validate = preg_match('/^(\/[^\0]*?\/?)[^\0\/]+$/', $path, $matches);
if (empty($validate) === TRUE OR is_dir($matches[1]) !== TRUE OR is_dir($matches[0]) !== FALSE)
{
	// handle error here
}

Acum, discuție pe marginea textului. Acest regex satisface direct ambele probleme. Prima, este fix problema de validare. Se ține cont doar de căi absolute – acesta fiind contextul în care operez. Cu toate acestea, soluția se poate adapta ușor pentru căi relative.

Singurul capturing group din expresie preia întreaga cale, mai puțin numele fișierului. A fost făcută să funcționeze inclusiv pentru root (/). Calea capturată trebuie să fie către un director, pe când calea întreagă trebuie să nu fie un director.

Teoria căilor este simplă. O cale UNIX poate să conțină orice caracter, mai puțin nul, iar / este folosit pe post de separator de directoare, deci este rezervat acestui scop. Căile de tip //var///www//// sunt valide. Exemplul anterior va duce în //var/www unde // în general (Linux, BSD) este tot una cu /. Nu am lucrat pe sisteme unde // să fie distinct față de /, deci nu am considerat că este nevoie să tratez cazul prin expresia de mai sus.

  • Share/Bookmark

G-WAN – acceleratorul de web

Deși titlul pare forțat, proiectul pomenit acolo are un potențial mare atâta timp cât este utilizat cum trebuie. Singurele probleme sunt toate aceste primadone, așa zișii programatori auto-proclamați, ce maxim au idee despre despre ceva scripting într-un limbaj cu tipuri dinamice de date, dar în momentul în care vine vorba de muncă adevărată sau a proiecta un algoritm, dispar. Nu susțin faptul că sunt marele guru ce s-a născut cu tastatura în mână, nu sunt fluent în ANSI C, căci despre acesta este vorba, dar (pe testate) am putut observa potențialul unei astfel de soluții. Deci se adresează programatorilor. Programatorilor ce nu se ascund de pointeri (pe care, recunosc, încă nu-i stăpânesc), programatorilor ce au idee despre cum funcționează platforma pe care rulează aplicația și nu se ascund sub încă un nivel de abstractizare [insert smart-ass name here], etc. Din această categorie recomand “What every programmer should know about memory“, chestie pe care vreau să o parcurg pe îndelete pe când voi avea timp.

Deci ce este acest G-WAN? Pe scurt, în cele aproximativ 120 kile de binar se găsește un web server brutal de rapid și un început de application server, practic suport pentru servlet-uri scrise în ANSI C, compilate dinamic, după metoda edit & play folosită de PHP-iști. Și evident, caching, acea sperietoare de “web developers”, altfel nu ar fi fost chiar atât de rapide.

Am urmărit îndeaproape proiectul de pe la v1.0.3 deoarece mi s-a părut interesantă prezentarea, dar fără aplicabilitate momentană “in real life”. Între timp aplicatia a mai crescut în valoare, iar platforma s-a modificat din Windows (la acea dată) în Linux. Autorul se săturase de limitările din kernelul Windows, limitări ce se găsesc și în kernelul Linux, dar sunt mai sus.

Nu vorbesc din citatele autorului G-WAN despre aceste limitări. Le-am testat pe propria piele. Fie că am executat fractalul lui Mandelbrot (servletul fractal.c disponibil în arhiva de distribuție), fie că am executat problema despre care vorbeam aici, atât implementarea brută cât și cea eficientă, pe un quad-core (C2Q Q9400) și Apache Bench pe localhost am stat în jurul valorii de 69000 req/s. Da, vorbesc de o aplicație, unde fractalul este cu ordin de complexitate mare comparat cu problema numerelor. Dar cu toate acestea, throughput-ul servlet-urilor a fost apropiat ca valoare. Deci există o limitare, dincolo de eficiența algoritmului și a puterii de procesare necesare.

Printre altele, nu a fost nici o limitare de lățime de bandă. Rulând teste de conținut static, am obținut aproximativ 1.2 GiB/s la o concurență suficient de mare, înainte ca ab să înceapă să dea timeout-uri și erori de conectare. Da, 1.2 GiB/s prin interfața de loopback. Aici se adaugă doar efortul de encapsulare, decapsulare și fragmentare a pachetelor din moment ce MTU este mare comparat cu o “rețea normală”, dar totuși cu o valoare implicită de 16436 pe care nu am încercat să o mânăresc și nici nu știu să fi mânărit vreodată prin setările de la lo. Testele dinamice nu se apropiau de această lățime de bandă, de altfel, conținutul static la 1.2 GiB/s abia urca pe la 20000 req/s, deci o limitare de bandă era mult mai evidentă în cazul acestui tip de conținut, față de un servlet.

Singura problemă ce am observat-o a fost una de scalabilitate pe mai mult de două nuclee de procesor. G-WAN lansează un număr de thread-uri egal cu numărul de nuclee, dar din cele 4 pe care le-a lansat, doar primul și ultimul încărcau procesorul în timp ce 2 și 3 frecau menta în idle. Cel puțin așa raportează htop pus în modul threaded la listarea proceselor din sistem.

De altfel, la capitolul conținut static nu am observat o viteză mărită cu ordine de magnitudine față de nginx, ci doar o viteză de ordinul procentelor mai mare, dar totuși vizibilă. La capitolul aplicații dinamice este zona unde strălucește, deși încă mai are puțin până în zona “production ready”, în sensul că momentan lipsesc două chestii mari și late. Prima chestie este renunțarea la privilegiile elevate dacă rulează ca network daemon, unde pentru a folosi portul 80 este nevoie de privilegii de superuser – sau să se apeleze la hack-uri precum NAT prerouting în iptables ori *inetd – nerecomandate. A doua chestie este suportul pentru reverse proxy. Din moment ce codul existent nu se transformă peste noapte în ANSI C, eventual ANSI C optimizat la sânge, G-WAN va putea fi folosit, cândva, pe post de frontent web server într-o arhitectură multi-tier.

Configurația este … ce configurație? De fapt până și pentru virtual hosting se folosește un sistem de “convention over configuration” ce simplifică la maxim treaba, ceea ce face web serverul foarte sysadmin friendly. Singurele chestii mai sofisticate sunt maitenance script-ul și acele handlers, chestii ce necesită cunoștinte de ANSI C înainte de a te apuca să le folosești. Cam toate chestiile minime în accepțiunea unui web server modern sunt acolo inclusiv gzip, activat automat în funcție de tipul de conținut. Restul … sunt specificații, mai mult sau mai puțin interesante.

Update: săpând puțin prin web, am dat de CTPP ce se laudă că are interfață pentru C, chestie ce ar putea satisface nevoile de template engine. Încă nu am renunțat la gândul de a încerca o chestie implementată sub formă de bibliotecă/biblioteci compilate din moment ce acea compilare dinamică nu are suport de optimizare de aia șmecheră cum are gcc, MongoDB sau ceva asemănător pentru persistență și un servlet pe post de front controller.

  • Share/Bookmark

I can has Makavelis numbers

S-a găsit Google Reader să mă scoată cu nasul din shell cu următoarea problemă, dată pe undeva pe aici. Practic rezolvarea problemei:

AB + CD + AC + BD = 100

Ca orice “nerd” ce se respectă, am pus mâna pe Eclipse pentru a rezolva problema, nu pe o foaie de hârtie, din moment ce prin natura ei există 104 ( da, 10.000) soluții posibile, dar doar 25 sunt corecte, considerând faptul că A, B, C pot lua valoarea 0. De fapt, am scris soluția ca pe una configurabilă pentru a-i servi și alt input dacă nu am nimerit-o și A, B, C încep de la 1. Oricum, muncă de 5 minute, dar i-am dat un refactor, să moară dușmanii de ciudă, fără număr la bandă.

Din moment ce propria pacoste de motan mi-a servit drept inspirație, codul e scris lolstyle (dar totuși câtuși de cât profesionist). Ca idee, I_can_has_numbers este clasa ce se ocupă de toate chestiile, iar fișierul I_can_has_everything.php este cel apelabil, fie din browser, pentru cei cu o stivă PHP instalată, fie folosind PHP CLI.

Cod: PHP5/OOP

Download: I_can_has_Makavelis_numbers.zip

Pentru cei născuți cu lene de a mai rula cod, acestea sunt soluțiile:

Number of solutions: 25

A = 0; B = 0; C = 8; D = 6; 0 + 86 + 8 + 6 = 100
A = 0; B = 1; C = 7; D = 6; 1 + 76 + 7 + 16 = 100
A = 0; B = 2; C = 6; D = 6; 2 + 66 + 6 + 26 = 100
A = 0; B = 3; C = 5; D = 6; 3 + 56 + 5 + 36 = 100
A = 0; B = 4; C = 4; D = 6; 4 + 46 + 4 + 46 = 100
A = 0; B = 5; C = 3; D = 6; 5 + 36 + 3 + 56 = 100
A = 0; B = 6; C = 2; D = 6; 6 + 26 + 2 + 66 = 100
A = 0; B = 7; C = 1; D = 6; 7 + 16 + 1 + 76 = 100
A = 0; B = 8; C = 0; D = 6; 8 + 6 + 0 + 86 = 100
A = 1; B = 0; C = 6; D = 7; 10 + 67 + 16 + 7 = 100
A = 1; B = 1; C = 5; D = 7; 11 + 57 + 15 + 17 = 100
A = 1; B = 2; C = 4; D = 7; 12 + 47 + 14 + 27 = 100
A = 1; B = 3; C = 3; D = 7; 13 + 37 + 13 + 37 = 100
A = 1; B = 4; C = 2; D = 7; 14 + 27 + 12 + 47 = 100
A = 1; B = 5; C = 1; D = 7; 15 + 17 + 11 + 57 = 100
A = 1; B = 6; C = 0; D = 7; 16 + 7 + 10 + 67 = 100
A = 2; B = 0; C = 4; D = 8; 20 + 48 + 24 + 8 = 100
A = 2; B = 1; C = 3; D = 8; 21 + 38 + 23 + 18 = 100
A = 2; B = 2; C = 2; D = 8; 22 + 28 + 22 + 28 = 100
A = 2; B = 3; C = 1; D = 8; 23 + 18 + 21 + 38 = 100
A = 2; B = 4; C = 0; D = 8; 24 + 8 + 20 + 48 = 100
A = 3; B = 0; C = 2; D = 9; 30 + 29 + 32 + 9 = 100
A = 3; B = 1; C = 1; D = 9; 31 + 19 + 31 + 19 = 100
A = 3; B = 2; C = 0; D = 9; 32 + 9 + 30 + 29 = 100
A = 5; B = 0; C = 0; D = 0; 50 + 0 + 50 + 0 = 100

 

Update: F (nu o să îi dezvălui numele din moment ce a decis să se semneze doar cu F :) ) a atras antețina asupra faptului că am făcut brute-force în soluția mea sofisticată, deci vin în întâmpinare cu un algoritm bazat pe modelarea matematică a soluției. Algoritmul rezolvă problema în numărul minim de pași (24), plus adăugarea soluției iregulate (unde trișez, este hardcoded). Numărul de bucle s-a redus la două cu număr minim de pași (4 pentru A, inițial 9 pentru B, după care scade, C și D sunt deduse).

Download: I_can_has_Makavelis_numbers_v0.2.zip

Update: din moment ce primii doi algoritmi sunt de cacao (fără o), primul e pur brute-force iar al doilea nu reprezintă o modelare matematică ce să includă toate soluțiile, revin pe scenă cu ultima soluție (finală) a problemei de mai sus.

Sursa algoritmului propriu zis:

for ($a = 0; $a < = 5; $a++)
{
	$double_a = 2 * $a;
	$end_b = 8 - $double_a;
	$d = $a + 6;
	for ($b = 0; $b <= $end_b; $b++)
	{
		$c = (8 - $double_a) - $b;

		if ($d % 10 === 0)
		{
			$a++;
			$d = 0;
		}

		$this->solutions[] = array
		(
			'a' => $a,
			'b' => $b,
			'c' => $c,
			'd' => $d,
		);
	}
}

 

Download: I_can_has_Makavelis_numbers_v0.3.zip

  • Share/Bookmark

Firebug 1.5 + Firefox 3.5.7 + Ubuntu Hardy amd64

Firebug este o unealtă indispensabilă activităților de dezvoltare web pe care le execut. Din păcate, actualizările se lasă cu urmări câteodată. Precum zice în titlu, am încercat combinația nefericită de mai sus. Buba stă în Firebug: 64 bit Firefox on Linux crashes with Firebug 1.5.0. Am mers pe firul epic al poveștii de pe issue tracker și mi-am resetat preferințele. Crash-ul reapare atunci când se reactivează tab-ul Net sau Console. Din nefericire, echipa Firebug aruncă vina către Ubuntu, desi eu mi-am făcut propriul build personalizat de Firefox, deci problema cred că zace undeva prin ceva bibliotecă livrată cu Ubuntu din moment ce versiunea de Firefox îmi aparține.

Soluția de moment: downgrade la Firebug 1.4: http://getfirebug.com/releases/firebug/1.4/

PS: Firefox 3.6 sub Hardy amd64 este probabil cea mai instabilă versiune lansată vreodată. Am avut versiuni de Firefox Alpha sau Beta ce erau mai stabile de atât.

  • Share/Bookmark

Designed by: studentzFM | Theme made for free by: Casino , punkzFM and mygroovez | Heavily modified by SaltwaterC