Нова версия на приложението за чистене на линкове

Може да е малко нарцистично, но приложението ми за махане на глупости от URL-и ми влиза в употреба постоянно и му се радвам много. Когато не ми се налага да разкарвам tracking параметрите ръчно, споделянето става по-лесно, което пък увеличава честотата на спама, който пръскам насам-натам. Win-win.

Малко след като пуснах първата версия, в приложението на Instagram (поне при мен) за известно време изчезна опцията за share и остана само “Copy Link”. Оттогава искам да направя нещо по въпроса, но поради една или друга причина това все оставаше на заден план.

Тъй като за днес си бях набелязал много неотложни неща за правене, реших да ги зарежа и да обърна внимание на Link decrapifier-а.

От Android 6.0 в менюто за избран текст може да се добавят елементи, които да работят с него по някакъв начин. Това става, когато някое Activity дефинира intent filter за PROCESS_TEXT.

Long story short, направих го да ми е по-удобно и вече мога да правя така:

И така:

В зависимост от това дали избраният текст е read-only (EXTRA_PROCESS_TEXT_READONLY) разбирам какво да се покаже при Unwrap менюто (видеото отгоре).

Освен промените по интерфейса оправих и глупав бъг в backend-а на приложението, заради който share-ването на текст от Twitter водеше до MalformedURLException.

Засега ми върши идеална работа, но по-нататък ще го пипна малко. В момента след “unwrap” остава само първият URL. Другият текст изчезва. Освен това се работи и само с първия адрес от избрания текст. За момента не виждам смисъл да си усложнявам живота с обикаляне на неограничен брой адреси, които могат да имат (почти) неограничен брой redirect-и зад себе си.

Друг потенциален проблем е, че няма дискриминация на избрания текст и двете ми менюта (Clean и Unwrap) се показват във всички случаи. Менюто, което само разкарва ненужните параметри и замества текста, е безсмислено в уеб страници, но засега не виждам умен начин да го махна. Потенциално решение е да оставя само едно меню и да добавя опция в настройките, според която да се избира дали само ще се почиства или ще се “разгъва” избраният текст. Засега не ми се усложнява толкова.

И като край – приложенията ми в момента имат между 300 и 500 активни инсталации. Без нито един crash или ANR, откакто са пуснати 🙂

Lab

Както писах преди, от доста време искам да имам физически сървър вкъщи, който да си администрирам и гавря, както реша. В началото на годината по щастливо стечение на обстоятелствата това се случи и в момента се радвам на един HP ProLiant ML350 G5.

Това се оказа несвършващ проект и от януари не съм спирал да си играя и да уча нови неща. От по-важните услуги, които се търкалят засега, са: OpenVPN, HAProxy, Let’s Encrypt, Pi-hole, FreeNAS, Jenkins, Graylog, Transmission и NextCloud.

Сървър

Първо спецификациите на сървъра в текущото му състояние:

CPU Един Intel Xeon E5440 @ 2.83GHz
RAM 32GB FBDIMM ECC (8 по 4GB)
RAID 5 3*250GB
RAID 0 1*2TB

За момента RAID конфигурацията е такава, защото: а) не съм купил дискове за повече и б) нямам caddy-та за останалите два слота. Предстои ми доста интересно приключение, когато реша да разширявам storage-а. Нямам търпение rebuild-а на някой масив да гръмне. Най-вероятно ще трябва да купя още един RAID контролер и да присадя drive cage на мястото на CD-то, за да има къде да сложа всичките дискове, които искам. Шест 4-терабайтови диска в RAID 6 биха били достатъчни за известно време.

На RAID 5 масива се намира ESXi 5.5 (HPE image) заедно с datastore-а за някои виртуални машини. На самотния 2TB диск е storage-а на NAS-а, където има разни важни файлове.

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

Малко след като нарисувах горната графика, lime2 се пенсионира и вече не е backup OpenVPN. Намира се в процес на прехвърляне на всички неща от стария OwnCloud и backup partition към NAS-а. Тази малка машинка беше цялата ми инфраструктура допреди няколко месеца.

