Monday, September 5, 2016

Teambuildings, conferences and pulling your hair out over simple update

So, you've been invited to spend a weekend with your company colleagues. There is also a conference event scheduled at destination. You can learn something, meet new people, exchange ideas, have fun. Well yes, splendid, lets do this.

Early morning, still dark, driving by bus. Developers like developers, still dreaming without it's first coffee. So everyone got back to sleep. First words could be heard over a coffee on a gas station. And adventure begins...

Arrived at our destination. Smell of sea, fresh wind and warm sun were so overwhelming so decision has been made to go to beach and relax first. Couple of drinks and conversations are on fire. Couple of minutes later, first phones got into action with some texting and taking photos. Amazing how we made without them so far :)

Next step conference. While listening to presentations of various subjects I've decided to take some time and update my Tumbleweed. Of course you don't do it on work days and weekends you use for some other activities so it was a perfect time. Well at least it was looked like one... :)

Booted my openSuSE Tumbleweed, set valid repositories and with confidence started Software application and clicked 'Update and Restart' under Updates section. Fast restart, and then hang on boot.. Waited for couple of minutes. Nothing. WiFi for sure, I was thinking. Never mind, lets do this again manually with zypper.

Restart has booted it again. Started zypper update process.
$ zypper up

And here we go. God ol' zypper working just fine. 1/1227 packages. Well that will take some time. And than it showed error stating he can't write to disk. Why not? Let's try again. This time only 200 packages. Should be fast. Going nicely and again at the end same error. So you can download and install some packages but others can't? Is it a repo problem?
Oh, presentation is over. Launch time, never-mind I'll continue later..

Conference day was coming to the end. One more try and now I got error again stating can't write to disk but this time on first package. Than in occurred to me to check disk. Quick:
$ df -h 
Filesystem      Size  Used Avail Use% Mounted on
/dev/sdb6        40G   39G  50MB  100% /

So it was problem all along. Trying to delete some unused journal logs to free some space.
$ journalctl --vacuum-time=0d

$ df -h 
Filesystem      Size  Used Avail Use% Mounted on
/dev/sdb6        40G   36G  50MB  100% /

Hm, I have available space but usage is on 100%? Is my filesystem corrupted?
No, as it turns out root is on btrfs partition and it behaves differently as opposed to traditional filesystems. It has the concept of allocating space on the underlying device, but not actually using it for files.

Also root partition was filled with update snapshots. To check the problem volume use:
$ btrfs subvolume list /

To delete snapshot you do not need use:
$ btrfs subvolume delete -c path

Where path is from previous command subvolume list that says "snapshot". We are using -c flag to commit changes immediately to btrfs file system.
Finally, after reboot zypper update passes.

Last presentation is over, and this reminds me again why I don't do updates on work days :D
And now, after-party and some team strengthening time.
Until next time, happy updating ;)

Friday, April 15, 2016

Acer R5 471T and Tumbleweed/Windows dual boot

First what you notice is that laptop is very slim design. Keyboard looks so thin, make you think they don't actually move while typing at all :) But when you start to type, it is really great! Screen is very glossy so even a smallest light reflection will make you move your head to proper angle. But it is great for indoor use.

After pushing power button, Windows has booted in couple of seconds. Great, everything works, even keyboard back-light and multi touch screen! And now let's install Linux along with installed Windows 10.

First install partition manager and resize 250GB parition to 150GB to make 100GB of unpartitioned space.

Next you want to make a USB installation stick. For OpenSUSE Tumbleweed you need to use ImageUSB.
Download Tumbleweed DVD ISO image from HERE.

Stick your flash drive with Tumbleweed installation to usb slot. Enter BIOS with F2 end enable Boot select with F12, or continue to Boot section and move USB Flash drive to first position.

After that installation will start. Because we have UEFI secure boot enabled it will ask us for confirmation to trust opensuse binaries for booting. After that installation will find unpartitioned space and suggest partition setup for root, home and swap paritions. Also it will set a boot mount point to EFI boot partition. This will install EFI binaries to proper place inside EFI boot parition.

After installation is finished it will reboot to windows again. It is because windows is overriding grub boot settings. To get around this open command prompt as administrator and execute:
bcdedit /set {bootmgr} path \EFI\opensuse\shim.efi

Finally grub menu! Tumbleweed has booted but WiFi is not showing any networks found, and it says WiFi not available.
$ sudo lspci
01:00.0 Network controller: Qualcomm Atheros QCA6174 802.11ac Wireless Network Adapter (rev 32)

