вторник, 29 ноября 2016 г.

Учусь программировать робота для хакатона

Некоторое время назад я записалась быть учителем на детских курсах по программированию. Поигрались мы со Скретчем , и учителя решили, что детки могут больше. Стали им давать HTML. Вот, кстати, презентация о табличках с заданием сделать открытку на праздники маме-папе. Детям всегда лучше давать то, что позволяет быстро увидеть результат. Когда ребенку можно показать, что методом малых усилий что-то меняется и это что-то ему нравится, то, значит, основное задание учителя выполнено. Когда ребенок придумал идею, хочет ее реализовать доступными методами, и попал при этом в тупик, тогда надо подсказывать. Идея будет расти, и сам ребенок будет двигаться к звездам. :)

Организаторы курсов предложили учителям провести детский хакатон, основная задача которого - собрать и запрограммировать робота. За основу взяли конструктор Lego Mindstorm EV3 45544 и бесплатную программу LEGO® MINDSTORMS® Education EV3 Teacher Edition для программирования на нем.


До того, как я сама попробовала что-то запрограммировать для робота, задача мне казалась нетривиальной. Когда же я увидела, что программирование осуществляется визуальными блоками, которые должны взаимодействовать между собой, мне подумалось, что дети справятся. Но стоило мне поставить перед собой цель запрограммировать прохождение роботом лабиринта, после того, как научила его идти прямо и в случае преграды поворачивать направо, я впала в ступор. Дело в том, что я привыкла к объектно-ориентированному языку программирования, а тут пишешь все в кучу и не знаешь, как поставить метку, чтобы перейти на тот или иной кусок программы в некий момент. Спустя несколько дней, за которые я робота даже не трогала, пришло вдохновение, и я поняла, что без методов и функций тоже можно сделать что-то толковое, и притом даже изящно.

Даже если у вас нет под рукой робота, могу предложить вам придумать собственный алгоритм для прохождения лабиринта, используя только:
  • датчик расстояния от робота до преграды, дающий на выходе количество сантиметров;
  • двигатель, которому можно задать направление движения, его мощность и продолжительность (измеряется либо в количестве секунд, либо в оборотах колеса, либо длится вечно, пока не выполнится некоторое условие по таймеру);
  • циклы;
  • операторы выбора (switches);
  • переменные;
  • математические операции.

Чтобы лучше понимать, чем вы располагаете и как этим пользоваться, скачайте себе программу и набросайте алгоритм. Не пробовала, но судя по всему вы даже можете посмотреть, как он будет работать, имея не дорогого лего робота, а виртуального.

Описание моей версии алгоритма прохождения лабиринта с использованием ультразвукового датчика, дающего расстояние до преграды, расположенной впереди


Робот может находиться в четырех основных состояниях:
0: Движение прямо;
1: Поворот направо;
2: Поворот налево;
3: Разворот назад.

После пунктов 1-3 подразумевается движение прямо в случае отсутствия близкой преграды. Движение прямо выполняется, пока преграда не окажется на расстоянии менее 20 см. После каждого поворота в коде стоит switch, основанный на расстоянии до преграды. В нем переменная заполняется значением цифры, которая станет управляющей на следующей итерации.

Вы спросите, зачем же делать проверку при развороте назад? Программирование для робота сильно отличается от написания обычной программы, которая не будет обитать в случайно меняющейся среде и у которой есть физический облик. Случается, что перед роботом неожиданно вырастает преграда в виде маминой ноги или папиной руки, и роботу недостаточно места для разворота. В таких случаях ему лучше отъехать назад на расстояние, которого ему хватит для маневра. У меня это - один оборот колеса. Данное действие в случае необходимости выполняется перед входом в switch выбора направления движения и его реализации. Другая причина - робот разворачивается не одинаково точно в зависимости от поверхности, на которой он ездит: ковер и паркет дают разные результаты. Также на градусы поворота влияет мощность поворота и калибровка робота. Мне одолжили такой экземпляр, которому для поворота на 90° на мощности 50 из 100  пришлось прописать 400°.



Вроде бы, все основное рассказала. Смотрите саму программу.



На этом видео можно увидеть робота в действии.


Если смотреть внимательно, то видно, что робот ни разу не входит в состояние “3”. Посмотрите внимательно на картинку программы, и вы поймете причину. Предпоследний блок ссылается на “3”, если расстояние слишком мало, и на “0”, если места достаточно. Последний блок называется “4”, а блока “3” не существует. :) А в таком случае он по умолчанию идет в “0” (на switch рядом с нулем отмечена соответствующая радио-кнопка).

Алгоритм вышел действенный и простой, но у него есть недостаток. Что случится, если отверстие, в которое нужно попасть, находится в середине стены? Например, робот идет по шляпке буквы Т, а выход - в ноге. Этот алгоритм ждет преграды, и в отверстие в стене сбоку без случайности не попадет. Иными словами, алгоритм хорош для прогулок по квартире или офису. А что, если имеем настоящий лабиринт?

Модернизацию выполнить не так сложно. Для этого необходимо дописать диагностику правой стены с некой частотой во время движения прямо. Почему только правой, а не двух? Потому что если окажется, что справа прохода нет, а слева есть, то когда робот обойдет все слева и не найдет выхода, он, вернувшись в исходное место, уже не будет знать, куда ему поворачивать, чтобы пройти по коридору дальше. Повернет он в стандартном направлении, которое будет противоположно тому, куда бы он повернул, если бы был открыт правый проход. То же самое на примере: робот шел по шляпке буквы Т справа налево и зашел в ножку, обошел ее и вернулся на перекресток, где есть дорога как вправо, так и влево. Следует помнить, что тут он уже был, и чтоб идти дальше, нужно повернуть налево. А такой алгоритм уже будет в разы сложнее.

Выглядит модернизация алгоритма как дополнительный switch в цикле в блоке движения вперед, который переключается в на основе данных о расстоянии с датчика, снимающего их дискретно каждую секунду. В случае, если робот в течение секунды находит препятствие, он выходит из внутреннего и внешнего циклов с направлением “1” (вправо). Если же секунда истекла, а препятствий не обнаружено, он поворачивает направо и смотрит, есть ли там ход. В положительном случае он туда идет.

  
К сожалению, робота мне пришлось отдать, и настоящий лабиринт для тестирования времени построить не хватило. Но с помощью метода “внезапного препятствия” можно увидеть, как работает робот.

От детей, понятное дело, требовать такой сложности еще рано. Дети хоть и заинтересованы, но им порой не хватает усидчивости, чтоб перебрать несколько вариантов того, как можно заставить программу работать. На хакатоне у детей вышло запрограммировать последовательности конкретных движений робота. Отступать они не догадались, циклы тоже не применили. Поэтому робот мог падать в результате сталкновений, поворачивать под неправильным углом, когда пытался развернуть стенку вместе с собой, и т. п.  Больше всего детям понравилось собирать конструктор лего. :) Возраст детей - от 10 до 14.

Другие задания, которые были на хакатоне:

  1. Собрать роборуку и ею поднимать бумажный стаканчик.
  2. Собрать и написать логику для принтера (двигать машинку так, чтоб она ездила по особой осмысленной траектории и рисовала прикрепленным к ней фломастером).
  3. Борьба роботов: 2 команды собирают по роботу и встраивают в них датчик касания, так что при нажатии на него робот “умирает”. Один робот должен атаковать другого и попасть в то самое место :)

Скоро будет новый хакатон. Взрослые будут учиться давать детям посильные интересные задачи, а дети - их выполнять. :)

Если у кого-нибудь есть соответствующий опыт или полезные советы, буду рада прочитать.

воскресенье, 16 октября 2016 г.

What to Do When Parallel Threads Modify the Same DB Row

During several days I was trying to solve an issue with rowlock on Oracle and MariaDB (MySQL). There were concurrent requests entering into @Transactional* method which changed data in the DB.





HOW TO DEBUG


When solving such issues, it might be hard to reproduce the situation because of the concurrency. One solution is to use logging or simple output. It’ll give understanding at least how many streams have passed a particular point in the code. Using static variables can also help. Iterating them might give an estimate of the number of times something happens.

It’s possible to send two concurrent threads using, for example, sleep() for a thread. Placing it before the problematic area will provide enough time to send as many threads as needed. However, you might need to use static counter in order to let every second thread without falling asleep.



HOW TO FIX

Lock


In the case of reading-writing the data, the safest fix is to put a trigger, which tells if the area contains consistent information or it’s better to wait till the previous thread finishes changing the resource. To find out more about this mechanism, read about Semaphores and, particularly, about one of its implementations, Mutex. What was especially strange with this approach in my case was that in MariaDB all worked fine but not in Oracle. The problem was that with the find request I used the following annotation: @Lock(PESSIMISTIC_WRITE). Its parameter is LockModeType enum value. Somehow it seems not to work proper with Oracle 12 or Hibernate 5.0.2.Final. What helped was to use entityManager.lock(Entity, LockModeType) method. You can also make a lock on the session: entityManager.unwrap(Session.class).lock(Entity, LockMode). Here you can get more general info about locking. For more information why the annotation didn't work and how to fix it check the following StackOverflow question of mine. One of the Hibernate authors was very kind to reply.


Exchange Uncommitted Info (Scarry)


There are different ways to fix the problem, but they heavily depend on the code. For example, you can enable information exchange between transactions-sessions. As soon as the data are changed in terms of one session, the other one will become aware of it and will read the already updated data. This feature can be enabled using READ_UNCOMMITED in the DB. Note that it’s default isolation level in MariaDB (MySql) but it’s not applicable in serious Oracle.
It’s also possible to use Hibernate’s second level cache.

Problems may occur, however. If the transaction that changed the data and gave it to the next parallel transaction rollbacks, the data, with which the second transaction operates, might become erroneous. Besides, it’s always better to have guarantees that 2 parallel transactions won’t read the data being changed, which they use to write new information. The first transaction still could want to continue updating the data, when the second one had already read it to change.


Try Until You Make it or Fast fix


Badly written locks can produce deadlocks. Two threads will constantly attempt to access the same resource. Each will wait until the other one releases the DB. If this happens very rarely, you might be interested in using Ostrich algorithm. The better solution might be to get rid of possible deadlocks and wait till the exception of writing to the DB happens. When it does, just try again and hope that this time, no other thread will want to disturb the same data. This solution might be applied when the problem happens really rarely, and when putting a lock will cause serious downshift in performance. For example, I knew that the erroneous insert to the DB was always followed by update, and I couldn’t have 2 bad consecutive inserts. So the just described fix worked for my problem.

I wish you good luck! Have fun with your problem. Hope the fix comes soon. :)

* This article is inspired by experienced problems in Java + Spring + Hibernate + SpringData + DB (Oracle and MariaDB)

воскресенье, 29 мая 2016 г.

Почему нам всем нужна герань или О старости

Сегодня вышла на улицу, а на ближайшем перекрестке на заборчике сидит бабушка, старая-старая, руки худые, что аж вены проступают. Разложила, что дома "запасного" нашла и продает. Пуговицы, грелка, перчатки резиновые, мелки, чтоб кройку помечать и др. Увидела, что я смотрю и сразу жадно сказала "Купіть". Я тогда только вышла, останавливаться не хотела, да и очень горько на все это смотреть было. Иду и думаю, что ей жить, наверно-то не на что, вот она и вынесла из дома, что могла. Она не идет просить милостыню от нужды, пытается заработать, как может. Не впервые я ее там вижу. Пол года назад она мне уже продала баночку меда, рассказывая, что ест по чайной ложке с мужем на ночь и уже прожила до почти 90 лет. Сказала, что мед лишний и им с мужем хватит. Сейчас, видно, "лишнего" уже нет. 
Когда назад шла, она все еще сидела. Дала я ей денег. Она очень обрадовалась и сначала даже не знала, что делать от счастья. Пошла потом вдогонку и стала давать мне мелок и перчатки. Настаивала, чтоб я взяла и что такое всем пригодится. Мне не хотелось брать вообще ничего от нее. Но все-таки взяла мелок, чтоб ей легче было, чтоб не выглядело, как милостыня для нее.
Очень стыдно, когда старые люди живут в нищете. Одно дело, когда перед тобой все двери могут открыться, ты только захоти, а другое - когда ты уже отдал все, что мог, и стал ненужным отбросом, оставленным на попечение только себе.

В каждом городе есть бабушки и дедушки, которым стыдно просить.Поэтому они продают отвертку, книгу, старые часы или герань.По-моему, нам всем нужна герань!!?
Есть 2 хорошие поговорки:     На все воля Божья и     Бог не дает таких трудностей, с которыми мы не могли бы справиться.
Так что надо уметь жить сегодняшним днем, чтоб в случае непредсказуемой беды, было о чем вспомнить и вдохновиться. А так же надо стелить солому про запас, где упасть вдруг можем, чтоб мягче падать. Хорошему человеку люди не дадут пропасть.

вторник, 10 мая 2016 г.

Visit to Riga Dev Day

Recently I had a chance to attend Riga Dev Day. This is an up-and-coming Java conference in the capital of Latvia, which is a high-key and at the same time poise place. Riga Dev Day has been held only since 2014 but its level of organization and interestingness was above my expectations. The talks took place in the first two days, and the last day was devoted to master classes.

There were many sponsor companies, and each advertised their products and wanted to hire more workers. Therefore, in case you want a nice job but are not sure which company to apply then just check out the sponsors. With high probability, you will find something neat for yourself.

What I personally liked the most is the IoT stuff (Arduino Company). As I envision this, it’s the part of houses of the future. The company cooperates with Bosh and tries to pave the way to reliable and cheap control systems for our belongings through Wi-Fi or Bluetooth. Currently they work on controlling the state of the washing machine by taking information from its electronic parts, which is a thin end of the wedge. As a result, they will have a program to give advice on which parts need updating, cleaning, or replacing, and when. After they’re done with the washing machine, they will put the chips in other devices produced by Bosh, and so make the communication between your belongings and yourself possible.

I have never seen a living IBM employee so for sure I staked to come to the stand. They proposed Bluemix—a server for web apps in different languages. Java, Python, JS, and many others are included, but no Kotlin for now.

Accenture is one of the biggest Latvian companies, which might be the reason why they gave the most generous presents to the participants. In order to participate in the lottery, one had to put the filled form in a little carton cube. The cube was then placed into a big box. The curious this is that the box was placed by a wooden robot-excavator on remote control. That was big fun. There were way too many buttons to navigate robot parts. You always get the feeling that the company cares a lot about its employees if it proposes something interesting you’ve got to handle to win the price.
The picture with the companies’ names is attached below so you may check on your own what others do/produce. I believe that none of them is are dubious.

Another thing I cared about was Ukrainians presenting some of the companies. Some of them work in Latvia, others are just Ukrainian partners that came to present the product. It was interesting to talk to them and hear out their opinions about working with the Latvians.

Obviously, sponsors are not the only thing you’d come to the conference for. Please check below some talks that might interest you.

  • Java 9 by Dalibor Topic—a general overview of the new features. The talk was about the changes brought to the language of the L size (impacts everyone), M size (you might come across like default garbage collector), and S size (you might stumble upon only in very limited cases).
  • Also, I have learnt the basics of Kotlin thanks to the talk by Svetlana Isakova, its developer. She really tried to make everyone follow what she was presenting, and, it seems, achieved the goal. 
  • The speaker who gets my other prize for an interesting talk is David Dalabassee with his news about the Web Front. He spoke a lot about parsing JSON, which is exactly what’s being used at my project.

To sum up, everyone at the conference was open-minded, easy-going, and just outstanding. I have got many positive impressions about the talks, the people, and the city, so be sure to come the next year and feel that for yourself.

воскресенье, 8 ноября 2015 г.

XP Days Review

Some talks and their describtion


XP Days is a 2 days conference being held in Kyiv, Ukraine for 6 years now. This conference is mainly devoted to style of leading IT projects and is pretty much unique in its kind. I’ve visited it recently, so here is my overview of the talks and speakers.



There were almost no similar talks at the conference; here is the schedule, and generally that’s what I’ll be using to guide you.





The time each speaker had was 50 minutes per slot. Yan Drugalya talked for around 25 minutes, and next 20 minutes or so he was answering the questions. He works at a project with many platforms, huge number of users and deployments. Obviously, they have enormous quantity of tests with varying settings and peculiarities. Here are some tests managing solutions that he proposed:
- Use Perl for setting running tests
- Unified Test Runner (UTR): a single entry point for running all tests
- Hoarder Web Service, which integrates test execution data, both from local and Build Farm test runs.
The proposals are not for everyone, moreover I didn’t see the tools on the market. Still, it was interesting to find out about something really big. Here you can read more.

Viktor Farcic talked about scaling your services. He proposed to compose and decompose them using Docker, which allows creation and sharing software through Docker images that can be ran on any platform. He also suggested using immutable deployment rather than mutable one. The main idea is that you divide your software into stable blocks, and with every deploy one creates new instance of the software not destroying the old version. He also proposed to use tools that determine, on which server to deploy the container depending on its resources. Such tools are Kubernetes, Swarm, and Mesos DCOS. Docker + Kubernetes were better described in Carlos Sanchez talk.

For me, never having experienced Ruby myself, it was pretty interesting to attend Boris Tveritnev talk. He was explaining purely technical material through communication with public which as for me is one of the most working methods.  Here is what I’ve learnt:
- Duck Typing is when it doesn’t matter which type of an object is used. What  really matters are methods or actions that can be performed with an object. In Ruby it’s possible to try to apply the method to the parent object if one of its children has its implementation. The instance of the child will be determined during the runtime.
- DDD is domain driven design, which helps separate static and dynamic parts of the code.
- DCI, or data, context, integration, is about making what has to be done having domain data by applying roles to it. It also allows to mock parts easily.
Here you can look through the slides of the presentation, even though they’d look much better with audio.

Don't create what you can buy
Many people attended talks of Venkat Subramaniam; he was talking during 4 slots! The subjects were Towards an Evolutionary Architecture and TDD. Probably, the main thing I should say is that it doesn’t matter, which particular subject he’s talking about. He’d always lead you to some simple verity which you’ll memorize like a rule.
Don't split functionality between sprints, evaluate the priority by value and architectural changes
Wait to pay until you're sure

Andrey Dzynia gave a great talk about (automation) testing. Those who’re thinking over this job should see the talk. One of his points is that programmers and testers think in different ways, and programmer might never look on something tester would do during ad hoс testing. He’s also proposed to read Thinking, Fast and Slow by Daniel Kahneman. That’s what I’m interested in recently. There are people who are super fast and efficient, but sometimes they don’t notice some stuff on the way. Others are slow, and such kind of problems are generally eliminated.



Finally, I’ll tell about the talk, which was one of my favorites at the conference. It was about pair programming by Jon Jagger. The thing is that I’ve heard a lot about it before, even tried it myself and liked it. So I wasn’t sure if I should pick another slot. Nevertheless, some thoughts I’ve heard during the talk changed my view on project organization. For example, the project is well organized when enrolled employees have some spare time. Sounds easy and pretty rational if you’re not the customer who pays for this spare time I believe. Still if to take the statistics, on all my projects except for one, I either had almost no spare time or I had to overtime. So these words made me think why so, how it can be changed, and how much real work on the project is left when all the formalities that support bureaucracy are eliminated. He also proposed to give some time off (possibly, a week) to every employee every once in a while when he’s minimally enrolled in the project but studies something new. After this small vacation he might share the knowledge with all the team members, and as a result everyone learns something new and potentially useful for the project. This will lead to constant upgrading and bringing better job quality into life.


About the other talks I didn't attend (but have an opinion) 


Peter Goodliffe has a great last name, and I’ve got a feeling he also has a great life! I didn’t attend his talk, but I met him in person and chatted a bit. Not sure if this information is relevant, but he walks barefoot or in flip-flops, no matter how cold it is outside. He also prefers green nail polish. Sounds strange? Yes, same to me. When it comes to talking, he seems to be an interesting person, so I plan to watch his Becoming a Better Programmer talk when available.


Some speakers are always good. I didn’t attend the talks but I know who to watch in spare time. Mikalai Alimenkou and Viktor Polischuk are on my mind when I’m writing this. Also, Eduards Sizovs is an adorable guy. He talks a lot and pretty fast, so in one speech he gets an opportunity to cover even half related subjects, e.g. solving conflicts having beer in a bar. Not surprisingly, he also gets many questions after the talk. Eugene Krivosheyev is an Agile trainer and is the one who always gives lots of advice on how to make work more efficient.

Hope the conference videos will come soon, and I wish you nice watching time!







P. S. And certainly there were great presents from IntroPRO, Playtika, and Luxoft.

воскресенье, 25 октября 2015 г.

First impression about iPhone and iOS


Thinking of a new phone?


In this article I'll explain the challenges I've faced when started using an iPhone after having used an Android phone. I hope it'll help you to make your choice and to broaden your vision if you've never experienced the "i" company.

If you're an extreme person or just prefer to count every possibility, then first of all you'd better find out the physical reliability tests results of the compared phones. Here are several videos to compare Samsung and iPhone
To sum it up the Samsung S6 looks to be more durable than the iPhone 6. Maybe the situation will change with the next versions, but I don't believe that it will happen rapidly. Why? Apple company reminds me a cat who in his youth was catching mice but later because of being very pretty and sweet was taken by some very nice and rich lady to home. He was fed with great food and started getting very fat so loose his ability to catch his food on his own. Really, why should you need to work on something way better if you already have everything you ever dreamed of?

About the operating system


1) The main purpose to have a phone is to call and to text. The call quality is pretty good, but what about messaging?
My first typed letter went great. But starting from the second I had a question: are the keyboard letters always capital? Why doesn't Shift change it?
Probably Apple users can't write "little" thoughts. By default all their thoughts and so characters should be printed big (uppercase)! One comes back on Earth when one starts typing. Uppercase characters turn out to be absolutely simple average lowercase characters, similar to those typed on an Android device when shift is not pressed.

Did I miss something or the logo of Apple was officially changed?

Think differentThink Bigturns into -> 







While installing apps, I memorized my password very well. I had to input it really lots of times. Counting that it's "strong" and that the keyboard doesn't comprise special symbols it took me around 15 clicks more than it'd take on a standard computer. On my old Android phone it'd take only about 7 clicks more.

2) Battery longlasting wishes to be longer.
My WIFI, GPS and mobile network were pretty much the only consumers of the battery, if not to take into account the phone by itself. Initial charge in the beginning of the day was around 75%. During the day WIFI was on around 2 hours: I've downloaded several apps. I've made 6 pics and spent around 5 minutes in calls. Battery died. I guess the facts told you enough, no extra comments are needed.

3) Usability of iPhone losses in the next points:

-  Where is the handy turn on/off board? Like where do I turn on/off my mobile Internet, GPS and similar? Oh, probably you might go to settings, find them there and set them the way you need! Yes, there is some menu which flies out of the bottom in you pressNew WIFI network? Any chance you'll be proposed  the list of all when you just pick WIFI option on a footer menu like you may do in Android? Life is not that easy, buddy. Go to Settings!

 - You won't see the percentage of your accumulator life unless you set it in settings. Note that they change the structure of settings pretty often. Like in iOS8 version it was not like in iOS9. Similar story with GPS setting and probably many more. iOS developers and testers might have big fights because of that. Maybe you remember but when Windows decided to change the structure of the Control Panel there was a big discussion over it. Like how could they have it same in all versions before Windows XP and make in absolutely different in Windows 7? Microsoft guys simply made a comfortable search so that those who're used to the old look could still find what they searched for without actually searching.

- My iPhone doesn't always display horizontal picture when I turn it.



- If you have a relatively large iPhone yet the one which fits nicely in a hand (e. g. iPhone 6 with 4,7 inches diagonal), it's not that trivial to press "back" button. Android phone has it in the bottom (near thumb) while iPhone in the top left corner. I can reach this place comfortably only when I hod the phone in the left hand and my other fingers are under the middle of the device. Still I prefer the right hand and to hold the expensive gadget in the bottom to prevent any chance to let it go. My thumb should be completely over it always be ready to firmly cover the phone.


Maybe I lack some marks in settings, but it would be nice to be proposed to complete the word and input the next which fits when it’s typedI'd prefer as well my login name to be memorized and picked after several letters are typed. The phone managed to memorize my first name for 2 inputs, then it disappeared and I can't get it back.  After several attempts at my last name, it started remembering it but I don't know how long it'll last. iPhone has dictionaries for some languages like English and Russian, but not for Ukrainian. It’s still better on phone than on computer. OSX corrects Ukrainian words thinking some of them are Russian even though the Ukrainian language is on. I'm grateful that iPhone doesn't do it.

- It is also important to mention that it's not that trivial to set up a song from an iPhone as a ringtone. Just look how many actions have to be performed for something ordinary on Android.

- The last but not least is that putting the cursor in the middle of the word while typing generally takes you longer than in Android at least when the phone is in vertical position. The reason for that is it takes time to turn on the magnifier and for the last one to look at the text and the cursor position.

That was lots of critics and I still have some. I bet I'll have even more. Still I'm happy to have a chance to use the iPhone and feel how cozy it is to read something from it, use pictures filters and just enjoy those nice visual effects.

Now, you're to decide if you're ready to pay several hundreds dollars more to get something that let's say cute but easily rottens inside, crashes and with not great usability. By the way, here is the link to compare how much better iPhones get with every new edition. When you look on the new coming iPhone 7 just remember who was the first to go beyond the edge and when it happened.