неделя, 23 декември 2012 г.

git goodness (pt. 2)

Lets continue from p1. I promised interactive add, rebase and cherry-pick. Here they come!

interactive add

So here's the use case: you've been working as usual in your git repo, and suddenly a co-worker comes by tell you about this crazy bug. You start working on another thing, in the same branch, without stashing. Then the same happens again, now with a more severe bug. At the end you have a few separe changes going on in the same folder, touching the same files in different (or the same) locations.

Now you want, as a good code monkey, to commit each change in a separate commit. To do this you can use git add -p [filename]. That will prompt for each individual modified chunk, whether you want it added to the index. The cool thing is that you can split a long chunk in smaller ones (using s), or even edit the chunk with your favourite editorvim, for the most control.

rebase

I think rebase is the coolest feature of git. It just lets you modify your history in all ways imaginable, with a pretty neat interface :)

There are a few use cases. First imagine you've been working on some feature on a branch, where other also commit. Now that you have created a few commits and want to push you realize there are new commits on that branch, so you have to somehow combine your commits with the upstream commits. There are 2 options: merging and rebasing. Merging creates a new commit that combines you head with the remote head. It is the most straight forward, but it also complicates the history -- if you run git log --graph you'll see what I mean. If you prefer your history straight you have to use rebase. It moves your commits on top of the remote ones.

If you're contributing to open source project you might be required to rebase your commits on top of the latest HEAD. github pull requests are actually smart enough, so you can rebase and force-push and the rebased commits will appear in place of the old ones.

Another legitimate use case of rebase is to tidy up your commits before submitting them upstream. You can reorder commits, edit old commits, change their commit message and squash a few commits together. Just use the --interactive (or -i) switch -- you'll see all your commits in an editor, you can reorder them by copy-pasting lines, and other actions are achieved by changing the word in the begining of each line. The person who came up with this interface is genius.

The usage is simple (do you expect me to say anything else?): git rebase [on-top-of [what]]. If you're in the branch that you want to rewrite, you can just specify on-top-of, or where do you want to start placing the new (rewritten) commits. what is the branch you want to rebase, in case you're not on it right now. If you just want to rewrite some history, go to the head and say git rebase -i last-unchanged-commit to reorder, reword, squash the commits after last-unchanged-commit.

If you just want to rebase unpushed changes on top of current HEAD, you can use git pull -r -- that is pull and rebase, not merge.

When you hit a rebase issue, you git add the broken files after you've fixed them and you issue git rebase --continue. If shit hits the fan -- bail out with git rebase --abort.

cherry-pick

Cherry pick lets you copy one commit to another place (normally another branch). You just go where you want the commit to be copied, and say git cherry-pick commit-id. That is it. If you were looking for something more fancy -- sorry for the disappointment.

stash (bonus material)

Consider the use case in the interactive add scenario. Only this time you realize on time, that you'd start working on a second thing, so you can save your current changes for later. You just say git stash [-u] and you have a clean folder again, ready for hacking! -u tells stash to also save the untracked files -- really handy. When you're done hacking and want to continue your work you do git stash pop -- which brings back all the changes you'd done before the stash.

вторник, 20 ноември 2012 г.

Keep the internet free (yet again)

https://www.whatistheitu.org/. Прегледайте видеото и линковете отдолу. Ако си дадете мейла, в получения мейл има линк за изпращане на мейл страницата до народните ни председатели. Преведох шаблона на български (все пак искаме да ни разберат посланието). Зори оправи всички грешки в оригиналния превод, за което много благодаря.

Уважаеми г-жо / г-не,

На предстоящата Световна конференция по международните далекосъобщения (WCIT) в Дубай, правителства ще разглеждат предложения за промяна на правомощията на Международния съюз по далекосъобщения (ITU). Някои от предложенията ще дадат възможност на ITU да заплаши прозрачността и иновацията, които направиха Интернет това, което е в момента, ще увеличи цените за достъп и ще намали човешките права в мрежата.

Интернет е мощно средство за комуникация, икономически двигател и разширява човешките възможности. Дискусиите за неговото бъдеще трябва да включват колкото се може повече заинтересовани лица, включително държавни представители, технологични експерти, бизнес лидери, граждани и организации за защита на човешките права.