There is problem in firmware for this WiFi card and it does not work with 4.5.x kernel.
Solution is to download Windows firmware binary and replace it with current linux version like so:

$ sudo cp /lib/firmware/ath10k/QCA6174/hw3.0/board.bin /lib/firmware/ath10k/QCA6174/hw3.0/board.bin.orig
$ sudo mv ~/Downloads/eeprom_ar6320_3p0_NFA364xp.bin /lib/firmware/ath10k/QCA6174/hw3.0/board.bin
$ sudo reboot

Finally fully operative dual boot!

Wednesday, March 2, 2016

AngularJS Single Page App with Laravel API

Idea is to create Single Page App in AngularJS to demonstrate basics such as:

  • custom directives
  • routing capabilities using hashtag
  • controllers for particular routes
  • making HTTP requests and handling responses
  • CRUD operations on frontend and API calls to the backend
  • uploading a file/image
  • pagination and accordion Boostrap UI components

AngularJS SPA files:
  • resources/views/index.blade.php
  • public/js/module/module_spa.js
Complete code can be found HERE.

Step by step Laravel work log for backend, can be found HERE.

Thursday, February 18, 2016

PHP solutions for Codility lessons

Hi Codilitiers!

I want to share with you solutions for Codility lessons as result of my preparations for Codility test. If you are using PHP to go through Codility lessons and tasks, THIS COULD HELP.


Codility tasks have been solved using PHP as preparation for TopTal.
There could be multiple 100% solutions for particular task and 
there are separated partial solutions in ./partial folder which 
represents solutions before perfect score was hit.

Hope it helps!

Play Chrome Chess at work

As a practice in NodeJS/SocketIO I've made simple Chrome extension to play chess online with your friends. It is still in beta but I will continue with development and support as much as spare time allows it.

ChromeChess is simple PVP version of good old chess where game of chess is just click away. 

This extension acts as simple chess user interface inside small popup window.

So, basically you can continue your daily work inside Chrome while still playing chess. When opponent makes his move you will be notified so you can open chess board and make your move.

Hope you like it. Enjoy!

P.S. For developers that want to help with development you can find me HERE.

Saturday, December 26, 2015

Ready for freelancing?

I’ve been a professional software/web developer for more than a decade, and up until now I mostly worked as full time employee in several companies and one contracting project as freelancer, where I gained expertise in many technologies and Scrum Master management skills. Latest technologies were mostly web development oriented.

After a decade of my professional life I could say that full time corporate job is right choice if you don't have much experience or you just got out of school. After gaining initial experience in corporate jobs, you will want to make portfolio populated with projects you have worked on. You will need a portfolio to show to future clients that you are right choice for them. Experience proves both client and you that you are capable of finishing projects.

After that you could try yourself working by contract or as freelancer, having flexible working hours, where the end result counts. You need to have self-discipline to work when needed and be reliable and responsible while communicating to clients. This will also help you make time to stay sharp and in step with technology edge, because you are in control of your availability. All this is just what I always wanted so I decided that it is time to dive into freelance world.

In corporate culture, if you think in terms of financial part of software and its price, then of course you would like to finish it ASAP to reduce its cost. Companies driven by that notion only, will often threat its developers as necessary evil. For those companies, it is not the product that is in focus and value it brings to client, but rather the points of contracted work and its unreasonable deadlines.

Often under management pressure to follow deadlines, developers reduce products quality to gain speed. Not the career plan you would like to follow, because you don't have time to improve and work is not fun in such stressed environments.

Then I searched for freelance market sites. And I found sites like UpWork and Elance which are great but they don't guarantee you constant work because first you need to build your reputation and even than you have to compete with some very low unreasonable offers.