Чувството всички (важни) машини да са свързани през гигабитова връзка е прекрасно! Мога да редактирам видео файлове в Premiere Pro, които се намират върху FreeNAS-а, който работи върху една от виртуалните машини, без да усетя някакво забавяне. Няколко клиента спокойно стриймват видео файлове през SMB, nfs и каквото още дойде, без да има никакви проблеми*.

Най-накрая подкарах и Grafana, която да ми харесва и върши работа, а не да е просто eye candy. Повечето данни идват от Telegraf, който ги събира по SNMP и ги пази в InfluxDB.

По-интересните неща, като цената на тока и данните от ESXi, идват от един Python скрипт, който използва SDK-то за ESXi (pyVmomi). Оказа се значително по-лесно така, отколкото с Java SDK-то, което работи директно със SOAP-а на ESXi. Така и не можах да го подкарам.

Цялата работа на скрипта е да се върже за VMware-а, да вземе данните, да scrape-не текущата цена на тока от сайта на Енерго-ПРО и да запише всичко в InfluxDB.

Тъй като го писах с идеята да го оправя “някой ден”, сега при всяко изпълнение се обръща до сайта на Енерго-ПРО. Това води до интереснa статистикa за последните 24 часа в Pi-hole:

 

Поиграх си доста и с ILO-то. Толкова е старо, че мога да го отворя само през Internet Explorer, защото само този браузър все още поддържа несигурни и стари SSL сертификати.

Когато инсталирах втората партида от 16GB RAM, се сблъсках с друго интересно нещо. Заради изгоряла плочка прекарах няколко часа в дебъгване на проблема. В NVRAM-а на дъното се беше записало, че в дадения слот има изгоряла плочка и докато не го изтрих няколко пъти, не се събуди дори само със здравите плочки.

Мрежа

За основен рутер използвам pfSense, който работи върху един HP thin client. Тънкият клиент се оказа напълно адекватен избор за това.

Външната връзка и WAN интерфейсът на рутера са сами на един VLAN, а на друг VLAN са всички останали устройства.

За първи път настройвах суич през конзолен кабел с истинска цел, а не за упражнение. Прекарах няколко вечери до 3-4 сутринта, докато се стабилизира мрежата. Добре че имаше кой да ми даде акъл.

Някога ще разделя клиентите на VLAN-и според предназначението им. Освен това ще е хубаво и да взема втори управляем суич с пасивно охлаждане. В момента в стаята ми е Zyxel-а, а вторият суич е истински, rack-mountable, 1U. Чувам го през две врати.

За безжичните устройства ползвам два обикновени consumer рутера, които работят в режим AP. Доскоро работеха с едно SSID, за да покрия нявсякъде. Имаха проблеми с някои клиенти с по-стари wi-fi модули и ги разделих на две SSID-та. Някога ще бъдат смемени с UniFi AP-та.

Първият ми тест на мрежата беше да копирам файл от основния компютър към NAS-а. Започваше със 100MB/s и почти веднага падаше на 1-2MB/s и надолу. След недоспиването от борбата с мрежите, вече бях напът да режа кабели, но пък netperf показваше, че мрежата успява да се запълни спокойно до гигабит.

Така пак научих, че върху RAID контролерите съществува кеш (в случая – с неработеща батерия), който при неправилна настройка на read/write съотношението прави писането бавно (изненада!). След като го оправих, нещата се нормализираха и вече bottleneck-а при писане върху NAS-а е само скоростта на дисковете. Тук също се радвам, че имаше кой да ми даде светлина. В момента съотношението е 5/95 за четене/запис.

Това с кеша е от нещата, които се налага да правиш изключително рядко и ако са направени правилно, забравяш, че съществуват. Също като настройването на Nagios. Както често твърдя – Nagios-а е най-стабилното нещо в живота ми.

Услуги

Основното нещо, за което исках да ползвам този сървър, е NAS и смятам, че засега се справя добре с тази си задача.

Имах много време да мисля какво искам да използвам за NAS софтуер и накрая се спрях на FreeNAS. Минах през всевъзможни варианти много преди да имам физически съврър и FreeNAS върху виртуална машина ми пасна най-добре. Разбира се, има и някои недостатъци на виртуализирането, но досега не съм се сблъсквал със сериозни проблеми.

Ако не друго, то поне охлаждането на процесора е адекватно. Все пак малко хора могат да се похвалят с процесори, които работят на температура под абсолютната нула.

Върху FreeNAS-а работят няколко jail-а. Основните са Transmission и NextCloud. Благодарение на Transmission имам една директория в share-а на NAS-а, която се следи за torrent файлове, които автоматично се добавят за теглене. Изтеглените неща се намират в друга директория, достъпна от всички устройства в мрежата. Така пиратстването свободното споделяне на медия с уредени авторски права е значително по-лесно.

 

NextCloud-а ми служи основно за синхронизиране на файловете от телефона и разни маловажни неща между компютрите. Първо ползвах OwnCloud, който се хостваше върху малкото OLinuXino (Lime2). Доскоро за off-site backup ползвах NextCloud върху единия droplet в DigitalOcean, където добавих 50GB Volume, върху който трябваше да са само най-важните неща. След известни проблеми с rsync реших, че Google Photos ми е достатъчен за off-site въпреки компресирането.

 

pfSense е доста полезен инструмент. Освен стандартните услуги, които трябва да предоставя един рутер (DHCP, DNS, etc.), в момента върху него работят доста неща, като по-интересните са: HAProxy, OpenVPN и plugin, който се грижи за Let’s Encrypt сертификатите.

OpenVPN-ът ми върши идеална работа. Няма много за писане откъм конфигурация, защото интерфейсът на pfSense е достатъчно прост и цялата работа се свежда до нацелване на разни стойности. Предишният VPN, който бях подкарал върху OLinuXino-то, беше по-интересен, защото цялата инсталация беше на ръка с всичките генерирания на сертификати за сървъра и клиента, както и настройването на рутирането и firewall-а. В pfSense всичко е графични интерфейси.

Сега мога да се закача за мрежата вкъщи, където и да съм, и с едно mount nas.miskin.in:/mnt/whatever /mnt/nas/ имам достъп до NAS-а.

Не бях работил с HAProxy преди това. Засега имам 20 frontend-а и 13 backend-а. Фронтендите са разделени под два основни за услугите с и без SSL. В общия случай са огледални – вместо да се реже достъпа без SSL, има frontend, който прави 301 redirect към същия адрес, но с “https://”.

20-те фронтенда могат да се свият до два, но засега така ми изглежда по-подредено и лесно за поддръжка. Бекендите са толкова малко, защото на Apache-тата отзад са конфигурирани виртуални хостове и е достатъчно да закарам заявката до правилната машина. След това уеб сървърът се дооправя с рутирането.

Както казах, повечето услуги работят през https. Това става благодарение на Let’s Encrypt. Оказа се малко по-интересна заигравка с HAProxy, за да мога да отговарям правилно на challenge-ите, които идват от Let’s Encrypt при издаване и подновяване на сертификати.

 

Ако не си личи, мразя рекламите с яростта на 1337 слънца. Благодарение на това всички компютри, до които имам достъп, веднага биват снабдени с някакъв AdBlock софтуер. С телефоните това се оказва излишно сложно и неудобно – не искам да ползвам друг браузър, не искам да root-вам телефона и т.н. За спирането на поне част от рекламите върху устройствата в мрежата използвам  Pi-hole. Тъй като все още нямам Raspberry Pi, се наложи да инсталирам Pi-hole върху старото OLinuXino (a.k.a sexy). Не му пречеше особено, че прекара няколко години затворено в кутия и в момента всички DHCP клиенти в мрежата (дори някои от тези с резервирани адреси) го ползват като главен DNS. Получи се доста добре и не усещам никакво забавяне, където и да е. Не помня всички проблеми, които излязоха по време на “инсталацията”. Помня само, че ми се наложи да ровя из инсталационния скрипт, защото имаше допуснати разни предположения за системата, които може и да са верни за Raspberry Pi, но при OLinuXino седят по различен начин. Намерих и полезен скрипт, който събира статистика от Pi-hole в InfluxDB (pi-hole-influx) за ползване в Grafana.

 

Друга основна услуга, която ползвам редовно, е Jenkins. Инсталирането и конфигурирането са тривиални. Забавата тук е при конфигурирането на job-овете.

Разделил съм ги на основно два типа – backend и frontend. Backend job-овете се отнасят до Spring Boot проекти, а другите – Node JS базирани (най-често Vue). Всеки един job се задейства при push в конкретен бранч на конкретен проект. Това става с прост hook в GitLab. Тук идва едно от многото удобства на HAProxy – понеже не исках Jenkins да се вижда извън локалната мрежа, настроих Jenkins frontend-а да приема заявки отвън само от GitLab.

Общо взето за всички проекти правя build и deploy по сходен начин. Java проектите се компилират и пакетират с Gradle. Преди build-а Jenkins се закача за сървърa, на който ще се деплойва, и затрива старите jar-ове. След това се нагласят конфигурационните файлове, с които трябва да работи Docker Image-а (cp log4j2_docker.xml log4j2.xml например) и се започва с Gradle-а. При успешен build готовия jar се копира на целевия сървър и се trigger-ва job-а за redeploy (ако за конкретния проект ми трябва автоматичен redeploy).

Redeploy job-овете са изключително прости. През SSH се закачам към сървъра, където ще се деплойва, правя Docker Image от jar-а, спирам, изтривам и стартирам наново контейнера, в който работи приложението.

При неуспешен build си пращам имейл, за да знам, че нещо се е омазало.

За фронтенд проектите е аналогично. Разликата е основно в това, че вместо gradle build се извикват npm install и npm run build.

 

Споменах, че за Spring приложенията се налага използване на различна конфигурация. Причината за това е, че някои от страничните проекти заживяха интересен живот и се наложи да са достъпни публично. Така приложението се налага да може да работи на три среди – local, dev и prod. Очевидно е какво е local. Dev средата се използва при изпълнение на тестовете по време на Jenkins build-а, а prod е това, което се вижда, когато проектът се достъпи публично.

Засега използвам Graylog за събиране на логовете от всички приложения. Това, обаче, ми излиза скъпо, защото на една машина вървят ElasticSearch, MongoDB и Graylog. На практика излиза, че 10GB RAM са недостатъчни, когато идват над 20 съобщения в секунда и се усеща забавяне. Излиза ми скъпо, защото потреблението на ток на сървъра скача осезаемо, когато се върши някаква работа с Graylog и се хабят изчислителни ресурси нещо, което може да се реши по по-лесен начин.

Обмислям да бутна приложенията да пращат имейл при някакъв проблем вместо да логвам всичко навсякъде. Поне докато не стигна някаква възвръщаемост, която оправдава по-високата цена на работата с Graylog.

 

Освен всичко описано дотук, по разните виртуални машини вървят всевъзможни други услуги: MySQL, PostgreSQL, RabbitMQ, Redis и още, и още. Все още успявам да се справя с поддръжката на всичко сам и ми е все по-интересно. По-горе писах, че използвам GitLab. Смятам скоро да си пусна една инстанция при мен, за да видя дали все още е толкова лаком за ресурси.

Проблеми

Основният ми проблем със сървъра е, че като сравнително стара enterprise машина, не е обърнато много внимание на ефективността на потреблението и във всеки един момент дърпа около 256W. Това е при включено само едно от двете 1000W захранвания. При две idle потреблението скача до около 280W. Грубата сметка идва около 40лв. на месец (без ДДС и всички такси: за пренос, загуба, “да има” и др.). Не е най-скъпото удоволствие на света, имайки предвид колко много неща мога да уча благодарение на него, но като знам, че мога да ги постигна с по-малко похабена енергия, ме човърка.

Друг проблем е шумът от вентилаторите. С качването на температурата през последните седмици, все по-често заварвам следната гледка:
Интересно е, че при по-ниска температура навън паметта достига 75-76 градуса без да вдигне осезаемо скоростта на вентилаторите. Въпреки това, суичът си остава по-шумен.

Преди няколко седмици трябваше да изключа всичко, защото имаше профилактика на захранването. Беше забавно, защото чак тогава си дадох сметка колко много неща съм закачил през последните месеци.

Бях оставил всичко да събере прах, за да се чувствам като в истински datacenter.

След включването на всичко, изненадващо, имах само един малък проблем – конфигурацията на суича не се беше запазила и SNMP-то му беше спряно, заради което в Grafana-та не излизаха статистиките за него. Всичко друго заработи без да се оплаква.

Оттук нататък приоритет ми е събирането на дискове за разширяване на storage-а, тъй като той ми умалява най-бързо. Може би и втори процесор, за да няма празни дупки.

Следващото най-важно нещо е да се сдобия с по-съвременна машина, която да не е толкова лакома за ток и да поддържа SSD по-лесно.

Мога да пиша още много, защото постоянно излизат интересни неща, които искам да пробвам, но ще спра дотук.


*Ако не броим нестабилността на sshfs и nfs mount-овете на лаптопа, които решават да потрошат всичко, когато го приспя и събудя. Някой ден ще дойде и неговия ред.

Използване на Java Reflection API за мързелива “документация” на response кодове

В единия от страничните проекти използваме REST за комуникация между фронтенда (Vue) и бекенда (Spring Boot). Приложението е сравнително просто и пиша бекенда сам и за документация на REST-а използвам Swagger. Това значително услеснява имплементацията на фронтенда откъм информация за endpoint-и и кой какво може да очаква като заявка/отговор.

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

Механизмът, на който се спрях за връщане на грешките към потребителския интерфейс, е сравнително прост и не е нищо ново – при грешка в бекенда към клиента се връща DTO с цифров код и пояснителен текст. Пояснителният текст служи само за улеснение на пишещия фронтенда. Локализацията на грешките, ако се наложи да има такава, ще се случва във Vue приложението според цифровия код.

В Spring това се имплементира изключително лесно. При неправилно действие (няма достъп, липсва задължително поле и т.н.) се хвърля Exception (в случая – ErrorResponseException), който се прихваща от @ExceptionHandler и към клиента се връща DTO-то с нужния код и текст. За имплементацията на този механизъм са нужни няколко основни неща:

  • Номенклатура на кодовете на грешки и клас, описващ формата на отговора, който очаква Vue приложението,
  • Някой да прихване Exception-а,
  • Exception за прихващане.

Номенклатурата е обикновено POJO със статични методи за всяка грешка:

import lombok.Data;

@Data
@AllArgsConstructor
public class ErrorResponseDTO {

    private Integer code;
    private String message;

    // 500
    public static ErrorResponseDTO generalError(Throwable t) {
        return new ErrorResponseDTO(500, "I can't even: " + t.getMessage());
    }

    // 1401 - JWT token expired
    public static ErrorResponseDTO tokenExpired() {
        return new ErrorResponseDTO(1401, "Token expired");
    }

    // 1402 - Invalid JWT token
    public static ErrorResponseDTO invalidToken() {
        return new ErrorResponseDTO(1402, "Invalid token");
    }

    // ...
 
    // 1409 - User is not active
    public static ErrorResponseDTO userIsNotActive() {
        return new ErrorResponseDTO(1409, "User is not active");
    }

    // ...
    // Още много статични методи, описващи останалите грешки
    // ...
}

Горното може да се реализира по много начини. Засега това ме устройва. Не смятам, че проектът ще стане достатъчно сложен, за да оправдае разделянето на тази номенклатура от DTO-то или категоризиране на грешките в отделни класове, пакети, Exception-и и т.н.

Прихващането на Exception-а става с @ControllerAdvice и @ExceptionHandler:

@ControllerAdvice
public class RestExceptionHandler {
    // ...
    @ExceptionHandler(ErrorResponseException.class)
    @ResponseStatus(HttpStatus.PRECONDITION_FAILED)
    @ResponseBody
    public ErrorResponseDTO processErrorResponseException(ErrorResponseException 
e) {
        return e.getErrorResponseDTO();
    }
    // ...
    // Други handler-и за други exception-и
    // ...
}

Exception-ът е обикновен наследник на RuntimeException, който съдържа в себе си DTO-то:

public class ErrorResponseException extends RuntimeException {

    private ErrorResponseDTO errorResponseDTO;

    public ErrorResponseException(ErrorResponseDTO errorResponseDTO) {
        this.errorResponseDTO = errorResponseDTO;
    }

    public ErrorResponseDTO getErrorResponseDTO() {
        return errorResponseDTO;
    }
}

С описаното дотук връщането на грешка става просто. Например, в Service-а за генериране на JWT токен има простата проверка дали конкретният потребител е активен. Ако не е, няма смисъл да му генерирам токен:

if (userData.getUserStatus() != UserStatus.ACTIVE) {
    throw new ErrorResponseException(ErrorResponseDTO.userIsNotActive());
}

Така при неактивен потребител към извикващия клиент се връща този JSON:

{
    "code": 1409,
    "message": "User is not active"
}

Логиката за потребителския интерфейс е изцяло в клиентското приложението. Дали ще се покаже директно върнатият текст или според кода на грешката ще се случи нещо, няма значение. Целта е пълно отделяне на логиката по обработване на грешката (ако така се превежда decoupling). Няма значение дали клиентът е Vue, Android или Swing приложение – отговорността е негова.

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

Можеше вместо рефлексия да използвам анотациите, предоставени от Swagger за този случай (@ApiResponses и @ApiResponse) върху всеки метод на всеки контролер в приложението.

Понеже рефлексията ми е интересна, се спрях на вариант с endpoint, който връща JSON с всички възможни грешки, които могат да се върнат към REST клиента. Тъй като всички грешки са дефинирани като статични методи на класа, който ги описва, алгоритъмът е тривиален:

  1. Вземам всички статични методи, декларирани в този клас,
  2. Викам ги един по един,
  3. Записвам резултатите в списък,
  4. Връщам списъка.
@RestController
@Slf4j
public class ErrorListController {

    @GetMapping(path = "/errors-list")
    public List<ErrorResponseDTO> getErrorsList() {
        List<ErrorResponseDTO> result = new ArrayList<>();
        
        // Взимаме всички методи
        Method[] methods = ErrorResponseDTO.class.getMethods();
        for (Method method : methods) {
            try {
                // Искаме само статичните методи
                if (Modifier.isStatic(method.getModifiers())) {
                    Method declaredMethod = ErrorResponseDTO.class.getDeclaredMethod(method.getName());

                    // Викаме метода
                    ErrorResponseDTO invoke = (ErrorResponseDTO) declaredMethod.invoke(null);

                    // Добавяме резултата към отговора
                    result.add(invoke);
                }
            } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
                log.debug("Ignoring exception \"{}\": {}", e.getMessage(), e);
            }
        }

        return result;
    }
}

Адресът на този контролер (/errors-list) е разрешен в WebSecurityConfigurerAdapter-а само при определени условия и не се вижда в “продукционната” среда. Отговорът изглежда долу-горе така:

[
  {
    "code": 1401,
    "message": "Token expired"
  },
  {
    "code": 1402,
    "message": "Invalid token"
  },
  {
    "code": ...,
    "message": "..."
  },
  {
    "code": 1409,
    "message": "User is not active"
  }
]

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

Програмата за геодезически задачи и за Android

Тъй като виждам, че доста често се тегли desktop версията на програмата за геодезически задачи, реших да я напиша набързо и за Android. Все пак, след като имаше версия за MIDP 2.0 телефони, защо не и за нещо по-модерно 🙂

Оказа се забавна играчка и смятам да добавя още доста неща, но първо ще трябва да намеря учебниците по геодезия, за да си припомня кое какво беше.

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

Може да се свали от Google Play от тук:
Get it on Google Play

Състезания

Да го свърша това, докато не ме е домързяло пак…

През последните седмици бях на няколко състезания, две от които национални по информационни технологии – едно в Благоевград и едно тук, в Търново. Дойде им времето да бъдат описани.
Не взех нищо от двете състезания, но не се и очакваше. Моят “проект” беше писан за има-няма 5 дни, докато другите си бяха играли месеци 🙂
Грешката ми беше, че не карах по това което мога (нещо с java), а си играх с PHP неща и сайтове. Както и да е, важното е, че се запознах с интересни хора и се разходих.

Първо – Благоевград (карам накратко, което си спомням)
За самото състезание разбрах случайно и реших, че ще е интересно да се види.
Пътуването към Благоевград не беше нищо особено, с изключение на многото пожари, някои от които още горяха.
Имаше малко проблеми с настаняването – в стаята ми нямаше интернет, затова се наложи едно местене и тичане по етажите.
Благоевград е интересен град.
Искаше ми се да видя какво са направили хората с приложни програми, но за всяко направление имаше различна стая.
Вечерта преди състезанието имаше откриване с някаква програма. Залата се напълни за минути!

Това е към 17:15:

Около 15 минути по-късно:

Журито ми хареса. Най ме нарадва как направо се заяждаха на места. Тъпо се получи, че най-заяждащия се отиде за кафе, точно когато дойде моя ред. Както и да е. Състезателната част беше fail. Няма да коментирам другите проекти, защото ще излезе, че “той не е взел нищо, затова хейти”. Само ще кажа, че едно от първите места беше за сайт, който говори. По-точно, ако пропуснеш поле или не си регистриран, се пуска някакво ogg от някъде и ти заявява “НЕ СТЕ РЕГИСТРИРАНИ!” или нещо от сорта. Ако който и да е реален сайт ми го направи това, ще издиря тоя, който го е направил и ще му пратя 3MB псувни, а сайта ще се постарая да го съборя.
Имаше интересни неща – неграмотни (“критерий”, “*ий”…) копия на фейсбук, проекти с имена на известни сайтове, неща, “писани с Notepad++”, на които сорса им е с маймуните, които се получават от WYSIWYG editor-а на Dreamweaver и всякакви такива 🙂
Единствено ми харесаха хората от Пазарджик. Чисто, HTML5, правено на линукс, etc…
Отплеснах се.
Разходките из града бяха яки. Научих, че превеждат Строс на български. Замалко да хванем митинг на Атака – разни хора (?) се разхождаха с плакат и вдигната дясна ръка.
Обиколихме старата част, снимах шахта, котка с шахта и няколко геодезични точки.
Впечатление ми направи, че навсякъде имаше картини с голи жени.

В хотела.

И в произволно кафе до училището

Рецепциониста беше интересен. Имаше брат-близнак, който също беше рецепционист! Виждал съм близнаци, ама това беше чисто Ctrl+C, Ctrl+V!
Питаха ме за фейсбука ми и като казах, че не ползвам беше все едно нямам самоличност, все едно съм никой.
Излезе, че той си помислил, че имам, ама не ползвам. Реакцията като разбра беше: “Ама ти нямаш регистрация?!” с интонация все едно съм гръмнал Кенеди и съм задушил всички сладки котки по света, докато съм ръбал от бута на най-сладкото куче…

Общо взето е това.
В автобуса от Благоевград към София вместо филм бяха пуснали камера, която беше вързана някъде отпред и можеше да се гледа пътя.

От София към Търново пък пуснаха The Mechanic. 2 минути, след като казах, че го имам на лаптопа.

***

Търновското състезание.
За първа година го организират и исках да видя как е.
Организацията им беше добра. Като се има предвид, че го правят малко хора, по нищо не отстъпва на другите национални. Трябваше да дойдат повече участници. Самото състезание беше много добре – журито не прави само забележки, а обяснява, дава насоки и т.н. След като всички се представиха, след това около един час от журито говориха за проектите и обясняваха неща. В сайта на състезанието има всички критерии, всеки с точките, обяснение и препъръки как да се  подобри. Препоръчаха книги. Много добре. Хареса ми повече от Благоевград.
Човек от направление “приложни програми” ме помисли за професор:)
Хубавото от състезанието е, че научих, че може да се кандидатства с тест по ИТ. Nice! Трябва да проуча по-подробно.