Пиша ви, за да ви помоля:
- да отхвърлите предложенията на WCIT които дават възможност на ITU да управлява Интернет, и по-специално тези които ограничават човешките права в мрежата;
- да направите обществено достъпни предложенията които България и другите страни ще направят на WCIT;
- да се допитате до мнението на Вашите граждани и експерти по предложенията, включително да поканите заинтересовани страни да вземат участие в Българската делегация;

Организацията ITU е направила много за доброто на света и аз се възхищавам на усилията ѝ. Също обаче споделям мненията на много хора по света които вярват, че взимането на решения относно Интернет трябва да се прави прозрачно, с участието на много заинтересoвани лица от обществото, правителствата и частния сектор, а не само от ITU.

С уважение,


петък, 16 ноември 2012 г.

dbus resolved

In case you've been living in a cave for the last 10 years in regard of Linux desktop managers you've probably missed D-Bus, or at least tried to avoid it as much as possible due to its over-engineered nature or the fact that its not automatically started by your bare bones window manager.

At least I did.

But today I found the best way to experiment/use it in your favorite shell. The command is called qdbus (oh well, you have to install qt for that, but it's worth it!).

  • Without arguments it will print all available services (first level address in dbus).
  • With a servicename as a single argument it prints all paths available for that service name (second level address)
  • With a servicename and path it lists all available methods, signals and events (third level)
  • You can specify all three (service, path, method) (+ arguments) and whoala! You'll never get the bad feeling in your stomach again, when you try to call a method or two via dbus

I hope this will help somebody else.

неделя, 4 ноември 2012 г.

Free leach torrents switch

In case you use lztr us, what.cd, pass the popcorn or anything based on project gazelle, which you shouldn't be doing because it's illegal, you can try passing &freetorrent=1 to torrents.php (in the url bar) and it will list all free leach torrents available at the moment. Just sayin'.

събота, 3 ноември 2012 г.

Dell touchpad recognized as PS2 mouse

I just want to put this online in case somebody has the same issue.

So here's my setup -- I have a Dell Latitude E6430 laptop. I have arch linux installed on it, and the touchpad was recognized as PS2 mouse, hence multitouch gestures were not working, including two-finger scroll and multitouch tapping.

A friend of mine suggested that this was actually not an elantech touchpad, but an ALPS one (low cost elantech). So a different driver was needed. The package that fixed the issue for me was psmouse-alps-driver from AUR. In case you use a different linux distro, try this url -- from the guys who wrote it. It is a replacement psmouse kernel module, built with dkms.

Commands you might find useful:

dmesg | less
and search for PS2
modprobe -r psmouse
remove old psmouse driver
modprobe psmouse
reinsert psmouse driver (after installation)
dkms status
see status of dkms managed modules
xinput
list X input devices

Update 16 Nov 2012

And everything works flawlessly until you decide to upgrade your kernel. You may imagine what would happen with your custom-compiled kernel driver. Just issue dkms autoinstall to recompile the driver against the current kernel, and then modprobe -r psmouse to remove the old one (if any) and modprobe psmouse to insert the new one.

And thats it! Until you upgrade your kernel ...

If you're using arch linux you can enable the dkms.service: sudo systemctl enable dkms.service, so it would do that for you on reboot.


четвъртък, 1 ноември 2012 г.

git goodness (pt. 1)

This post is intended for people, who know the basics of git and want to go to the next level ;-)

Branches

A git branch is just a reference to a commit. You can easily change the reference by git reset --hard <refspec>. The first time you do this you are most probably going to lose some commits :) To see the commits you were on recently, try git reflog, and then another git reset --hard <refspec> to point your branch to the right commit.

Remote branches

These are branches on remote repositories. They are read only -- that is, you can not change where they point to by hand. You can update them with git fetch <remote>. Note that git pull does a fetch and a merge/rebase, so it would update them too.

By default you do not have local branches representing all remote branches, just for master. If you have a remote origin with a branch coolbranch, just use git checkout -b coolbranch origin/coolbranch

Deleting remote branches is odd. Use git push origin :branchtodelete and don't ask me why :)

Tracking branches

You can specify that a local branch is linked to a remote branch, so that git pull and git push work without additional arguments.

If you created a new branch on your local machine and want to push it (to say, github.com), you would do git push -u origin newbranch. -u tells git to set newbranch as tracking origin/newbranch.

When you start working on a new branch from origin, if you do git checkout -b branchname it sets local branch branchname as tracking origin/branchname.

gitconfig

User-wide git configuration resides in ~/.gitconfig. Here is mine, I think its good enough to be shared ;-)

[user]
  email = your.name@email.com
  name = Your Name
[alias]
  st = status
  ci = commit
  co = checkout
  l = log --graph --decorate --pretty=oneline --abbrev-commit --all
[color]
  diff = auto
  log = auto
  status = auto
  branch = auto

Aliases are a great way to save you from typing the most common commands. I also had the habit of using st and co from svn and mercurial, so if you're also used to that add them in.

Everybody likes fancy colors nowadays (even me!), they also make the output more readable. To enable colorful output just include the [color] section and list the commands you wish to see in color. You can also specify the colors used, check the docs for more info on that

Read more about the long line in the next section

history

Checking the repo history is a fundamental operation. I'll explain the most useful options here:

git log <commit>

Lists all ancestor commits of the given commit, or HEAD if no commit is given. The commit hash, the author and the full commit message are shown. Use this if you want to search the history for a given commit (sha128) or words you hope to find in the commit message.

git log -p <commit>

The same as above, but also include the diffs of each commit. Very handy if you want to check the history of something in the source code like a function or variable.

git log <path/to/file>

You may also check the history of a particular file.

git log --graph --decorate --pretty=oneline --abbrev-commit --all

I use this recipe to get an ascii graph of all commits in the repo. I use it so often that I aliased it with git l (check gitconfig above). Experiment with a subset of the options to see what they do.

To be continued...

This turned out longer than I expected. I hope I can post more on this topic, more specifically interactive add, rebase, cherry-pick. Stay tuned.

събота, 11 август 2012 г.

keybinds in console

Наскоро научих как точно се настройва коя клавишна комбинация какво прави в терминала. Сега ще споделя това знание... за да може като го забравя да си го прочета от тук :)

клавиши и комбинации

За съжаление, комбинациите не се задават в някакъв четим формат а приличат на нещо от сорта на ^[Od (ctrl + left arrow при мен) или ^[^[[D (alt + left arrow). За да разберете коя комбинация, на каква последователност отговаря стартирате read, натискате и гледате какво излиза на екрана. Ето какво излиза при alt+up, delete, end на моята машина:

[iskren ~]% read
^[^[[A^[[3~^[[8~

После заместваме ^[ със \e като пишем последователностите, т.е ^[^[[A става \e\e[A, ^[[3~ става \e[3~ и т.н.

команди

След като харесате кой клавиш искате да прави нещо, трябва и да обясните какво точно искате да прави :) За да видите списък със всички команди, в терминал (zsh only tested) натискате alt+x tab tab. В общи линии това са extended commands стил emacs но има и други.

клавишни комбинации + команди

Сега остава да напишете някъде коя комбинация, коя команда искате да стартира. Единия вариант е да ги сложите в /etc/inputrc, където формата е "combination": command. Другия е да сложите в $HOME/.zshrc bindkey "combination" command. Обърнете внимание, че комбинацията се задава в двойни кавички.

четвъртък, 10 май 2012 г.

Arduino + Arch

Наскоро подкарах Arduino UNO ver3 на ArchLinux-а върху лаптопа, затова ще споделя с 2 думи как става понеже е нетривиално.

  1. Инсталирате си arduino пакета от aur (версия 1:1.0-3 при мен)
  2. Създавате си директория, с името на проекта (да речем blink) и вътре в нея основния файл (blink.ino -- basename трябва да съвпада с директорията)
  3. Сваляте си arduino-cmake в директорията на проекта (поддиректория arduino-cmake, ако ползвате gitiпрепоръчително е със submodule)
  4. Създавате CMakeLists.txt файл във blink със следното съдържание:
    set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/arduino-cmake/cmake/ArduinoToolchain.cmake)
    
    cmake_minimum_required(VERSION 2.8)
    project(Blink C CXX)
    
    print_board_list()
    print_programmer_list()
    
    generate_arduino_firmware(blink
        SKETCH ${CMAKE_SOURCE_DIR}
        BOARD uno
        PORT /dev/ttyACM0
        PROGRAMMER usbtinyisp
        AFLAGS -V
        NO_AUTOLIBS)
  5. $ mkdir build
    $ cd build
    $ cmake ..
    $ make
    $ make blink-upload

Ако ползвате друго ардуино може да се наложи да смените BOARD, и/или PORT. За второто може да проверите със ls /dev/ttyACM* /dev/ttyUSB* за да разберете как точно се казва устройството на вашата машина (след като сте закачили arduino-то естествено).

Ако съм пропуснал нещо, пишете да го фиксна ;-)

четвъртък, 2 февруари 2012 г.

Act 4 ACTA

Ако сте чували за SOPA и PIPA (популярно главно в САЩ), то ACTA може да се нарече техен еквивалент в ЕС.

За да се запознаете по-добре гледайте:


След което може да прочетете какво казват по въпроса Григор Гачев, Йордан Юруков, Нели Огнянова.

Накрая може да дойдете на протеста по случая - 11:00 часа на 11 февруари, НДК.

Междувременно докато чакате да дойде протеста може да метнете едно писмо до евродепутатите.

До момента съм получил положителен отговор от Евгени Кирилов. Следващия път като гласувате за евродепутати да го имате предвид!

неделя, 11 декември 2011 г.

Code retreat #3

На 3ти декември се проведе Code Retreat #3.

Събрахме се 20тина души на различно ниво, с основната идея да се осъвършенстваме като програмисти. За повечето TDD беше нова концепция, така че основния фокус беше върху нейното овладяване.

Ще опиша накратко какво научих от срещата:
  • Тестването е хубаво нещо. Ако имате възможност - правете го. Не че не го знаех това и преди, но сега е по-затвърдено :)
  • Тестовете са идеалния начин да се рефакторира кода. Причината е, че при наличие на тестове сме малко по-спокойни и сме готови да направим по-големи промени на кода.
  • Писането на fake-ове, с други думи код, който не е верен в общия случай, но прави така, че тестовете да минават, е установена практика. До колко съм съгласен с нея още не знам :)
  • TDD не е сребърен куршум. Според мен трябва да се използва с мярка. Понякога влагането на малко повече време в началото за взимане на важни дизайнерски решения ще се отплати многократно по-късно. Това, че TDD се фокусира върху конкретното следващото нещо, което трябва да се имплементира, и това по някакъв начин ни успокоява, защото имаме да мислим за малко неща е хубаво, но според мен е твърде силно опростяване.
  • Тестовете са хубав начин за комуникация. Може би много по-добър от вербалната комуникация, защото 1) стоят в репозиторито и 2) могат да бъдат изпълнени. Ако има възможност да се генерира документация и примери от тестове аз съм "за" с 2 ръце. Също - ако може да се намали изпращането на мейли, чатове и вербална комуникация между членовете на един екип за сметка на повече и по ясни тестове, "за" съм с 3 ръце :)
В заключение, TDD е малко или много свързано с писане на тестове. Ако имате удобен начин да пишете тестове не ви коства много да пробвате TDD. Проблема в момента е, че практиката да се пишат тестове не е добре улегнала в повечето проекти, и ако решите да пишете patch за проект, който не ползва тестове, шансовете са че и вие няма да напишете тест, защото първоначалното усилие по изграждането на условия за тестване не е малко. От друга страна ако проекта ползва тестове, то направо е престъпление да го допълвате, без да пишете тестове към него, даже в някои случаи няма да ви позволят.

Така че, ако имате възможност да пишете тестове -- пробвайте TDD. Ако не, поне се старайте новите проекти в които участвате да имат изградена система за тестване, и ползвайте TDD в тях :) Ако TDD не ви харесва, нека това не подбива мнението ви за тестването по принцип.

сряда, 30 ноември 2011 г.

Няколко проблема

Това е превод на /reality. Основната статия ще остане на английски и ще добавям още информация, така че ако се интересувате може да хвърляте по едно око и там.

Мотивация

Нещо ме човърка от вътре. Наблюдавам света около мен и виждам много проблеми и малко решения. Виждам как решенията създават по-големи проблеми, от тези които решават. С други думи -- виждам, че състоянието ни се влошава вместо да се подобрява. Ще отбележа, че въобще не говоря за България конкретно -- проблемЪТ е глобален.

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

Друг важен момент е подреждането на проблемите по важност. Докато "обувките ми убиват", "шапката ми не си отива по цвят със шала" и "не съм подготвен за оперативната среща утре" може би заслужават част от вниманието ни, проблеми като не функционалността на икономика, базирана върху непрестанен растеж, ерозията на почвата породена от агресивни селскостопански методи, изчерпването на евтината и удобна енергия под форма на нефт и природен газ и глобалното затопляне не са за игнориране.

В този пост ще изложа съвсем на кратко една част от по-важните според мен проблеми. Това няма за цел да те стресира или натъжи, а по-скоро да те информира.

Икономика

Измерването на просперитет на базата на растежа на дадена икономика има разрушително действие върху природните ресурси и е напълно неустойчиво в дългосрочен план.

Crash Course Клипчета от 5 до 16 разглеждат икономическите проблеми, главно в Америка.

The American Dream by the Provocateur Network Забавно клипче на тема федерален резерв, банки, заеми дълг.

Енергетика

Евтината енергия под формата на нефт и природен газ е на изчерпване. Нужно е да се вземат мерки навреме за да не се стигне до момент, в който 90% от техниката не може да работи защото не използва подходяща енергия, или защото просто не може да се произведе достатъчно. Нефтът също се използва и като наторител за голямо количество селскостопански култури -- ако не се ползва добивът рязко ще падне.

300 years of fossil fuels in 300 seconds Кратка история на изкопаемите горива.

Wikipedia - Peak Oil Проверете фактите директно от уикипедиа (и прикачената информация). Peak Oil може и да е трик на производителите да вдигнат цената, но това, че петрола е крайно количество не е.

Reinventing the Leaf Кратка лекция за един научен проект, целящ да добива въглерод директно от светлина. Интересен е увода, в който професора изтъква, че слънчевата енергия е най-перспективна в дългосрочен план, и единственото друго решение е да строим по една атомна централа всеки ден в продължени на 40 години :)

Околна среда

Jeremy Rifkin - the crisis that we face Ако смятате, че глобалното затопляне ще направи зимните спортове по-трудно достъпни, а летните по-приятни, гледайте това видео!

Wikipedia - Global Warming "Глобално затопляне" -- това се превърна от проблем, нуждаещ се от решение в buzzword. Смятам, че всеки трябва да си набави качествена информация по темата (примерно укипедиа) и да реши сам за себе си сериозността му.

Очаквайте още по темата.

четвъртък, 10 ноември 2011 г.

CoffeeScript + Node.js

CoffeeScript е език, компилиращ се до JavaScript, със семантична идентация, вдъхновен от Ruby.

Ако планирате да пишете на Node.js, инсталацията е доста лесна

node.js

$ git clone https://github.com/joyent/node
$ cd node
$ ./configure --prefix=~/opt/node && make && make install
$ echo 'export PATH="$PATH:$HOME/opt/node/bin"' >> ~/.bash_profile
$ export PATH="$PATH:$HOME/opt/node/bin"

npm

$ curl http://npmjs.org/install.sh | sh

coffee-script

$ npm install -g coffee-script
Ако всичкия server-side код е на coffee-script директно полвайте coffee за да го изпълните (вместо node). Ако искате от javascript файл да require-нете coffee-script файл (без да го компилирате), тогава
require('coffee-script');
require('./script'); // assuming you have ./script.coffee
За любителите на vim има и плъгин.

Селектиране на текст с vim

Във vi / vim / gvim последната селекция може да бъде селектирана отново с комбинацията gv (normal mode).

При желание може да се автоматизира селектирането след операция за идентация
vnoremap <tab>   <gv " tab indents
vnoremap <s-
tab> >gv " shift-tab unindents

Също може да се скача в началото/края на последната селекция
`< `> - в абсолютното началото/край на селекцията
'< '> - на първия символ на първия/последния ред на селекцията

сряда, 5 октомври 2011 г.

не бъди расист

Ако си мислиш, че някой етнос / хората, които принадлежат на него, са виновни за каквото и да било, или пък без тях нещо ще бъде по-добре, чети надолу.

Действията на хората не зависят от етноса им, а от средата, в която живеят. Ще дам нагледен пример. Вземи едно новородено българче и едно новородено циганче и им размени семействата. Т.е. циганчето започва да живее в българско семейство, родители българи, евентуално братя/сестри българи, съседи българи (представете си средно-статистическо българско семейство), а българчето отива да живее в циганското семейство – може би десетина братя/сестри, в една къща, не достатъчно пари за изхранване на всички, вероятно в краен квартал, съседи – други цигански семейства (средно-статистическо циганско семейство).

Сега въпросът е: ще може ли да различите след 15 години българчето от циганите, съдейки по начина, по който се държи (а не по цвят на кожата, например). Ако не може да бъде различено, тогава всеки, който има нещо против циганите по принцип, би трябвало да има и също толкова против това българче. От друга страна, циганчето, което е живяло в българско семейство, има по-големи шансове да завърши училище, евентуално университет, да си намери по-добре платена работа, да живее по-добре с две думи. Разбира се, то най-вероятно ще има проблеми заради цвета на кожата си, но това донякъде може да бъде преодоляно с грим (все пак жените го правят постоянно ;-)).

Опитвам се да кажа, че циганите (или кой да е друг етнос) не са такива, каквито са, заради биологичните си родители, а заради обстановката, в която са се развивали. От една страна, тази среда е създадена от тях самите, но ако в цялата страна имаше само цигани, те нямаше да имат проблем с "циганите", а с "хората". Т.е. средата в която живеят те е, малко или много, повлияна от начина по който се държим ние. Самият факт, че си имат име, по което да бъдат разграничавани, е лош, сам по себе си. Ако средно статистическият българин не е враждебно настроен към циганите, то поне се стреми да има колкото се може по-малко общо с тях. Това изглежда безобидно, но всъщност е в основата на разделението.

Докато всички не се наречем Българи (а следващата логична стъпка е Хора) и не се изправяме пред проблемите, които имаме, без да взимаме под внимание незначителни фактори от историята – кой къде и от кого е роден, родителите му къде и от кого са родени, техните родители и т.н. – няма да постигнем значителен напредък.

Относно медийното покритие на събитията около Кирил Рашков — самият факт, че те бяха толкова добре отразени, не за нещо друго, а защото престъплението е междуетническо (в смисъл, циганин посяга на българин) е плашещ. Просто расизмът се харчи доста добре в България, не се поддавайте! Всеки, който е извършил престъпление трябва да си получи заслуженото, независимо от това от каква народност е, и от каква народност е потърпевшият.

четвъртък, 19 февруари 2009 г.

Искрен on Rails

Тук ще напиша набързо решенията на проблемите, който възникнаха при първия ми по-сериозен сблъсък с web-framework-а Rails (предназначен за езика Ruby).

1. Инсталиране (тук ще карам малко по спомен)
# сдобивате се някак си със rubygems - това е пакетния мениджър на Руби (за линукс потребителите - потърсете за подходящ пакет за любимата ви дистрибуция)
gem update --system # ъпдейтвате rubygems най-вече
gem install rails --version 2.2.2 # инсталирате рейлс
gem install postgresql-pr # инсталирате адаптера за работа с postgres (ако разбира се искате да ползвате postgres - по дефоулт 2.2.2 идва със sqlite3)
gem install rspec-rails # инсталира rspec - най-новия писък на модата, тъй нареченото BDD - Behaviour Driven Development

2. Предварителни настройване на проекта
rails my_app # създава папка my_app със скелета на цял рейлс проект
# от сега нататък приемам че се намираме в папката my_app, създадена по-горе
haml --rails . # добавя haml към проекта (това е удобен темплейтен език, изглежда по-добре от дефоултния erb)
ruby script/plugin install git://github.com/technoweenie/restful-authentication.git # инсталирате си restful authentication
mv vendor/plugins/restful-authentication vendor/plugins/restful_authentication # !!много важно - променяте името на плъгина (махате му тирето) - без този ред не работи като хората
ruby script/generate authenticated user sessions --rspec # база на аутентикацията (т.е user-и и сесии)

четвъртък, 1 януари 2009 г.

свободна музика?

Отдавна не бях блогвал, но стечението на обстоятелствата (което ще опиша след малко) беше предпоставка за това да прегледам блога на Яна и да видя ... линка към моя блог, което пък ми напомни че и аз имам 'таковъ животну' ... както и да е :)
Значи напоследък забелязах че apache-то ми се държи странно (apache е web сървър - демек нещото което като човека X напише в любимия си браузър "http://iskren.info" показва грозна зелена страница). И тъкмо ме бяха обхванали мрачни мисли свързание с форматране, преинсталиране, рестартиране (последното имаше донякъде положителен ефект) когато ми дойде гениална мисъл ... да му погледна log-а. Дам ... като се сетих (толкова късно) направо ми стана гадно, че се познавам.
Та - гледам аз лога на апачето и какво да видя - постоянни request-и от всички краища на планетата, хвърчат към моето apache-нце и то неуморимо ги удовлетворява. И понеже първото на което ми попадна погледа беше достъп на файл в една от директориите на Пешо веднага си казах - той се е разчел нещо. Но уви - след като му писах веднагически, отговори че не той е ровещият се в сървъра. След кратка мисловна пауза и по-подробно разглеждане на лога останових ... че някакви сайтчета индексират моя, за да може да пускат "безплатна музика" на хората, които ги посещават (например http://grooveshark.com).
Следващото нещо което направих, беше да потърся iskren.info в google. След самата страница и мой цитат в блога на Яна, изплуваха и мистериозните сайтове предлагащи безплатна музика, който просто сочеха към сървъра ми. След като се загледах по-подробно в единия от сайтовете, реших да прочета "Terms & conditions" - е да, хората повториха 101 пъти, че музиката не е на техния сървър и те не носят никаква отговорност за нея, нямат никаква връзка с хората, на чиито сървъри е музиката ... итн, итн.
От една страна ОК - имам музика, сложил съм я (вече) за свободно сваляне от http-то, за да мога по-лесно да пусна на някой приятел някоя песничка, която ме е накефила. Обаче това диво адресиране от всевъзможни сайтове, тази популяризация ... няма ли да почукат на вратата след някой друг ден 2-3 гардероба и да поискат нечии хард?
Майната му! Като съм решил да имам общодостъпна музика на компютъра - така ще бъде! Защо трябва само да се крием и да слагаме пароли на всичко? В крайна сметка това е един от плюсовете на това, че не живеем в Америка - страната на неограничените възможности ... на държавата спрямо гражданите й.
За много години на всички (ако някой въобще чете това), и да бъде свободата :)

петък, 23 май 2008 г.

<T>emplate magic

Просто не мога да се сдържа да не се похваля какво извращение успях да подкарам на C++ наскоро. Става дума за тип, в който може да се слага всеки друг тип (по един във всеки момент) и да се взима текущия тип (като се каже какъв е). Т.е исках да върви подобен код:


generic x;
x.set (5);
x.get <int> ();//--> 5
x.set (std::string ("alabala"))
x.get <std::string> ();//--> alabala

//type checking
x.is <int> ();//false


Та значи горното нещо в началото ми се струваше сън, докато не осъзнах, че е напълно реално - нужни са само 2 помощни класа (т.е общо 3) и горният код РАБОТИ.

Накратко:
1. Абстрактен базов клас, поддържащ методи set и get, приемащи/връщащи void *
2. темплейтен наследник на горния клас, в който се пази указател към T, но самите функции разбира се връщат пак void * (защото са в йерархия)
3. клас wrapper на горния, който не е темплейтен, но съдържа темплейтнати функции (т.е класа не е темплейт, но някой негови функции са), който държи един указател към базата и когато поискат нещо от него той прави dynamic_cast до наследник от искания тип, след което каства резултата към нещо човечко (т.е void * --> Т * --> Т). Хубавото е, че примерно set функцията сама разбира типа на шаблона (дедуцира го от аргумента) - затова няма смисъл да го пишем изрично (т.е set <int> (4). За get функцията обаче е задължителен (е няма пълно щастие :) ).

Хубавото тука е, че се извършва type checking от компилатора (при dynamic_cast), както и освобождаването на заделената памет от виртуалния деструктор на 2рия клас - т.е общо взето прехвърляме задълженията си към компилатора (както и според мен трябва да се прави).

п.с.: За да е малко по-полезно това чудо добавих и функция, която преобразува всеки тип до стринг (за да мога да печатам по лесно наред). Та наложи се да сложа и темплейт-специализация на тази вункция за типа int (т.е функцията to_str за едни типове да работи по един начин, за int да работи по друг). Тази функция, се третира като нормална, и за това трябва да стой в cpp файл, който се линква отделно (т.е не в h/hpp файла със шаблона, защото ако се инклудне от поне 2 места става мазало). По принцип темплейтите трябва да са написани в един h файл, защото компилатора не позволява да ги разделяме (extern template не е имплементирано почти никъде), но точно специализациите може (и трябва) да се пишат в отделен файл - иначе казва redefinition of ...


#include <cstdio>
#include <string>

class base {
public:
virtual void *get () = 0;
virtual void set (const void *) = 0;
virtual ~base () {}
};

template <typename T>
class derived : public base {
T *_data;
public:
derived () : _data (NULL) {}
virtual void *get () {
return static_cast <void *> (_data);
}
virtual void set (const void *data) {
delete _data;
_data = new T (*static_cast <const T *> (data));//copy constructor
}
virtual ~derived () {
delete _data;
}
};

class wrapper {
base *_p;
public:
wrapper () : _p (NULL) {}
template <typename T> T get () {
return *static_cast <T *> (dynamic_cast <derived <T> *> (_p)->get ());
}
template <typename T> bool is () {
return dynamic_cast <derived <T> *> (_p) != NULL;
}
template <typename T> void set (const T &nv) {
delete _p;
_p = new derived <T>;
_p->set (&nv);
}

};

int main () {

wrapper x;
x.set (5);
printf ("%d\n", x.get <int> ());

x.set (std::string ("alaabala"));
printf ("%s\n", x.get <std::string> ().c_str ());
printf ("%d %d\n", (int)(x.is <int> ()), (int)(x.is <std::string> ()));

return 0;
}

сряда, 30 април 2008 г.

pointer-to-member-function C++

(който не разбира заглавието - става дума за указатели към член-функции в класове на C++ - който и това не разбира да го прескочи :))

Ако искате да напишете код, който да работи с даден обект и да вика негова функция, обаче самата функция да може да се променя (т.е да напишете по-обща функция един вид) тогава е полезно да може да предавате така наречения указател-към-член-функция. В следните няколко парченца код ще опитам да покажа как точно става това граматически - на книжовен C++, защото лично аз имах малко проблеми докато докарам синтаксиса преди няколко дена.

Основният проблем е, че типът на една функция, която е в клас не е просто връщана-стойност (*) (аргуенти), защото тези функции получават един неявен указател this, който сочи към данните на обекта. Освен това този указател е от различен тип за всеки клас (т.е не може просто да кажем че това е member функция и да стане) - трябва като цитираме съответна функция да кажем и от кой клас е:
името-на-класа::името-на-функцията
.
Сега вече типа става:
връщана-стойност (име-на-клас::*име-на-функция) (аргументи) [const]

забележете, че ако функцията е const трябва да го кажем изрично - защото от това зависи типа на указателя this, който както казах неявно се предава.


class cls {
int mem_fun (const char *) const;
static void static_mem_fun (double, char);
};


Ако искаме да подадем mem_fun на някоя фунция (за да може тя да вика точно тази функция за даден обект - обекта отделно трябва да го дадем разбира се) трябва да я приемем по следния начин:
void mem_fun_user (const cls &c, int (cls::*f) (const char *) const) {
/*по този начин я викаме - обърнете внимание на скобите и звездата*/
/*ако c беше указтел към клас тогава викаме със '->*' */
int p = (c.*f) ("haha");
}

сега остава да покажа как се предава :)

void foo () {
cls c;
/*не слагайте допълнителни скоби, или аперсанта другаде - НЕ РАБОТИ - точно както съм го дал така :)*/
mem_fun_user (c, &cls::mem_fun);
}


Можете да подавате и указатели към оператори - просто трябва да ги изпишете (style="font-family:courier new;">&rational::operator +) - държат се като обикновенни функции (но се викат по интересно ;)).

При статичните функции е по-лесно - защото при тях няма този скрит указател this който казва на кой клас е. Т.е техния тип е като на обикновенна функция, а за да ги подадете пишете име-на-клас::име-на-функция както при член функциите

Ето една страничка с (може би) малко по-подробна информация по въпроса:
http://www.parashift.com/c++-faq-lite/pointers-to-members.html

понеделник, 28 април 2008 г.

Сефтето на блога

Ето го и първия пост :) Дано не зарежа и това начинание, както много други.
Като ми дойде музата пак ;)