2017. november 2., csütörtök

Codility simple C programming task 2 - solution

As part of my job interview process a few years ago in the UK, I was given a Codility task to solve online. I can't remember which company I applied for, neither the names of the interviewer(s). I could not solve the task back then (no wonder why, as you'll see soon), but I saved the task for the future. The time has come and I re-visited the task. After I did the code review, to my surprise, it turned out that the PROBLEM WAS NOT WITH ME but with the IT WAS TO DO WITH THE INTERVIEWER. I solved the task on my own at home and my solution is shorter, better. I publish it for public benefit and to see that it's not always the candidate unskilled but the interviewer was completely at a loss and was an incompetent bungler. The original task was simply wrong, it contained buggy code and it is not even close to being right. He should have devoted more time to prepare a good task for the candidate assessment.

The task can be seen in the attached picture below.


The task is to solve the C code by modifying "at most two lines of code". This is not possible. If something is BROKEN, you can't fix it by applying cosmetic fixes. YOU HAVE TO THROW IT AWAY. If you examine the bad code below, you can see it contains nonsense. It simply does not work. It's not even close to being a good code. I assume it's just there to derail the candidate. For e.g. if you look at the assumptions, you can see that the wrong code contains checks it should not check for, since we assume something, we should not check for it. We assume it and that's it.

BAD CODE:

int solution(int A[], int N, int K) {
   int i;
   for (i = 0; i < N - 1; i++) {
if (A[i] + 1 < A[i + 1])
          return 0;
   }
   if (A[0] != 1 && A[N - 1] != K) 
          return 0;
     else
          return 1;
}

Look at my fixed code below in its clear beauty.

GOOD CODE:

int solution(int A[], int N, int K) {
   int i;
   for (i=0; i<=N-1; i++) {
      if (A[i]==K) return 1;
   }
   return 0;
}

The correct algorithm goes like this. When you find the element of A array equals to K, we return with 1 (true). We find what we want and do not have to worry about the rest. When the check is over and no value is found that matches the key we're looking for, we will return with false (0). This is how you write simple and good code that solves the problem without the extra hassle. What can be easier than that?

I also wrote a wrapper main program to actually test the above function with different values. See below. 

task-2.h:

/* 
   This is task-2.h. It declares the function to be used in the main program. 
 */

int solution(int[], int, int);

task-2.c:

#include
#include "task-2.h"

int main() {

int noofelements=3; 
int key=2;
short rc=0;
int array[noofelements];

array[0]=1;
array[1]=1;
array[2]=3;

printf("elements in the array are:\n");
for (int i=0; i
   printf("%d\n", array[i]);
}

rc=solution(array,noofelements,key);
printf("is key %d found in array?\n", key);
if (rc==0)
   printf("false.\n");
else
   printf("true.\n");

return 0; // return true to satisfy shell

}

Put the solution() function , the good code into into a separate file task-2-fixed.c and compile and link them together with gcc and try it. IT WILL WORK. Below is the Makefile for reference:

# Makefile for task-2
#
task-2-fixed.o: task-2-fixed.c
gcc -c $<

task-2.o: task-2.c task-2.h

gcc -c $<

task-2: task-2.o task-2-fixed.o

gcc -o $@ task-2.o task-2-fixed.o

all: task-2


I feel much better as I solved the problem and proved that I am competent enough. Also, I proved that the interviewer was not good. I am happy that I was not hired by that company at the time! Problem solved. If you need help with the code, it's been tested by me and works successfully.

;-)

qmi
2 Nov 2017

UPDATE:
A friend of mine, Zoltan Hanko pointed out to me that although my solution may be correct finding the key K in the array A but that task was not exactly that in the first place. He was right. The task is to check whether array A contains number 1,2.......K and no other numbers. I am sorry, I overlooked it. My solution above only finds the key K and returns with true if found. I fixed my code so that it checks for stray numbers that are greater than K and also checks if there is no 0 (zero) among the array elements. Since the original task description says that 'assume that the array elements are sorted in non-decreasing order', I do not check if they are out of order. See the fixed code below:

int solution(int A[], int N, int K) {
   short found=0;
   int i;
   for (i=0; i<=N-1; i++) {
      if ((A[i]==0) || (A[i]>K)) return 0;
      if (A[i]==K) found=1;
   }
   if (found==1) 
return 1; // true
   else
return 0; // false
}

It is tested and works. For e.g., with array values 1,1,2,3 taken as input the function returns false, because even though key K=2 is found but the last index value is 3, which is a stray number larger than K. Therefore returns with false. However, even with the above code and now finally the original task requirement is fully met, the above working code is NOT EVEN CLOSE TO THE ORIGINAL BROKEN ONE. The interviewer who prepared this task was obviously incompetent.

Take away: I suggest every interviewer to come up with value-added and well written tasks to AVOID WASTING TIME of the unsuspecting candidate.

qmi

7 Nov 2017


2017. október 30., hétfő

Codility simple SQL task 1 - solution

Intro 

A while ago I applied for a job and as part of the application process, I was tasked with a simple task to solve online: a straightforward SQL task to which I was given a link on codility.com for the specific task. This online task was used a candidate skill measurement. I had a 2h time limit, I can't remember the result but I remember that I was not selected later on in the application process. Anyway, I was smart enough to use my laptop's screenshot key to save my screen shot ;-). The task is simple and small, it is good to measure your basic SQL skills. It can be used in computer science school as well to teach students. I wanted to share how I solved it just in case someone finds it useful.

The task was to write an SQL query that returns the list of invoices with the total price of each. The data and the relational database format is given as it is shown in the picture.


As it is seen, the database just contains one table named invoice_items which contains three records.

Solution

My solution uses the sqlite3 program for sake of simplicity. You can use your own favourite relational database software whichever you like. The only requirement is that it could understand SQL queries. First you fill in the data like below. In the end, don't forget to save the in-memory database to the file named invoices.

bash$ sqlite3
sqlite>
CREATE TABLE invoice_items (inv_num INTEGER, item TEXT, price INTEGER);
INSERT INTO "invoice_items" VALUES(3,'a',10);
INSERT INTO "invoice_items" VALUES(3,'b',15);
INSERT INTO "invoice_items" VALUES(1,'c',7);
sqlite> .save invoices;
sqlite>
bash$

At this point, your data has been added and you have a tiny database with one table and three records. Now, go back to sqlite3 and run the simple query to see all records first. 

bash$ sqlite3
sqlite> .mode column
sqlite> .headers on
sqlite> select * from invoice_items;
inv_num     item       price       
---------   ---------  -----------
3           a          10
3           b          15
1           c          7
sqlite>


OK so far, we got the data. The solution below uses the sum() function to summarize (to sum up) the values in the price column. We need to calculate the total price for each invoice item and that function does the work. Then, we need to aggregate the records by using the GROUP BY clause. Then we need to sort the results by using the ORDER BY clause in descending order (that is what the DESC word denotes). These are built into SQL and every implementation should be able understand them, not only sqlite3. The one-line SQL query looks like this:

SELECT inv_num, sum(price) FROM invoice_items GROUP BY inv_num ORDER BY inv_num DESC;

Let's run the above query in sqlite3 prompt as shown below:

bash$ sqlite3
sqlite> select inv_num, sum(price) from invoice_items group by inv_num order by inv_num desc;
inv_num     sum(price)
-------     ----------
3           25
1           7

Voila! The task is solved. We got the expected result. Let me know if you have any questions.

:-)

qmi
30 October, 2017

2017. szeptember 19., kedd

Difference between URL masking and URL redirect

Hi guys. It's been a while since I wrote something on here. While I was looking at the URL redirects on my website, I noticed that I should actually mask the URLs that should look nicer. I have got a few redirects in order to use them on external referral sites and they end up hitting my website. When the resulting link is masked, it looks nicer and reveals less information to the visitor.

So the redirects I have got set up are as follows:

www.miklos.info/munka → www.miklos.info/hu/3/it-konzultacio?lang=hu
www.miklos.info/consulting → www.miklos.info/en/3/itconsultation?lang=en

When the above referring links are getting visited, they used to be rewritten in the browser title bar so the resulting links were displayed until now. I wanted the URL to be masked and the visited link URLs are not be rewritten but keep the original links in the browser title bar displayed, the content however would be served. I am using Apache as a web server on my website, so the Redirect and Rewrite rules can be used via the Rewrite Engine feature :-) . So far I had redirects in my webpage .htaccess file in the web root directory as below.

Redirect /munka /hu/3/it-konzultacio?lang=hu
Redirect /consulting /en/3/itconsultation?lang=en

The above redirects work fine but it results the browser's title bar containing the long, unmasked link when you used to visit the site. 


Note that here I do not need to redirect the request to another site, I just need them remain on the same site, but with different URLs. I would like the URL masked in the title bar. After having read the official documentation and pondering a little bit, I realized how can I mask the URLs. You can just simply use the RewriteRule directive! So simple. It masks the URLs and the serves the content from the resulting links without changing the URL in the display bar. Let's see how to solve the problem by using the correct rewrite rules. My configuration is as below. 

RewriteEngine On
RewriteRule ^munka$ /hu/3/it-konzultacio?lang=hu [L]
RewriteRule ^consulting$ /en/3/itconsultation?lang=en [L]

Save and quit the config file and reload the webpage in browser. After applying the new rewrite rules in Apache, I get the new content served but with the original URL! So with the word munka, the content on the line following is being served (/hu/3/it-konzultacio?lang=hu) and visiting the site with the word consulting in the URL in the end, the content is served which is on the line to the right after the word (/en/3/itconsultation?lang=en).


Voila! The web page(s) are served with the new, redirected content but the URL remains the original, masked! This is how you mask the URL in the title bar with Apache using the rewrite rule feature. 

😄

qmi
19 September, 2017



2016. május 25., szerda

Docker on Debian Linux 32-bit PC architecture

Docker recently has got a large hype due to its simplicity and lightweight nature. It's especially useful for developers to try out software builds in an isolated namespace without messing with the base system libraries and dependencies. I was a bit frustrated when I wanted to look into Docker, as it did not work for me after following the Docker Quickstart docs, though it is quite straightforward. Downloading a.k.a 'pulling' the default Docker image for Debian Jessie from Docker hub results in:

[qmi@qmitoshiba:~]$ docker pull debian:jessie
jessie: Pulling from library/debian
e41045043712: Pull complete
ce58426c830c: Pull complete
Digest: sha256:3dc34c5b6d35644b1c1af8cc3e0665022611e78999d7269c460afc5a0678ac45
Status: Downloaded newer image for debian:jessie



So far so good. But when I tried running it, it failed with the known exec format error:

[qmi@qmitoshiba:~]$ docker run -i -t debian:jessie /bin/bash
exec format error
Error response from daemon: Cannot start container f14f9b8ddc08f8f5722d28c39b36ef69e15ec98f6bf5a9582237cf938398e043: [8] System error: exec format error
[qmi@qmitoshiba:~]$


This error message did not look good at first. Then I recalled from my past that this must be something to do with my laptop's architecture. I am having my Debian running on a 32-bit Toshiba laptop, which otherwise works fine. I can run Debian Sid perfectly well, including the Docker daemon and the docker client tool. The following command clearly shows the ELF binary header being my OS on my laptop is a 32-bit platform:


qmi@qmitoshiba:~]$ file /usr/bin/docker
/usr/bin/docker: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=fefa6e269130abb71db94873811c37e86c14c066, not stripped
[qmi@qmitoshiba:~]$


Ooops...then looking into the pulled Docker image closely, it turns out that it was built for amd64 architecture:


[qmi@qmitoshiba:~]$ docker inspect debian:jessie | grep -A1 "Architecture"
    "Architecture": "amd64",
    "Os": "linux",
[qmi@qmitoshiba:~]$



Unfortunately, the Docker Quickstart docs (mentioned above) does not state it clearly that the standard images were built for 64-bit platforms and that is how they were published to the registry. This leaves the 32-bit users in a dire need reaching out for help :-/ . I knew for sure that this could be fixed, so I did my own research. I found this blog a great help, so I can just extend what I found there. Kudos to J M Keyes! Credits go to him. Let's prepare our own bootstrapped Jessie core image as follows:


$ mkdir rootfs
$ sudo debootstrap jessie rootfs/


This takes a while but we will get a basic Debian Jessie file system image. Let's compress it into a tar+gzipped image, mine becomes a mere 137Mb size tarball after it's compressed. Make sure you compress it by cd-ing into the directory first, you will need the root directory in the top-level in the tarball image. Suppose you have the bootstrapped image in the directory called roofs in the current active directory, you can use the following command to compress it quickly:


$ sudo tar -czf rootfs.tgz -C rootfs .


Then you will have the rootfs.tgz containing the compressed file system image. Now, let's build our Docker image. Prepare a file named Dockerfile in the current directory with the following content:

FROM scratch
MAINTAINER Miklos Quartus
LABEL "deployer"="qmi"
ADD rootfs.tgz /


The above will tell Docker how to build a brand new image instead of downloading it from the public Docker registry. Of course, you can replace the MAINTAINER information. The LABEL is optional, but it helps later to administer and keep track of the running container. The last line, 'ADD rootfs.tgz' will tell Docker to add the compressed tarball content to the newly built Docker image as a base file system. Now, we are ready to build our first image! It's so simple. Do the following (you don't have to be root):


[qmi@qmitoshiba:~/docker/test]$ docker build -t jessietest .
Sending build context to Docker daemon 143.2 MB
Step 0 : FROM scratch
 --->
Step 1 : MAINTAINER Miklos Quartus

 ---> Using cache
 ---> f24ad889833e
Step 2 : LABEL "deployer" "qmi"
 ---> Using cache
 ---> f3ed82889f5b
Step 3 : ADD rootfs.tgz /
 ---> Using cache
 ---> 4d9bbfdae567
Successfully built 4d9bbfdae567
[qmi@qmitoshiba:~/docker/test]$



Awesome! It looks like we have just built our first Docker image successfully. You can check it with the command docker images, you'd like. I assume you have the docker application container engine service up and running on your machine (you should have the 'active (running)' state if you run  systemctl status docker.service command), let us try to run our newly build image in our Docker ecosystem. You need to know that every container needs to have an underlying image. So, when we will run our container, we create it and start it in one go. Refer to more explanation for page 62 in the book titled 'Docker Up and Running' :-)

OK, so let's run our container built based on the compressed file system image. We will be requesting a simple shell.


[qmi@qmitoshiba:~/docker/test]$ docker run -i -t jessietest /bin/bash
root@4cd2f95cbe4a:/#



Voila! There you go! :) We're inside our container running a Bash shell. The container ID is 4cd2f95cbe4a, as the shell prompt shows. The impossible first now became possible after investing in a little bit of effort. I am no longer hurdled by the 64-bit published images in the registry. I have built my own and it works perfectly well. BTW, you can check our container status by running a docker ps command in another terminal.


root@qmitoshiba:~# docker ps -q

4cd2f95cbe4a
root@qmitoshiba:~#

Done. We have managed to build our own Docker image for 32-bit platform on Debian. If you have any questions, comments or suggestions, please comment here or send me an email at inbox@miklos.info .

2014. november 28., péntek

Vodafone szolgáltatás-lemondás veszélye - XNET

A minap történt velem, hogy a Vodafone-nál a Zsebnet 1000 szolgáltatást lemondtam. Ez egy 30 naponként megújuló szolgáltatás, ami 1Gb-ot ad 2490Ft-ért. Jó a szlogenjük a weblapjukon: "Zsebedben az Internet!". Azonban elfelejtenek egy alattomos csalásra felhívni a figyelmet: a lemondáskor a havidíj fel nem használt része nem kerül jóváírásra, az addig meglévő, tisztességes úton megvásárolt adatforgalom elveszik. November 21.-én kaptam 1Gb-ot az előfizetésemre, ami jóváírásra került. Még aznap úgy döntöttem, hogy lemondom. Ehhez egy 'XNET' szócskát kell a 1270-es számra küldeni, ahogy ez a honlapjukon szerepel. Azonban lemondás után rövidesen törlik a teljes szolgáltatást és a meglévő adatforgalom is teljesen ELVESZIK! Ezt természetesen nem verik nagy dobra, sehol nem hangoztatják. Ez véleményem szerint bőven kimeríti a tisztességtelen piaci magatartás tevékenységét. Az ügyfélszolgálattal természetesen kapcsolatba léptem, ők is csak megerősíteni tudták az alábbiakat:

"Köszönjük, hogy felkereste honlapunkat.

Levelére válaszolva tájékoztatjuk, hogy panaszára vonatkozóan az Általános Szerzödési Feltételek Díjszabás mellékletének 2.1-es pontja az alábbi információt tartalmazza.

"A GPRS WAP és GPRS Internet havidíj levonása az elöfizetö számlájáról elöre történik, és hóközi lemondás esetén a havidíj fennmaradó része nem kerül jóváírásra. Ismételt aktiválás esetén a teljes havidíj ismételten levonásra kerül. Az adatforgalom a küldött és fogadott adatmennyiség együttes összegét jelenti."

A fentiek értelmében, ha Ön lemondja a GPRS Internet szolgáltatást, úgy azt elöfizetéséröl töröljük, függetlenül attól, hogy felhasználta-e a 100 MB adatforgalmat. Ha a szolgáltatás ismételten megrendelésre kerül, úgy annak havi elöfizetési díja levonásra kerül az elöre fizetö elöfizetés egyenlegéböl, és teljes egészéhen felhasználható a havidíjban foglalt 100 MB adatforgalom. Szíves megértését köszönjük!"

Láthatóan ebből a linkből is kiderül, hogy nem velem történt meg először az ilyesmi. Tanulság minden honfitársamnak: LEGYETEK ÓVATOSAK, HOGY MIKOR MONDTOK LE SZOLGÁLTATÁST A VODAFONE-NÁL. Érdemes a legutolsó napra hagyni, amikor kihasználtátok az összes forgalmi keretet. És ha a fenti infó nem volt elegendő a kedves - netán Vodás - olvasóimnak arra, hogy kedvet csináljon más szolgáltató után nézni, akkor figyelmeztetnék mindenkit, hogy náluk a hang-alapú internethasználat (pl. VOIP telefonálás Skype-pal, Rynga-val, stb.) nem engedélyezett (!):

"A Vodafone felhívja az ügyfelek figyelmét, hogy a ZsebNet opciók esetén a mobil eszközökre letölthető alkalmazásokon (Skype, MSN, Viber, WhatsApp, stb.) keresztül használt, internet alapú hang/video-hívások indítása - és kliens szoftver függvényében a szöveges chat üzenetek küldése - nem engedélyezett. "

Lásd a lakossági ÁSZF. idevágó pontjait, 41. oldal, 2.4.1 bekezdés, ahol ők saját maguk teszik ezt nyilvánossá. Persze ez a marketingjükben nem szerepel, ügyesen elhallgatják.


Good-bye Vodafone!

2014. november 13., csütörtök

Informatikai konzultáció, tanácsadás

Elkészült magyarul is az a weboldal, ahol néhány dolgot összegyűjtöttem arról, milyen számítástechnikai munkát, informatikai tanácsadást vállalok a leendő magyarországi ügyfelek számára. Ez a lista nem teljes, hanem folyamatosan bővülni fog. Fő profilom a Linux (Debian/Ubuntu) és nyílt-forráskódú terület (FreeBSD is). Ezen belül konzultálok vagyis szakmai segítségnyújtást vállalok a következőkben:

  • Operációs rendszer üzemeltetés, támogatás, rendszergazdai támogatás
  • Felhő-alapú megjelenés (AWS, Google Cloud), virtualizáció (Xen, VMWare)
  • IT infrastruktúra tervezés, automatizálás (Puppet), fejlesztői támogatás
  • Tűzfalak (iptables, pfSense), terhelés-elosztás (Riverbed Stingray Traffic Manager)
  • Webes megjelenés (webhosting), domain regisztráció, LAMP 
  • Mentés-archiválás (rsnapshot, rsync, bacula)
  • Shell-szkriptelés, Python ill. AWS szkriptek írása
  • IT biztonság, behatolás-tesztelés, "white hat hacking", sebezhetőség-vizsgálat, hibakeresés
Fontos, hogy a magyarországi vállalatok, vállalkozások számára is rendelkezésre álljanak olyan szakemberek, akik adott esetben tudnak vállalni ilyen munkákat és juttatás ellenében bérelhetők.

2014. október 21., kedd

My personal website is up

Thanks to GoDaddy Inc., I have been able to set up my official website using their free web hosting. My website can be reached at www.miklos.info. I will continue to provide professional IT consulting services, IT infrastructure support, IT security improvements, support for open-source software using Debian GNU/Linux, FreeBSD and the like.