If only there could be some intermediate which will connect self-organizing teams of professionals with right customers, willing to pay for good quality product along with reasonable deadlines (so we don't need to compete with immoral offers to jobs like to make a copy of popular social network for 30$, or less, in couple of days). With financial aspect covered, team job is to handle time and quality aspect and gets job done. Team than incrementally develops software and brings value to customer so they together can steer product in right direction.

And then I heard of TopTal while attending presentation with freelancing as topic. It was scheduled at gathering of developer community of Banja Luka. Ines Avdic Zekic from Sarajevo held informative presentation about TopTal. Less than 3% passes screening process, she said. Nobody likes to be tested, but if this is what I have to pass to put financial aspect in background than by all means, let’s do this.

Why join TopTal?

If you pass TopTal screening process, then TopTal stands for you. TopTal takes care of finding jobs and paying you upon completed work, even in such cases where the customer refuses to pay. Take worries about not being paid away, and just commit yourself to finish your job.
Yours is to get job done. Money should be just a side effect of your work.
You can set higher or lower price per hour and frequency of jobs you receive will depend on that. Higher the price per hour, lower frequency of jobs.
It enables you to connect with other freelance professionals and do work together for TopTal trusted customers and companies.
You are not tied to location, as long as you have reliable internet connection.
Market is dictating new technologies, and that technology edge is exactly what you want to learn and contribute in. TopTal enables you to grow as IT professional. It provides you with courses and webinars to learn technologies with highest demand on market. 
It enables you to grow your software using edge technologies to bring better value to its users. You don’t wont to end up in companies just to maintain some piece of software until time and new technologies overrun them.
Availability and commitment can be changed. Your availability varies and you can reduce your availability while you are travelling or on vacation, and also increase it when you are eager to work.
Working 9-5 is not necessary what will bring the most out of developer. I want to use morning hours for work because I'm well rested. Then after lunch I could take a nap, do some physical activities and then go back to work and finish work refreshed and sharp minded.

In Banja Luka, there is still no developers working for TopTal. This would be a great opportunity to make a first step to connect TopTal with talented developers from this region and Banja Luka developer’s community. What I’ve heard so far, convinced me more that TopTal is right fit for me. I’m eager to learn new technologies and improve myself through active communication with TopTal clients and deliver them good piece of useful software. Later on my ambitions would be to gather people around me so we could provide TopTal services in a wide range of technologies as a self-organized team.

Now I'm heading back to Codility for some more practice. TopTal is also providing guide for interviewing PHP developers.

Wish me luck!

Tuesday, July 14, 2015

Simple blog using Laravel - Part I


Create articles migration:
$ php artisan make:migration create_articles_table --create="articles"
Inside database/migrations find created migration and edit:
and add these lines to up() method:
Schema::create('articles', function (Blueprint $table) {
To execute created migration do:
$ php artisan migrate


and add this line:
Route::resource('articles', 'ArticlesController');
Which is easier way and equal to manually supply all CRUD routes following REST convention like so:
Route::get('articles', 'ArticlesController@index');
Route::get('articles/create', 'ArticlesController@create');
Route::get('articles/{id}', 'ArticlesController@show');
Route::post('articles', 'ArticlesController@store');
Route::get('articles/{id}/edit', 'ArticlesController@edit');


We have articles table, so lets create Article model:
$ php artisan make:model Article
Edit our model app\Article.php and add $fillable fields so we can mass assign them while creating article. Also specify published_at field inside $dates so Laravel threat this field as Carbon date object instead of simple string representation.
class Article extends Model
    protected $dates = ['published_at'];
    protected $fillable = [

Add two rows to article table using Laravel interactive tinker tool:
$ php artisan tinker;
$ App\Article::create(['title' => 'My first article', 'body' => 'Article body', 'published_at' => Carbon\Carbon::now()]);
$ App\Article::create(['title' => 'New article', 'body' => 'New body', 'published_at' => Carbon\Carbon::now()]);
$ App\Article::all();
Update first article:
$article = App\Article::find(1);
$article->body = 'Lorem ipsum';
Get collection of articles:
$articles = App\Article::where('body','Lorem ipsum')->get();
Get first article:
$article = App\Article::where('body','Lorem ipsum')->first();


Let's create plain ArticlesController:
$ php artisan make:controller ArticlesController --plain
So now we will create index action to fetch list of articles.
Edit app\Http\Controllers\ArticlesController.php:
public function index()
    $articles = Article::latest('published_at')->published()->get();
    return view('articles.index', compact('articles'));
We want to use published() scope while fetching articles to get only those published until today and sort them descending from newest to oldest by published_at using latest(). So let's create published() scope in app\Article.php model. Notation is keyword scope followed by scope name, like this:
use Carbon\Carbon;
public function scopePublished($query)
    $query->where('published_at', '<=', Carbon::now());
To show details of selected article we need show() action. Edit app\Http\Controllers\ArticlesController.php:
public function show($id)
    $article = Article::findOrFail($id);
    return view('', compact('article'));


Inside resources folder create app.blade.php:
<!doctype html>
<html lang="en">
<meta charset="UTF-8">
<link rel="stylesheet" href="//">
<div class="container">
Inside resources\articles create index.blade.php:
<div class="col-md-12 staff-header">
<div class="col-xs-12 col-md-12">
@foreach( $articles as $article)
<a href="{{ action('ArticlesController@show', [$article->id]) }}">{{ $article->title }}</a>
<h6>{{ $article->body }}</h6>
Inside resources\articles create show.blade.php:
<div class="col-md-12 staff-header">
<h5>{{ $article->title }}</h5>
<div class="col-xs-12 col-md-12">
<h6>{{ $article->body }}</h6>

Tuesday, June 30, 2015

Laravel on Debian Wheezy


First we need LAMP packages installed.
Laravel requires PHP >= 5.5.9 so we will install php56.

Add package repositories to apt sources.
Edit sources.list
$ vi /etc/apt/sources.list
and add these two lines:
deb wheezy-php56 all
deb-src wheezy-php56 all

Add dotdeb.gpg key so apt can authenticate packages from added sources.
$ cd
$ wget
$ apt-key add dotdeb.gpg
$ apt-get update

Install Apache, MySQL and PHP
$ apt-get install mysql-server mysql-client
$ apt-get install apache2
$ apt-get install php5 libapache2-mod-php5 php5-mcrypt

Enable rewrite apache modul
$ a2enmod rewrite
$ /etc/init.d/apache2 restart

Confirm that php is working well with apache by creating info.php file:
$ vi /var/www/info.php
add this line:
<?php phpinfo(); ?>
Access inside browser: http://localhost/info.php


# To install laravel we need composer:
$ sudo curl -sS | php -- --install-dir=/usr/local/bin --filename=composer

* Use composer to install laravel:
$ composer global require "laravel/installer=~1.1"

* Add laravel bin to your PATH so you can use laravel executable from any location. Edit bash_profile file:
$ vi ~/.bash_profile
and add these lines:
export PATH

* Create new base for web application
$ cd ~/NetBeansProjects
$ laravel new LaravelDemo

# Or we could skip installing laravel and using it's executable to create base for web application (steps marked with asterisk *), and go ahead do all that with composer directly:
$ rm -rf ~/NetBeansProjects/LaravelDemo
$ cd ~/NetBeansProjects
$ composer create-project laravel/laravel LaravelDemo --prefer-dist

# Create Apache VirtualHost by:
$ vi /etc/apache2/sites-available/
and add these lines:
ServerAlias *

DocumentRoot /home/{user}/NetBeansProjects/LaravelDemo/public

        Options Indexes FollowSymLinks MultiViews
        AllowOverride All
        Order allow,deny
        allow from all

ErrorLog ${APACHE_LOG_DIR}/laraveldemo_error.log

# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
LogLevel warn

CustomLog ${APACHE_LOG_DIR}/laraveldemo_access.log combined

# Enable virtual host:
$ a2ensite

# Add virtual host to hosts file by editing:
$ vi /etc/hosts
add this line:

# Restart apache
$ service apache2 restart

# Create simple /about route and appropriate controller, action and view
$ cd ~/NetBeansProjects/LaravelDemo
$ vi app/Http/routes.php 
add this line to routes.php:
Route::get('about', 'PagesController@about');

# Create PagesController by:
$ php artisan make:controller PagesController --plain
$ vi app/Http/Controllers/PagesController.php
add about() method to PagesController.php:
    public function about() {
    return view('about');

# Create about view by editing about.blade.php:
$ vi resouces/views/about.blade.php
add this line:
    Hello World

# Make local configuration
$ copy .env.example to .env

# Generate app key
$ php artisan key:generate

# Set Directory Permissions
$ cd ~/NetBeansProjects/LaravelDemo
$ chgrp www-data -Rv storage/
$ chmod g+w -Rv storage/
$ cd bootstrap/
$ chgrp www-data -Rv cache
$ chmod g+w -Rv cache

Test it by pointing browser to:

Create database
mysql> create database laraveldemo;
mysql> CREATE USER 'laraveldemouser'@'localhost' IDENTIFIED BY 'laraveldemopass';
mysql> GRANT ALL ON laraveldemo.* TO 'laraveldemouser'@'localhost';

# Add mysql authentication data to .env
$ vi .env
change these lines: