Cel mai iubit dintre Arhitecti

Posted in Regula 0, Stand-up philosophy on February 28th, 2011 by jos8cal

Asociatia pentru o lume mai buna a anuntat recent un master class la care pe post de Dumnezeu va fi un Dumnezeu care a pus umarul la inventarea cosorului pentru impletit cod. Educator si pedagog, el va fi pret de o saptamina ca un doctor care va sta la capatiiul arhitectului bolnav si va astepta pina acesta se va face bine, adica se va ridica pe picioarele lui!

Toti arhitectii vor merge acolo pentru reeducare! Adica sa invete o meserie din care sa se hraneasca pe sine si ulterior familiile lor. Cu ajutorul unui instrument ingenios, vor invata sa faca impreuna lucruri folositoare pentru oameni si pentru programatori in special. Caci meseria este bratara de aur! Si anume, vor invata sa impleteasca cod in general.

In ingeniozitatea lui, programatorul isi impleteste codul folosind briceagul, care ii permite mai apoi sa-si ievaluieze productivitatea la hectar de cod scris. Dar pentru asta, cineva s-a gindit cu capul lui sa vina in ajutorul programatorului si a inventat un instrument mai ingenios decit briceagul. Asa a aparut Cosorul.

Cosorul este format din doua parti: partea lemn-oasa si partea fer-oasa, iar pentru a invata sa-l minuiti corespunzator aveti nevoie de 2750 de euroi fara TVA. Spor la impletit!

Mai jos redam o bucata din editia precedenta a master class-ului care a avut loc la Slanic:

Tags: , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,

Purely Fabricated Interview Expert Pattern

Posted in Slagare internationale, Stand-up philosophy on February 21st, 2011 by Mihnea

Am aflat de la Andrei Ignat ca Scott Hanselman a publicat o noua lista de intrebari de interviu pentru programatori. Cred ca Hanselman asta e un fel de Ovidiu Cucu international, ca vad ca tot publica liste d-astea. Ca orice programator care se respecta, si eu sint constient ca pot deveni somer peste noapte, deci fac eforturi mari sa ma tin la curent cu ultimele evolutii in domeniul intrebarilor de interviu. Atasez mai jos raspunsurile mele la intrebarile lui, pentru cei 3 cititori din totalul nostru de 5 care nu sint membri pe programare.org. Scuzati limba lu’ Shakespeares, am zis sa nu break character.

What is SOLID?

YABA.

Why are patterns important?

Patterns are important because people who cannot program must be able to project importance by wielding pompous words.

Who are the Gang of Four? Why should you care?

The Gang of Four, also known as The Alpha Wankers, are four non-programmers who understood what power words are and applied the concept to programming. I care because Aurelian Popa told me that today it is more important to be “social” than to know how to program, and using pretentious jargon like “singleton” instead of “global variable” is a guaranteed way of improving one’s social status. They are not to be confused with the Wang-Zhang-Jiang-Yao group, whose name they borrowed in a spectacularly ill-advised stab at self-irony.

Explain the concept of Separation of Concerns and it’s pros and cons.

Separation of Concerns means that when you concern yourself too much with design patterns, you can stop being concerned about grammar. No man can understand the singleton pattern AND remember the basic rules of languages with immensely complex grammars such as English, so once you embrace the teachings of the Gang of Four, grammar becomes Somebody Else’s Concern. The first sign of this transcendence is putting an apostrophe in the possessive pronoun “its”.

Discuss the concept of YAGNI and explain something you did recently that adhered to this practice.

YAGNI is something YAGN, as it’s related to XP.

Are you still writing code? Do you love it?

No, I’m too busy calling my global variables singletons and speaking at conferences about it.

What do you do to stay abreast of the latest technologies and tools?

Hahaha you said breast!

How do you react to people criticizing your code/documents?

I punch them, fire them and/or write inflammatory posts about them on forums or blogs.

Whose blogs or podcasts do you follow? Do you blog or podcast?

Are blogs and podcasts design patterns? Never heard of them. Anyway, I like the color fuchsia, I am an open-minded person focused on self-improvement and my hobbies include hiking, music, reading and taxidermy. I hope this helps you determine if I’m a good programmer or not.

What is the last programming book you read?

I only ever read one, “Design Patterns”. I memorized every word. I don’t need to know anything else.

What’s so great about <cool web technology of the day>?

<generic answer>

How can you stop your DBA from making off with a list of your users’ passwords?

I didn’t know such sexual deviationism is so common among DBAs and anyway, why is that my problem instead of HR’s? Oh wait, you said “making off”, not “making out”. My bad.

What do you do when you get stuck with a problem you can’t solve?

The Design Patterns book is a complete list of solutions which are just waiting for problems. Unenlightened people approach programming the wrong way: they see problems and look for solutions. I use the sure-fire method of picking solutions from The Book and inventing problems for them. That way, I’m never stuck. Any feature or system which cannot be implemented in this way is ill-defined and not worth my concern in the first place. See also the “Separation of Concern” principle.

What’s the difference between a web server, web farm and web garden?

Wait, what? Web garden?

When do you know your code is ready for production?

When I have at least 157 design patterns in it.

What’s YAGNI? Is this list of questions an example?

Didn’t you ask this already?

Noile mele cuvinte favorite: Information Expert (a nu se confunda cu Code Expert), Pure Fabrication, Protected Variations.

LE (adica Later Edit, Ovidiu): hahahaha am aflat ce-i ala web garden. Redefinirea cuvintelor limbii engleze, in pula mea.

LLE: GoF au incercat sa si cinte la un moment dat. Punk, pentru ca si la muzica se pricep la fel de bine ca la programare. Iata-i aici prezentind pattern-ul “Old Grey Whistle Test”:

Tags: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,

Da-mi taticule si mie o lopata si-o mistrie

Posted in Slagare internationale, Stand-up philosophy on February 19th, 2011 by Mihnea

Cei ce trec prin viata doar in plimbare
Uita ca exista si penitenciare
Unde nu-i soare si nu creste-o floare
Si doare cind musti din covrig

Nenumarati contabili au flatulat de-a lungul timpului perspective numerologice asupra traiului de programator, de la regula 80/20, care a fost aplicata sistematic si contradictoriu tuturor perechilor posibile de cantitati numarabile (dar nu neaparat masurabile) din aceasta ingrata activitate, pina la transpiratul 10/50/30/10. Eu propun o simplificare a acestor dihotomii, triotomii si cvadruplotomii ciomuistice: programatorii isi petrec majoritatea timpului facind cacaturi care n-au absolut nici o legatura cu lucrul pe care vor sa-l programeze.