Жалко, че повече няма да мога да ходя като участник.

2010-03-16

Неща, за които трябваше да пиша преди седмица.

Първо да кажа за Sonisphere – няма да ходя. Мина лимита на хора, които мога да изтърпя да ме питат. Bummer.

Миналата събота бях на втория кръг от олимпиадата по английски. Пак обичайните лесни неща. Този път беше интересно. Диктовката беше от някоя от Хари Потър книгите, а една от темите за есе беше “Your favorite sitcom. What is it about? Why you like it?” или нещо подобно. Разбира се, че като отговорен сериен маниак, избрах тази. Писах за The Big Bang Theory, може би единствения неанимационен ситком, който ме радва. Оказа се, че недоспиването имало недостатък – вместо Howard, писах Harold. Срам!

Разрових се за стари неща, които съм писал и излезе, че от SoftPedia са качили Padnote и csv-to-graph при тях. Не подозирах, че и там слагат безполезни програми. Както и да е, Padnote е добавена като програма за Mac, където има 318 сваляния и за Windows, където свалянията са 24. csv-to-graph има общо 285 (Mac/Win = 154/131).

Отивам да слушам дискографията на AC/DC.

Как да си пусна java програма?

Е, писна ми разни хора да ме питат как да си подкарат разни java програми. Ето го обяснението на нереално сложния процес на подкарване на програма, писана на java: Continue reading “Как да си пусна java програма?”

Програма за решаване на втора основна задача в геодезията [обновена + версия за Android]

GeoStuff е програма за решаване на основни геодезически задачи за Windows и Android.

Windows



Текущата версия на програмата за Windows е 1.1.0 (от 19.03.2016) и може да се свали от тук (.zip, ~45KB)

Програмата използва .NET Framework 4.5 и би трябвало да тръгне на всеки нормален компютър с Windows 7 и нагоре. Ако не тръгне, трябва да се изтегли .NET Runtime от сайта на Microsoft.

Версия 1.0, използваща Java и Swing, все още може да се свали от тук (.rar, ~50KB). Тази версия работи на всички компютри с инсталирана Java Runtime Environment (JRE) без значение от операционната система.

Android

Програмата има и версия за Android, която дава възможност за решаване на двете основни задачи и права засечка.

Get it on Google Play

 

 

 

Повече информация и последни версии ще има на страницата на приложението: тук

Безполезна програма за генериране на честоти с java

messingfrequencies

Ето това е труда на 5-минутно умуване и игра с java-та. “Програмата генерира честота със зададено цяло число. Времетраенето е от 0.000… до 1 секунда (някога може да си поиграя да го направя и повече). Няма ограничение за честотата. И докато сме на темата за честотите, веднага заявявам, че не поемам никаква отговорност за повреди, нанесени от използването на “програмата”. Като бонус чертае и почти вярна графика на сигнала, който излъчва. Това може да намери приложение като програма за тестване на големи високоговорители (особено интересно е при 2 херца), за досаждане на съседите и др. Download

02.09.2009

Търся си тема за блога. Нещо просто, леко, изчистено, колкото се може повече да се държи като К2. Досега нищо интересно не намирам и май ще се налага да си играя с CSS-а на K2-то.

Написах си CSV parser. Чертае графика с данни, взети от файл. Имам да ѝ пиша един тон работи още. Да видим кога ще се сетя да я довърша и да я пусна в “useless java applications” stream-а.

Вчера ми се наложи да поразцъкам в онлайн банкирането на Пиреос Банк. По-бавен сайт не съм виждал. Има някакви иконки вдясно, на които няма описание, пише, че зарежда, докато нищо не става, превода не струва. Най-досадната работа от всичко са паролите – задължително трябва да са с букви и цифри. Това винаги ме е дразнило. Паролата си е моя, ще бъде каквато си я искам! Изглежда правено набързо…

pb1

Сутринта си цапнах ръката и май съм я навехнал доста яко – едвам я свивам. Много тъпо се получи. Сега има да я чакам да минава, а на доктор не мисля да ходя. Най-лошото е, че не мога да свиря. fuck!