Cea mai de cacat situatie in care te poti gasi ca programator este atunci cind trebuie sa cooperezi cu niste cod facut de altcineva, adica intotdeauna. In general tu vrei sa faci o chestie clara, dar pina sa ajungi sa scrii alea 2 linii care te intereseaza pe tine trebuie sa te bati cu sute de muisme care iti stau in drum: compilatoare, IDE-uri, SDK-uri, framework-uri, biblioteci, OS-uri si asa mai departe. In loc sa te preocupi de ce face codul tau, te chinui sa intelegi care din mizeriile de lib-uri pe care le folosesti fragmenteaza memoria intr-un asemenea hal ca nu mai vrea OS-ul sa-ti dea 20 de amariti de megi de memorie, cind tu ai commit size pe la 700 MB.

Mai deunazi, in uzina la noi se barbota cu sirg la un plug-in de Max care trebuia sa coopereze cu un alt plug-in, ce nu era al nostru. Acest alt plug-in avea amabilitatea de a oferi chiar un SDK, adica niste headere cu nume de variabile din maxim 2 litere si fara documentatie, deci nu se intrevedeau incidente. Totul a mers ca uns pina in clipa in care am chemat o metoda numita “Eval” si am luat unresolved external.

Vedeti voi, plug-in-ul nostru nu poate fi linkat cu lib-urile celuilalt plug-in, caci trebuie sa se incarce si daca plug-in-ul alalalt nu exista. Daca punem o dependinta statica catre DLL-ul lor, al nostru nu mai merge decit daca e si al lor instalat. In concluzie, trebuie sa incarcam dinamic un pointer la metoda aia s-o apelam doar daca exista, lucru banal in teorie. Procesoarele, aceste chestii de care in zilele noastre sint mai preocupati gamerii decit programatorii, chiar au o instructiune pentru apelat functii, deci n-ar trebui sa existe articole pe blog-uri despre asta, nu? Ei bine, pina la CPU exista C++, compilator si Max, iar retardarile lor combinate dau o retardare mai mare decit suma partilor.

O metoda e o functie ordinara careia trebuie sa-i pasezi cumva si this-ul pe sub mina. In functie de platforma, dinsul trebuie sa fie pus intr-un registru sau pe stiva. Pe linga instructiunea de apelat functii, CPU-ul, acest lucru magic, are in mod surprinzator si instructiuni pentru pus chestii in registri sau pe stiva. Problema e cum il convingi pe compilator sa le genereze cind tu ai un pointer la functia aia – pe care l-ai luat cu GetProcAddress() – si pointerul la obiect.

Intr-o lume ideala s-ar face ceva de genul:

// In expozitiune:
#ifdef _WIN64
const char* methodName = "?Eval@ClasaMuista@@QEAAMM@Z";
#else
const char* methodName = "?Eval@ClasaMuista@@QAEMM@Z";
#endif
void* method = GetProcAddress(dll, methodName);

// In desfasurarea actiunii:
ClasaMuista* instPtr = ...;
float arg = 0.37f;
float retVal;
#ifdef _WIN64
__asm
{
	mov		rcx, instPtr
	movss	xmm1, arg
	call	method
	movss	retVal, xmm0
}
#else
__asm
{
	mov		ecx, instPtr
	push	arg
	call	method
	fst		retVal
}
#endif

Deoarece nu traim intr-o lume ideala, un mintos de la Microsoft care crede ca procesorul e o legenda urbana s-a decis ca Visual C++ nu va avea inline asm in 64-bit. La momentul la care a fost proclamata, aceasta prostie fenomenala a fost intimpinata cu urlete si mui de catre cei afectati, dar pe Microsoft i-a durut la penis. Motivul oficial este la fel de retardat ca decizia in sine: cica nu poti scrie acelasi asm pentru 32 de biti ca pentru 64. Si ce? D-aia avem ifdef, in mortii lui de ifdef. Nu inteleg ce ii fute pe ei grija ca eu trebuie sa fac gimnastica cu ifdef. Daca trebuie, o fac. Alternativele propuse de mintos sint ori sa te descurci cu intrinsics, ori sa scrii codul intr-un fisier separat si sa-l compilezi cu un assembler. Aia cu intrinsics nu se aplica aici, dar si in cazurile in care se aplica o mai da in bara, caci VC nu e tocmai Tata Lor™ la tradusul intrinsic-urilor in cod (ceea ce ma mira foarte, caci de pe banca de unde stau eu mi se pare destul de usor sa produci cod optim din asa ceva, sau cel putin mult mai usor decit alte optimizari pe care compilatorul lor le face bine). P-aia cu assembler-ul extern nu vreau s-o aplic pentru ca mi se pare insultator sa fiu nevoit sa instalez masm sau alta atrocitate ca sa chem o functie.

Un scurt moment am cochetat cu ideea de a face un const char* cu opcode-urile unei functii care pune argumentele unde trebuie si cheama cacatul de metoda, dupa care sa indrept un function pointer spre el si sa-l chem, da’ cirpeala e cam mare, asa ca am zis sa o luam totusi pe calea ortodoxa: facem un pointer la un member function si-l chemam p-ala. Adica:

// Expozitiune:
typedef float (ClasaMuista::*EvalFunc)(float);
union
{
	void*		voidPtr;
	EvalFunc	funcPtr;
} p;
p.voidPtr = GetProcAddress(dll, methodName);
EvalFunc method = p.funcPtr;

// Desfasurarea actiunii:
ClasaMuista* instPtr = ...;
float retVal = (instPtr->*method)(0.37f);

Observam tigania cu union-ul, care-i necesara pentru ca n-ai voie sa castezi void* la pointer la metoda. C++ e retardat si-ti permite sa derivezi din mai multe clase de-odata, caz in care pointerul ala trebuie sa mai contina niste cacat pentru ajustarea corespunzatoare a this-ului. Desi Java a transat problema asta acum vreo 15 ani (spre surprinderea tuturor, caci e singurul lucru facut bine in Java), C++ inca n-a inteles ca numai cretinii deriveaza din mai multe clase cu date in ele. Ba mai mult, ca sa le dea apa la moara cretinilor, ofera si virtual inheritance, acest goatse al OOP-ului care pretinde ca te scoate din cacat cind diagrama ta de clase seamana cu Coloana Infinitului, dar de fapt sileste compilatorul sa produca cod de o uritenie rar intilnita. In fine, C++ n-o sa primeasca interfete doar pentru ca ma oftic eu aici in fata poporului (la urma urmelor, se chinuie de vreo 12 ani sa-i creasca closures si inca nu e gata), dar in cazul de fata toate aceste griji pot fi date uitarii, caci clasa cu care trebuie sa cooperam nu e derivata din nimic, deci pointerii la metodele ei sint pointeri normali. Deci rulam codul si crapa. Cu WTF-ul pe buze, privim in disassembly si ne minunam:

000000013F191043  movss       xmm1,dword ptr [__real@3ebd70a4 (13F1921B4h)]
000000013F19104B  movsxd      rcx,dword ptr [rsp+28h]
000000013F191050  add         rcx,rbx ; Tu cine pula mea esti?
000000013F191053  call        rax

Ce o fi cu acea adunare de colea, ce seamana izbitor de tare cu o ajustare a this-ului pentru multiple inheritance? In acest moment, ne revine din negura vremurilor amintirea ca VC++ are un flag care-ti permite sa fortezi toti pointerii la metode sa foloseasca formatul extins, cu offseti si cacat. Cautam in MSDN si aflam ca flag-ul se cheama /vmg. Privim in project settings, dar nu-i. Mai privim odata in MSDN si observam ca exista si un pragma care face acelasi lucru, moment in care vedem rosu in fata ochilor.

In acest punct de turnura al naratiunii trebuie sa vorbim un pic despre 3D Studio Max si programatorii care lucreaza la el, caci poate nu-i un subiect familiar tuturor. La Max au lucrat de-a lungul timpului cei mai prosti programatori care au scris vreodata cod. Banuiala mea e ca singura cerinta de angajare la Discreet/Kinetix/Autodesk este sa fi lucrat in prealabil la Yahoo Messenger. Proportiile prostiei celor care au facut Max-ul nu se pot descrie in citeva rinduri, insa pentru a va forma o idee pot mentiona ca absolut toti cei care au pus vreodata mina pe SDK-ul de Max, indiferent de nivelul lor de pricepere, au sfirsit prin a dori moartea violenta a dobitocilor care au gindit si implementat acest program de cacat care nu mai moare odata. As dori sa va pot arata niste cod din matele Max-ului, dar cica n-am voie ca NDA si mui.

Cind am vazut ca exista acel pragma, m-am gindit instantaneu la MAXScript. Acest infect limbaj de scripting este facut de cineva cu stofa de Silviu Ardelean, deci am avut o banuiala ca pe undeva prin mecanismul de expus functii C++ in MAXScript voi gasi muia aia. Am dat cu pragma pointers_to_members in virful headerului precompilat, si prompt VC++ mi-a zis:

c:\program files\autodesk\3ds max 2011\maxsdk\include\maxscrpt\..\maxscript\macros\define_instantiation_functions.h(55) : error C2285: pointers to members representation has already been determined – pragma ignored

Muie Max. N-am rabdare sa vad de ce crede dinsul ca are nevoie de cacatul asta, dar va pot garanta ca e gresit. Sigur au futut ceva prin alta parte si au cirpit-o in felul asta. Din cauza imbecilitatii lor, eu nu pot sa chem un cacat de functie.

Ajungind aici, eu m-am enervat si am plecat acasa, dar jos8cal a mai dat un ochi in pagina aia din MSDN care zicea cum e cu pragma si /vmg si a vazut ca mai exista o cirja cu care se poate abuza limbajul: keyword-ul __single_inheritance. Chiar daca un retard ii spune compilatorului sa faca pointeri de cacat, poti reveni la pointeri ordinari pentru clasele care te intereseaza punind keyword-ul ala in declaratie. Deci l-a pus, si a mers. URA AM REUSIT SA CHEMAM O FUNCTIE!

Sau nu. A doua zi, a trebuit sa repetam manevra intr-un plug-in de Maya. Maya nu-i facut de handicapati, deci nu-i nevoie de pragme si keyword-uri si alte chestii d-astea. Din pacate insa, el ruleaza si pe OS-uri de hipsteri si comunisti, unde rolul Domnului Trandafir este jucat de GCC. GCC nu se osteneste sa faca pointerii la metode sa fie pointeri chiori in cazurile cu imbecilitate redusa; dinsul foloseste pointeri d-aia extinsi tot timpul si n-ai cum sa-l rogi sa faca exceptii. Deci ce cacat facem?

GCC are inline asm si in 32 de biti si in 64:

// Expozitiune:
void* method = dlsym(dll, "_ZN11ClasaMuista4EvalEf");

// Desfasurarea actiunii:
ClasaMuista* instPtr = ...;
float arg = 0.37f;
float retVal;

#ifdef __LP64__
__asm__ __volatile__(
	"call *%%rax"
	: "=Yz"(retVal)
	: "Yz"(arg), "D"(instPtr), "a"(method)
	: "memory"
);
#else
__asm__ __volatile__(
	"push (%2)\n"
	"push %3\n"
	"call *%%eax\n"
	: "=t"(retVal)
	: "a"(method), "r"(&arg), "r"(instPtr)
	: "memory"
);
#endif

Singura manevra aici este sa afli cum se cheama constraint-urile alea pentru template-urile de ASM pentru fiecare clasa de parametru care-ti trebuie. Daca il intrebi pe goagal de “gcc inline assembly constraints”, pagina relevanta (adica asta) nu e printre hit-uri (e o pagina care duce la o pagina care duce la asta, totusi). Sint alte pagini insa, scrise de firtati de-ai lui Silviu care simt nevoia sa se exprime desi habar n-au despre ce vorbesc, si care-ti spun, de exemplu, ca constraint-ul pentru rdi este “di”.

Trebuie notat totusi ca am avut bulan ca functia vrea un singur parametru de tip float. In Linux 64-bit, parametrii de tip float se dau in xmm0, xmm1 etc. Exista un constraint pentru xmm0 (numit intuitiv “Yz”, cum se vede mai sus), dar pentru restul nu mai exista (e doar “x”, care inseamna orice registru SSE, adica il lasi pe nenorocit sa aleaga). Ca sa-ti dai parametrii in cazul ala, ii pui in variabile, dai adresele variabilelor, faci lucru manual cu movss ca sa le incarci in registri si pui registrii respectivi in clobber list. Nu ca ce se intimpla deasupra ar fi optim sau ca ar conta, da’ totusi, obscen.

E de notat ca puteam folosi pointerul la metoda si in GCC, si in VC++ fara __single_inheritance, daca ne bateam capul sa scriem chestii in dinsul astfel incit sa faca call-ul care ne intereseaza (layout-ul e documentat pentru GCC si se gaseste pe net sau cu ochiu’ in dezasamblare pentru VC++). Mie asta mi se pare un hack si mai mare decit un const char* cu opcode-urile care fac ce doresc.

Dragi tovarasi, VICTORIE! Am reusit sa chemam o functie! Programarea e o meserie magica, plina de satisfactii, unde visele devin realitate prin simpla apasare a unor butoane!

PS: toata aceasta voma se putea evita daca aia care au facut celalalt plug-in se prindeau ca atunci cind vrei sa expui clase C++ dintr-un DLL, e o idee buna sa faci o interfata si s-o dai p-aia afara. Daca ClasaMuista::Eval() era virtuala, instanta aia de ClasaMuista pe care o primeam de la ei ar fi avut in ea un pointer la vtable, in care s-ar fi aflat si adresa functiei Eval() si ar fi mers totul ca prin minune. Runtime dispatch, chestii avansate nu gluma. Maxim 0.43% din totalul programatorilor de pe planeta asta sint in stare sa faca un API, dar din pacate un procent mult mai mare incearca.

Tags: , , , , , , , ,

XCode

Posted in Slagare internationale on February 17th, 2011 by Mihnea

Steve Jobs are cancer la pancreas deoarece o multime de programatori au vrut sa-si bage pulile in ficatul lui si unii din ei au nimerit pe linga. Probabil Steve nu e direct de vina pentru faptul ca XCode este un puroi revoltator, dar oftica e mult mai spornica atunci cind o poti canaliza in directia unei persoane si Steve e usor de nimerit in pozitia fruntasa in care s-a postat. Cancerul nu este total nejustificat insa, caci rolul de Führer al Nationalsozialistische Hipsterisch Arbeiterpartei ii confera lui Steve dreptul de a-i spinzura cu coarde de pian pe cei care au adus pe lume abominatia; faptul ca el nu-si exercita acest drept este o insulta la adresa intregii omeniri de la Charles Babbage incoace.

Pentru a intelege cum a putut lua nastere XCode, acest abject esec al spiritului uman, trebuie sa examinam intii contextul in care a fost construit el. Vom vedea ca soarta lui a fost pecetluita inca inainte de a se scrie prima linie de cod, dar ca maimutele care au lucrat la el nu s-au multumit sa mosteneasca imbecilitatile platformei pe care cladeau, ci au dus stafeta prostiei pe noi culmi.

Contextul lui XCode este OS X. In Finder (echivalentul hipsteristic al lui Windows Explorer, pentru neinitiati), tasta pentru a deschide un fisier selectat nu este Enter, ci Cmd+O. Enter face rename. Articolul asta s-ar putea incheia aici. Evident n-o sa se incheie, dar macar discutiile din magazinele Apple intre clientii potentiali si vinzatori ar trebui sa se sfirseasca in acest mod.

– Cum fac rename la un fisier?
– Apesi Enter.
– Muie.

Este clar de ce cred Apple ca au facut asta cu Cmd+O: pentru consistenta. In alte programe, “Open” este Cmd+O, deci sa fie si in Finder. Motivul real pentru care au facut asta este la fel de clar: pentru ca sint retardati. Pentru rename cu enter nici macar nu exista un motiv inchipuit, exista doar retardarea.

Fanboii vor spune ca asta cu tastele e doar o preconceptie a cuiva care vine dintr-un alt mediu. Pentru ei am exemplul redimensionarii. In OS X, ferestrele se pot redimensiona doar din coltul din dreapta-jos. Daca ai un geam in dreapta ecranului si vrei sa-l faci mai lat, intii trebuie sa-l tragi mai la stinga, dupa care sa-l maresti. In general n-o sa stii cit de mare vrei sa-l faci, deci n-o sa-l tragi suficient de mult in stinga si n-o sa ai loc sa-l faci cit de mare vrei, asa ca o sa-l mai tragi un pic, si o sa-l mai maresti un pic. Aparent, un test cu un focus grup a relevat faptul ca utilizatorii sufera un atac de panica daca ii lasi sa redimensioneze geamurile din orice colt. Eu cred ca de fapt testul a relevat surprinzatoarea implicatie ca daca faci focus grupuri cu retardati, ajungi la concluzii retardate.

In Biblia UI-ului Apple, unde regasim porunca asta cu strictetea redimensionarii, putem citi si citeva reguli de bun simt. Una din ele e sa nu-ti faci alfabetul tau din pictograme, pentru ca in general oamenii stiu deja un alfabet. Pictogramele trebuie folosite pentru grupat vizual chestiile similare, nu pentru a inlocui textul. Exceptie fac pictogramele pe care le pricepe orice om, gen sagetile, dar si alea trebuie folosite cu mare grija. In aroganta lor, Apple isi dau derogare de la regula asta si pentru mazgalelile de pe tastele lor speciale, caci daca nu vrei sa inveti ca semnul de puscarie e tasta de linga spatiu, nu meriti Lumina lui Steve. Scrie in pula mea “Alt+Cmd+Enter”, nu “juma’ de zvastica puscarie inapoi”, ca nu vreau sa invat ideograme hipsteristice doar ca sa pot sa joc Finder din taste. De asemenea, tastaturile Apple au ergonomia unei mine antipersonal, deci daca vrei sa-ti mai poti misca miinile dupa o zi de interactionat cu un Mac trebuie sa-ti iei o tastatura de oameni, care n-o sa aiba simbolurile cultului Apple pe tastele speciale si n-o sa poti sa te uiti sub degete sa vezi pe ce cacat de buton vrea sa apesi. Pentru avansati avem si o intrebare bonus: cum se numesc cele trei taste din poza urmatoare? Indiciu 1: nici macar pe tastaturile Apple nu sint. Indiciu 2: da, sint 3, muia aia din stinga care abia se vede asa apare in dialogurile de configurare.

Problemele astea sint minore, dar le-am mentionat pentru a putea zugravi o mentalitate. Apple cred ca orice iese din mina lor este perfectiunea intruchipata si o binecuvintare pentru intreaga suflare a planetei, asa ca vor tine cu dintii de orice idee, chiar daca se dovedeste a fi o imbecilitate. Mai mult, daca intrebi cum poti face o chestie care nu se poate face, nu-ti vor spune “nu se poate, sintem retardati”, ci vor incerca sa-ti explice ca de fapt nu vrei sa faci chestia aia. Nu vei putea redimensiona niciodata geamurile ca oamenii, din orice colt, pentru ca Apple stiu mai bine decit tine ca nu vrei sa faci asta, asa cum au stiut timp de 20 de ani ca mouse-ul trebuie sa aiba un singur buton. Heil Apple.

De la mentalitatea asta ajungem la problema editarii textului, care il afecteaza direct pe XCode. Prin 1986, IBM s-au prins ca oamenii folosesc tastatura pentru a scrie text si ca ar fi frumos daca ar pune pe ea niste butoane pentru chestii uzuale cum ar fi mers la inceputul rindului, la sfirsitul lui, o pagina in sus sau una in jos. Apple nu au fost de acord. Cine cacat vrea un buton de home? De la balconul Geamiei Perfectiunii si Adevarului Suprem, muezinii Apple le-au tot repetat credinciosilor: mouse-ul are un buton si n-aveti nevoie de home, end sau function keys. Pina la urma fatwa-ul impotriva butoanelor a fost ridicat si o vreme tastaturile Apple au avut butoane de home si end, dar tocmai a fost reinstituit, si ultimele instrumente de torturat degete marca Steve iar au pierdut butoanele astea eretice. Oricum, nici cind le aveau nu mergeau, pentru ca in dorinta lor de a fi altfel, Apple le-au pus sa te duca la inceputul si sfirsitul documentului, dar fara sa mute cursorul, ca asta sigur e o chestie care-ti trebuie foarte des (mult mai des decit sa duci cursorul la inceputul liniei). De asemenea, page up si page down muta doar view-ul, nu si cursorul, alta chestie teribil de utila (mai ales cind ai scroll wheel la mouse, o inventie recenta in lumea Apple, ce-i drept).

In concluzie, viteza cu care poti edita text in XCode l-ar face pe Gutenberg sa se sufoce de ris. Risul lui Gutenberg poate duce la cancer la pancreas pentru Steve prin mecanismul descris in introducere, avind in vedere ca programatorii tind sa-si petreaca majoritatea timpului scriind text. Sigur, te poti duce la inceputul rindului apasind Ctrl+A, ca pe vremea lui VT100, sau Cmd+Stinga, dar Apple n-au auzit nici macar de smart home, un feature care e in toate editoarele de text din ultimii 20 de ani. Ctrl+A si Cmd+Stinga te duc intotdeauna la prima coloana, nu schimba intre primul caracter din rind si prima coloana, ca la oameni. Au si Alt+Page Up / Alt+Page Down, care muta si cursorul (normal, doua taste pentru functia uzuala si una singura pentru aia inutila). Daca te simti aventuros poti chiar sa-ti redefinesti tastele ca-n jocuri si sa pui home sa faca home, doar ca sa-ti amplifici frustrarea in momentul in care trebuie sa faci ceva la calculatorul altcuiva. Cu putina vointa poti sa-ti cresti productivitatea pina undeva la nivelul lui notepad din Windows, moment in care intervin feature-urile avansate, alea care ne arata ca XCode stie ca nu-i un editor de text chior, ci un editor de cod.

XCode are code completion. Tasta cu care il activezi este Escape. Asta e si mai tare decit rename cu Enter. Escape, in pula mea. Bine, ca in practica nu conteaza, deoarece parserul de C++ e cam la nivelul pe care l-ai obtine daca i-ai cere celui mai prost student din grupa sa-ti faca un parser de C++ dupa ce a mers mahmur la prima ora a unui curs in care se mentioneaza tangential programele “flex” si “bison”. Code completion-ul intelege functii, metode si uneori nume de variabile, dar cam atit. Daca ii arati un template intra in fibrilatie. Totusi, in rarele ocazii cind incepi sa scrii numele unei functii si i se pare ca stie ce vrei sa scrii, iti sugereaza functia, cu tot cu parametrii sai:

Daca dai enter sa accepti sugestia, selecteaza definitia primului parametru, astfel incit s-o poti suprascrie cu ce vrei sa pasezi acolo. Urmatoarele defintii nu se mai selecteaza automat, deci trebuie sa le stergi de mina. Daca nu le stergi, ramin acolo in program si poti chiar sa salvezi textul in halul ala:

Daca te uiti in fisier dupa ce-l salvezi, observi urmatoarea aberatie:

int main()
{
    test(5, <#float y#>)
    return 0;
}

Ineficienta in editarea textului ar fi o problema daca ai putea sa ajungi la fisiere ca sa le editezi, ceea ce in general nu e cazul. Un nou focus grup compus din retardati i-a ajutat pe Apple sa decida ca schimbatul intre ferestre din taste este o alta mare sursa de confuzie pentru utilizatori. In OS X, tasta cu care schimbi intre geamurile aceleiasi aplicatii ia ferestrele la rind in ordinea in care au fost create, nu schimba ordinea in functie de ultima accesare, cum face Ctrl+Tab in Windows. Daca ai 10 fisiere deschise dar umbli in momentul de fata in doua, nu poti cicla intre ele cu o tasta. Daca apesi Cmd+`, vei trece de fiecare data prin toate cele 10 surse, plus celelate geamuri ale lui XCode care or mai fi deschise. Daca nu-ti convine asta, exista un mod in care toate sursele se deschid in acelasi geam, dar atunci nu poti sa ciclezi intre ele in nici un fel din taste. In cel mai bun caz iti pui o tasta care deschide dropdown-ul cu lista de fisiere active, dupa care il alegi cu sagetile p-ala pe care il vrei. Daca intrebi un fanboi Apple ce-i cu retardarea asta, iti va spune ori ca nu-i bine sa ai atitea fisiere deschise in acelasi timp, ori ca exista o tasta pentru schimbat intre doua fisiere .h si .cpp cu acelasi nume si e gresit sa vrei sa ciclezi intre doua fisiere care nu respecta regula asta. In orice caz, Apple stiu mai bine decit tine ce vrei sa programezi si cum.

Presupunind ca nu te deranjeaza sa tot duci mina de pe tastatura pe mouse ca sa schimbi intre ferestre de parca ai avea OCD si ti s-ar parea ca mouse-ul nu-i niciodata unde trebuie, tot vei avea o problema: ce geam sa alegi? XCode e un program saritor, care stie ca e bine sa-ti deschida acelasi fisier in cit mai multe geamuri de-odata. Recordul meu e de 5 geamuri diferite cu acelasi fisier, si l-am obtinut in felul urmator:

  1. Click pe fisier in lista din geamul principal al proiectului, se deschide in geamul ala.
  2. Dublu click pe fisier, vine si un geam separat cu el.
  3. Fa-l sa contina o eroare de compilare, da-i build. Da click pe iconu’ cu eroarea, vine un geam cu build status care va contine si el fisierul.
  4. Da find in files dupa ceva din fisierul ala. Click pe rezultat. Ai ghicit.
  5. Pune un breakpoint in fisier, deschide debugger-ul (care e un geam separat, dintr-un motiv ce-mi scapa) si fa-l sa se opreasca in breakpoint. Da, acum il ai si-n debugger.

Sint convins ca se poate depasi recordul, dar mi-e lene acum sa mai caut cacaturi prin meniuri. Mai interesant este sa ne aplecam un pic asupra debugger-ului, daca tot l-am mentionat. Fiind o companie care incearca din rasputeri sa fie altfel decit tot restul lumii doar de dragul de a fi altfel, era de asteptat ca Apple sa copieze ce fac altii fix in locurile in care nu trebuie. In speta, XCode trateaza problema debuggingului in acelasi mod retardat in care o abordeaza toate pocnitorile de IDE-uri facute pe genunchi in baie de adolescenti cuprinsi de febra Linux si open source: vorbeste cu GDB printr-un pipe. Prin viu grai. Ceva de genul write(gdb_pipe[0], “Draga gdb, poti te rog sa pui un breakpoint?”). Ca si in pocnitorile open source, schimbul de amabilitati se incheie abrupt cind gdb nu intelege sonetul expediat prin pipe, de exemplu atunci cind incerci sa faci step in printf().

Desi cu gdb se pot face multe lucruri, XCode e pe undeva pe la nivelul lui Borland C++ 1.0 ca feature-uri expuse. Tastele de step into/over nu merg in disassembly daca dai sa vezi combinat source cu disassembly. Nu exista set next statement (exista o consola unde poti vorbi direct cu gdb, insa, daca te simti poet). Exista un fel de edit & continue, dar merge doar pe programe didactice si oricum e destul de limitat fara set next statement. Daca ai un breakpoint si inserezi linii deasupra lui, uneori nu se muta mai jos, astfel incit sa ramina la codul la care era, ci ramine la linia lui, adica ti se va opri la alt cod. Daca ai un program mai complicat decit hello world, uneori se plictiseste de facut debug la el dupa citeva rulari, si nu se mai opreste in nici un breakpoint pina nu restartezi sistemul. Lista poate continua, dar cred ca s-a inteles cit de impecabil e debugger-ul. Probabil ca daca-i arati problemele unui fanboi, iti va spune sa scrii cod fara buguri, ca sa n-ai nevoie de debugger.

Totusi, ca sa ai la ce sa faci debug, trebuie sa poti intii sa-ti compilezi proiectul. Apple au vazut la Visual Studio manevra cu platforme, configuratii, Debug, Release, cacat, dar n-au inteles nimic. La ei nu poti avea doua target-uri cu configuratii diferite in acelasi proiect. Cretinatatea acestui fapt mi se pare colosala, caci nu-mi dau seama cit de retardat trebuie sa fii ca sa concepi sistemul in acest mod, mai ales cind exista alte IDE-uri care s-au lovit de aceeasi problema si au rezolvat-o deja. Raspunsul la intrebarea retorica este ca Apple au concluzionat ca configuratiile sint ca widget-ul de redimensionat geamuri: prea multe optiuni, prea mare confuzia in focus grup. Iar au stiut mai bine ca tine.

Sa presupunem ca facem doua plug-in-uri pentru doua aplicatii 3rd party. Fiecare plug-in suporta o serie de versiuni ale aplicatiei sale, si pentru fiecare versiune vom avea doua configuratii, Debug si Release. Primul plugin va avea Debug2008, Release2008, Debug2009, Release2009 etc. iar al doilea va avea Debug8.0, Release 8.0, Debug 9.0, Release 9.0 etc. Acum surpriza: facem si un lib cu care linkeaza ambele. Deoarece dezvoltarea lib-ului se intimpla concomitent cu dezvoltarea plug-in-urilor, vrem sa includem proiectul lib-ului in ambele solutii, ca asa ne-am obisnuit din Visual Studio, unde ai voie sa-ti setezi proiectele cum vrei tu, nu cum vrea Steve. Mai mult, lib-ul nu depinde de aplicatia-host, deci va avea doar doua configuratii: Debug si Release.

In primul rind, XCode nu are conceptul de proiect impartit intre doua solutii. Poti ori sa faci un proiect separat cu lib-ul si sa stai cu ambele proiecte deschise si sa dai build de mina in ambele cind schimbi ceva, ori sa faci proiectul lib-ului de doua ori, o data in fiecare proiect de plugin, cu toate fisierele si setarile si muile. Daca alegi metoda asta, vei remarca ca trebuie sa-i faci lib-ului aceleasi configuratii pe care le are plug-in-ul, pentru ca XCode nu vrea sa vada disensiuni intre target-urile aceluiasi proiect. Daca nici asta nu te convinge, o sa te rezolve faptul ca uneori oricum nu linkeaza cum trebuie, ca desi pui dependinte si cacaturi pe-acolo, nu se prinde tot timpul ca trebuie sa linkeze din nou plug-in-ul pentru ca s-a schimbat lib-ul.

Sistemul de muire a programatorilor din XCode are multiple nivele de fallback. Daca nu reuseste sa va futa cu cacaturile astea legate de configuratii si target-uri, tot va gasi un mod in care sa se asigure ca nu-l puteti folosi in nimic mai mare de hello world. De exemplu, daca va trece prin cap sa aveti un lib care se cheama altfel intre configuratii diferite (cacat_debug.lib si cacat_release.lib, sa zicem) si sa-l puneti ca dependinta la alt target din proiect, simpaticul XCode ii va trece numele curent in setarile de link ale target-ului care depinde de el. Cind schimbati configuratia activa, se schimba si numele ala, la linia corespunzatoare in fisierul cu proiectul. Daca dai commit asa si dupa aia da update un nefericit care are alta configuratie activa decit aveai tu, o sa iasa un conflict. Ca bonus, cind il rulezi in command line ca sa faci un batch build, nu-i in stare sa calculeze numele lib-ului asa cum o face cind e in GUI mode, asa ca o sa incerce sa-ti linkeze target-ul cu ce a ramas scris acolo ultima data cind ai inchis GUI-ul. Si in final, daca nici in cazuri d-astea nu va prinde, uneori se decide sa mute random chestii prin fisierul de proiect desi tu nu schimbi nimic cu mina ta, ca sa o puna totusi de un conflict cind dai urmatorul update.

XCode vine si cu o serie de unelte ajutatoare de o calitate la fel de suprema ca el. Preferatul meu este muismul ala de facut installere. Apple au decretat ca nu vor sa vada installere pentru aplicatii, ceea ce e un lucru bun (la ei aplicatiile vin ca niste arhive din care tragi fisierele afara si gata). Totusi, in unele cazuri chiar trebuie sa faci un installer, si atunci ai la dispozitie PackageMaker, cel mai bugos program pe care l-am vazut vreodata. Pe linga faptul ca periodic iti fute proiectul pentru ca asa i s-a sculat, si ca setarea proiectului in sine este un demers sisific, cel mai tare feature al acestui program mi se pare ca isi tine proiectul in format XML, dar XML-ul e tot pe o singura linie. Daca deschizi un proiect de installer, ii dai build si dai sa-l inchizi, iti va spune ca s-a schimbat. Daca faci timpenia sa-i zici sa salveze, in multe cazuri iti va distruge proiectul. Daca incerci sa dai un diff sa vezi ce-a facut, nu vei avea prea mare spor, fiind totul pe o linie. Noroc ca-i XML, acest format care poate fi citit si de oameni, si de masini, si de Silviu Ardelean.

Observ ca s-a facut tirziu si ca m-am intins un pic. As mai avea chestii de zis, dar ma voi screme inspre retorica finala. Inteleg ca pe Steve il doare la pancreas despre XCode si suferinta pe care o provoaca el programatorilor fortati sa faca aplicatii pe OS X. Nu inteleg totusi cum se face ca muistii care lucreaza la gunoiul asta nu au fost inca linsati de colegii lor, care trebuie sa-l foloseasca. Daca eu as fi programator pe plantatia de meri si as sti ca in cladire cu mine traiesc si defeca cod infectii care au abatut asupra mea cel mai rau intentionat IDE din istorie, s-ar lasa cu singe. Aia de la Apple ori au un IDE secret pe care-l folosesc in-house, ori isi cirpesc propriile solutii cu vim, emacs sau alte editoare preistorice (ceea ce nu e neaparat mai bine), ori spalarea pe creier aplicata personal de Steve fiecarui nou angajat chiar are randament 100%.

Tags: , , , , , , , , , , ,

Optimizing QuickSort and staff

Posted in Premiul n00bel, Slagare internationale, Stand-up philosophy on February 3rd, 2011 by jos8cal

Frunzaream recent revista celor de la codexpert.ro. Cum ce revista? Pai si-au lansat revista! E scrisa de un bot. In fine!

Evenimentul lansarii a fost unul sters, ca sa nu mai zic de lipsa totala a fundamentului ideologic. Dat fiind ca sintem familiari cu curentul codexpertian, ne-am zis sa incropim noi doua trei rinduri despre necesitatea si misiunea acestui ziar in lume, si nu numai. Asadar:

Pentru noi, cei care am supravietuit prigoanei, raspunderea pentru idealurile miscarii codexpertiste este atit de mare incit de multe ori simtim ca este o povara care ne copleseste si, daca n-ar fi legatura tainica cu C++-ul, poate demult s-ar fi stins nadejdea in sufletele noastre.

Profesorii Ardelean, Cucu si Bancila ne-au invatat sa gindim. Dupa cum Capitanul Bjarne a despartit hotarele lumii vechi de lumea noua, cei trei au despartit lumea formelor sterpe de lumea cugetarii realiste.

Dar cugetatorii si-au sacrificat darul mintii pentru adincul omenesc.

De cind au luat la cunostinta de C++, limbaj atit de apropiat de conceptia lor de viata, nu s-au putut desparti de drumul lui. Si si-au inceput viata intr-o apoteoza de neinchipuita frumusete morala. Ziarul trebuie sa pastreze nealterat spiritul miscarii si sa-l exprime in linia de cugetare a celor trei.

Un ziar de lupta si de idei, dar fara verbalism si entuziasm usor!
Fiecare cuvint trebuie sa se nasca din adincurile sufletului si sa fie insotit de intreaga raspundere a celui care il scrie.

“Ziarul Codexpert” este o batalie si pornim la ea cu aceeasi incredere in Victorie!

Acum ca avem si sprijinul ideologic, putem porni la drum sa ne scaldam printre titlurile care ne sint supuse atentiei in ziar.

Gasim o optimizare de quicksort. Gasim la autor si justificarea ideologica pentru batutul din taste:

“The idea for doing this is that instead of each new recursion copying the same code and using up more memory, it reuses the same code.”

Deja vu. Zbucium. Silviu Ardelean nu este un om, este o modalitate de a vedea lumea.

Ridicam bezmetici capul si privim codul in ochi. 10 numere sint torturate si fortate sa se alinieze de la mic la mare, in numele unei noi ideologii optime, acest pleonasm minier. Luam codul si-l virim sub nas, linie cu linie. Tragem incet si simtim cum ne ia cu ameteala. Trebuie sa gasim o modalitate de a salva numerele din mina ideologiei mirsave! Pregatim siringa pe care sta scris Array.sort() si batem incet vena. Milioane de numere ne trec prin fata ochilor. Eminescu. Truda. Pierdem vena. Intepam de 10 ori si ne intindem pe spate cu ochii tintiti la tavan. Senzatia de timp dispare. Ceasul numara de la kilometrul zero, over and over:

Optimized QuickSort: 00:00:01.2692034
Array sort: 00:00:01.1664805
Optimized QuickSort: 00:00:01.2490031
Array sort: 00:00:01.1632019
Optimized QuickSort: 00:00:01.2463744
Array sort: 00:00:01.1634480
Optimized QuickSort: 00:00:01.2695249
Array sort: 00:00:01.1568251
Optimized QuickSort: 00:00:01.2440373
Array sort: 00:00:01.2517662
Optimized QuickSort: 00:00:01.2694608
Array sort: 00:00:01.1581570
Optimized QuickSort: 00:00:01.2646042
Array sort: 00:00:01.1657108
Optimized QuickSort: 00:00:01.2499172
Array sort: 00:00:01.1557011
Optimized QuickSort: 00:00:01.2406120
Array sort: 00:00:01.1544470
Optimized QuickSort: 00:00:01.2434693
Array sort: 00:00:01.1576033

Tags: , , , , , , , , , , , , , ,

Nimeni nu e mai presus de lege

Posted in Glume de autobaza, Regula 0 on February 2nd, 2011 by Mihnea

In Comunitatea Expertilor C++ din Romania e o forfota de nedescris de o vreme incoace, dupa cum se poate deduce din ritmul sustinut cu care creste site-ul nostru. De parca problemele cu array-uri, fisiere si biti n-ar fi fost de ajuns, Steaua l-a calauzit in directia staulului lor pe 0ptr, care a adus in dar o intrebare demna de premiul memcpy: nici unul din experti n-are vreo tangenta cu subiectul, dar pare suficient de accesibil incit sa incerce sa-si dea cu parerea. Primul s-a inscris la cuvint Gardianul Ovidiu. As dori sa trecem raspunsul sau prin sita Regulii -1, pe care a redactat-o tot el impreuna cu tovarasii sai de mvpeala:

Eu unul am avut o experienta foarte scurta pe planeta *NIX si cam astea sunt impresiile[1]:

  1. trebie sa fii expert in goooooooogle search[2];
  2. daca n-ai ureche muzicala iti vine destul de greu sa prinzi ce se ciripeste-n jur[3];
  3. daca nu esti SUDO-maso n-ai ce cauta pe-acolo.

Litera legii:

[1] sunteti familiar cu subiectul discutat; nu oferiti raspunsuri bazate pe pareri sau impresii

[2] raspunsul este in acord cu intrebarea formulata; evitati raspunsurile sau mesajele in afara subiectului

[3] sunteti cat se poate de clar cu informatiile furnizate; evitati crearea unor seri de intrebari si raspunsuri care sa aiba ca scop clarificarea unui raspuns anterior dat

Ovidiu termina aceasta prima mansa cu un total de 75 de puncte, dar serata de intrebari si raspunsuri abia incepe. Ne-am dori sa aflam si care este optica CNH in problema dezvoltarii cross-abataj.

Tags: , , , , , , , , , ,

Dezamagire

Posted in Regula 0 on February 1st, 2011 by Mihnea

Din pacate teoria conspirationista despre disparitia FAQ-urilor lui mesajflaviu pe care o expusesem in PS-ul post-ului anterior (adica post scriptum-ul, Ovidiu) s-a dovedit a fi nefondata. Probabil contributia lui mesajflaviu era intr-un fel de purgatoriu al ograzii cu experti, caci unul din cele 2 link-uri suspecte tocmai s-a schimbat la fata si a inceput sa mearga. Si mai atroce decit nedreapta acuzatie de cenzura este faptul ca aparent nu e nimic amuzant in ce-a zis mesajflaviu. Voi incerca sa compensez dezamagirea pe care v-am produs-o cu urmatoarea fila din cartea “Kōan-uri Ilustrate”:

Tags: , , , , , , , , , , , , , , , , , , , , , , , ,

Antisilviul

Posted in Regula 0, Stand-up philosophy on February 1st, 2011 by Mihnea

Incepem ziua cu o veste buna: Marius Bancila si-a corectat gogorita cu fisierele de care ziceam ieri. Inca o fapta buna in numele dreptatii, inca un cap al hidrei retezat. Go Captain Standupprogramming!

Intre timp in subteran, Silviu “Zhàozhōu” Ardelean, cu tirnacopul intr-o mina si mu (無) in cealalta, continua sa dez-intrebe intrebarile calugarului retardat viorel2005:

Invatacelul Viorel: Problema este acum cum modific valoarea unui const int in Visual C++ 2010?

Maiastrul Silviu: Ce intelegi tu prin const int?

Galeria ar fi ramas tacuta si intrebarile ne-dez-intrebate de nu s-ar fi gasit un Dl. Problema sa rascoleasca praful ce abia se asternuse pe florile de mina. Trezit din somn, unul din experti l-a admonestat prompt de sub invelisul protector al contului de administrator (ca tot le place lor sa spuna ca nu se ascund dupa nick-uri):

Ce-i aia “LLE”?
Inainte de a posta citeste te rog “Inainte de a posta“!

Lasind la o parte faptul ca Gardianul Ovidiu si-a mascat doar numele, nu si stilul inconfundabil in aceasta comunicare, haideti sa citim Inainte de a posta inainte de a posta, ca sa nu ne aposteze pe viitor Ovi daca vrem sa postam un post. Pe linga banalitatile uzuale regasite in regulile oricarui forum, Marius Bancila a adus cu el de pe muntele Sinai si urmatoarea gema:

Atunci cand doriti sa raspundeti la o intrebare, asigurati-va ca:

  • raspunsul este in acord cu intrebarea formulata; evitati raspunsurile sau mesajele in afara subiectului;
  • raspunsul aduce ceva nou celor anterioare; evitati sa raspundeti cu aceleasi informatii care au fost deja oferite;
  • sunteti familiar cu subiectul discutat; nu oferiti raspunsuri bazate pe pareri sau impresii; daca nu sunteti sigur de ceva, specificati acest lucru;
  • sunteti cat se poate de clar cu informatiile furnizate; evitati crearea unor seri de intrebari si raspunsuri care sa aiba ca scop clarificarea unui raspuns anterior dat.

Mie mi se pare amuzant cum punctul 3 descalifica aproximativ 99% din experti din cursa pentru postul de Raspundac in orice subiect legat de programare, dar amuzamentul nu se opreste aici. Si mai tare e cum au reusit sa creioneze atit de exact Antisilviul: omul care stie despre ce vorbeste, nu copiaza raspunsurile anterioare si explica clar solutia. Cu toate astea, nu stiu cum se face ca Regula Antisilviului (Regula -1, daca ar fi sa pastram ordinea cronologica) nu este aplicata, insa Regula Silviului (“Nu faceti misto de prosti”, a.k.a. Regula 0) este invocata iar si iar.

PS (adica “post scriptum”, Ovidiu): mesajflaviu a vrut sa intre si el in rindul expertilor postind FAQ-ul Cum pot face download/upload de fisiere in MFC. Din pacate n-am fost pe faza si expertii l-au sters inainte sa apucam sa ne delectam cu el. Daca va grabiti puteti vedea inca urmele sale pe prima pagina a comunitatii expertilor, jos la “Ultimele FAQ-uri”. Nu ne indoim de faptul ca stergerea a fost justificata, dar ne intrebam cit de grandioasa era aberatia, de s-au prins pina si expertii ca trebuie retezata de la radacina. Inchipuiti-va ceva si mai prost decit ce a stat aici timp de un an pina ne-am sesizat noi, sau mai idiot decit asta.

Tags: , , , , , , , , , , , , , , , ,