aboutsummaryrefslogtreecommitdiff
path: root/content
diff options
context:
space:
mode:
Diffstat (limited to 'content')
-rw-r--r--content/2015-11-10-software-development-pitfalls.md86
-rw-r--r--content/2016-10-14-how-we-destroyed-development.md40
-rw-r--r--content/2017-01-12-gce-aws-docker-digitalocean.md51
-rw-r--r--content/2017-03-07-golang-profiling-simplified.md122
-rw-r--r--content/2017-04-10-what-its-like-to-be-a-software-developer.md34
-rw-r--r--content/2017-04-17-what-i-ve-learned-developing-ad-server.md145
-rw-r--r--content/2017-04-21-profiling-python-web-applications-with-visual-tools.md193
-rw-r--r--content/2017-08-11-simple-iot.md500
-rw-r--r--content/2018-01-16-using-digitalocean-spaces-object-storage-with-fuse.md272
-rw-r--r--content/2018-08-05-the-bullshit-web-developments-pov.md94
-rw-r--r--content/2019-01-03-encoding-binary-data-into-dna-sequence.md416
-rw-r--r--content/2019-05-11-bci.md71
-rw-r--r--content/cv.md68
-rw-r--r--content/files/avatar-512x512.pngbin533383 -> 0 bytes
-rw-r--r--content/files/avatar-64x64.pngbin11266 -> 0 bytes
-rw-r--r--content/files/bci/spike-waves.pngbin1037764 -> 0 bytes
-rw-r--r--content/files/copy-benchmarks.tsv101
-rw-r--r--content/files/dev101-git-topics-1.pngbin13317 -> 0 bytes
-rw-r--r--content/files/dev101-git-topics-2.pngbin12260 -> 0 bytes
-rw-r--r--content/files/dna-sequence/benchmarks.odsbin21911 -> 0 bytes
-rw-r--r--content/files/dna-sequence/chart-encoding-speed.pngbin14201 -> 0 bytes
-rw-r--r--content/files/dna-sequence/chart-file-sizes.pngbin12391 -> 0 bytes
-rw-r--r--content/files/dna-sequence/dna-basics.jpgbin165883 -> 0 bytes
-rw-r--r--content/files/dna-sequence/quote.pngbin1068 -> 0 bytes
-rw-r--r--content/files/dna-sequence/sample-binary-file.pngbin66417 -> 0 bytes
-rw-r--r--content/files/dna-sequence/sample.pngbin65930 -> 0 bytes
-rw-r--r--content/files/fuse-droplets.pngbin42891 -> 0 bytes
-rw-r--r--content/files/fuse-spaces.pngbin32450 -> 0 bytes
-rw-r--r--content/files/golang-profiling-cpu.pdfbin16518 -> 0 bytes
-rw-r--r--content/files/golang-profiling-mem.pdfbin19221 -> 0 bytes
-rw-r--r--content/files/iot-app-output.pngbin23767 -> 0 bytes
-rw-r--r--content/files/iot-rest-example.pngbin33912 -> 0 bytes
-rw-r--r--content/files/iot-sqlite-db.pngbin199821 -> 0 bytes
-rw-r--r--content/files/kcachegrind.pngbin88486 -> 0 bytes
-rw-r--r--content/files/profiling-viewer.pngbin173672 -> 0 bytes
-rw-r--r--content/files/simple-iot-application-overview.svg2
-rw-r--r--content/files/simple-iot-application.zipbin6406 -> 0 bytes
-rw-r--r--content/files/snakeviz.pngbin59601 -> 0 bytes
-rw-r--r--content/files/sqlite-benchmarks.tsv1001
-rw-r--r--content/files/style.css6
40 files changed, 0 insertions, 3202 deletions
diff --git a/content/2015-11-10-software-development-pitfalls.md b/content/2015-11-10-software-development-pitfalls.md
deleted file mode 100644
index 76924fe..0000000
--- a/content/2015-11-10-software-development-pitfalls.md
+++ /dev/null
@@ -1,86 +0,0 @@
1---
2
3layout: post
4title: Software development and my favorite pitfalls
5description: Couple of observations regarding project management.
6slug: software-development-pitfalls
7date: 2015-11-10
8---
9
10**Table of contents**
11
121. [Initial thoughts](#initial-thoughts)
132. [Ping emails](#ping-emails)
143. [Everybody is a project manager](#everybody-is-a-project-manager)
154. [We are never wrong](#we-are-never-wrong)
165. [Micromanaging](#micromanaging)
176. [Human contact, no need for it!](#human-contact-no-need-for-it)
187. [MVP is killing innovation](#mvp-is-killing-innovation)
198. [Pressure wasteland](#pressure-wasteland)
209. [Conclusion](#conclusion)
21
22## Initial thoughts
23
24Over the years I had privilege to work on some very excited projects both in software development field and also in electronics field and every experience taught me some invaluable lessons about how NOT TO approach development. And through this post I will try to point out some of the absurd outdated techniques I find the most annoying and damaging during a development cycle. There will be swearing because this topic really gets on my nerves and I never coherently tried to explain them in writing. So if I get heated up please bare with me :)
25
26As new methods of project management are emerging, underlaying processes still stay old and outdated. This is mainly because we as people are unable to completely shift away from this approaches.
27
28I was always struggling with communication, and many times that cost me a relationship or two because I was not on the ball all the time. Through every experience I became more convinced that I am the problem and never ever doubted that the problem may be that communication never evolved a single step from emails. And if you think for a second, not many thing have changed around this topic. We just have different representations of email (message boards, chats, project management tools). And I believe this is the real problem we are facing now.
29
30There are many articles written about hyper connectivity and the effects that are a direct result of it. But mainstream does nothing towards it. We are just putting out fires and we do nothing to prevent it. I am certain this will be a major source of grief in coming years. And what we all can do to avoid this is to change our mindset and experiment on our communication skills, development approaches. We need to maximize possible output that a person can give. And to achieve this we need to listen to them, encourage them. I know that not everybody is a naturally born leader, but everybody has an opinion.
31
32There are many talks right now about methodologies such as Scrum, Kanban, Cleanroom and they all fucking piss me of :). These are all boxes that imprison people and take away their freedom of thought. This is a straight forward mindfuck / amputation of creativity.
33
34Let me list a couple of things that I find really destructive and bad for a project and in a long run company.
35
36## Ping emails
37
38Ping emails are emails you have to write as soon as you receive an email. It’s sole purpose is to inform sender that you received their email and you are working on it. It’s result is only to calm down the sender that their task is being dealt with. It’s intent basically is, I did my job by sending you this email so I am on clear ground. I categorize this email as fuck you email. This is one of the most irritating types of emails I need to write. This is the ultimate control freak show you can experience and it gives sender false feeling of control. Newsflash: We do not live in 1982 where there was a possibility that email never reached destination. I really fucking hate this from the bottom of my heart :)
39
40They should be like: “Yes, I am fucking alive and I am at your service my leash!”. I guess if I would reply like this, I wouldn’t have to write any more of this kind of messages :)
41
42## Everybody is a project manager
43
44Well, this is a tough one. I noticed that as soon as you let people to give their suggestions you are basically fucked. There is a truth in saying: “Give low expectations and deliver little bit more you promised.”.
45
46People tend to take a role of a manager as soon as they are presented with an opportunity. And by getting angry at them you only provoke yourself. They are not at fault. You just need to tell them they are only giving suggestions and not tasks at the beginning and everything will be alright. But if you give them a feeling that they are in control you will have immense problems explaining why their features are not in current release.
47
48Project mission must be always on the top of project requirements and any deviation from it will result in major project butchering. And by this I mean that project will get it’s own path and you will be left with half done software that helps nobody. Clear mission goal and clean execution will allow you to develop software will clear intent.
49
50## We are never wrong
51
52I find this type of arrogance the worst. We must always conduct ourselves that we are infallible and cannot make mistakes. As soon as procedure or process is established there is no room for changes or improvements. This is the most idiotic thing someone can say of think. If think that processes need to involve and change over time. This is imperative and need to have in your organization if you want to improve and develop company. We all need to grow balls and change everything in order to adapt to current situations. Being a prisoner of predefined processes kills creativity.
53
54I am constantly trying new software for project managing and communication. I believe every team has it’s own dynamic and it needs to be discovered organically and naturally through many experiments. By putting team in a box you are amputating their creativity and therefore minimizing their potential. But if you talk to an executive you will mainly find archetypical thinking and a strong need to compartmentalize everything from business processes to resource management. And this type of management that often displays micro management technique only works on short periods (couple of years) and then employees either leave company or become basically retarded drones on auto pilot.
55
56## Micromanaging
57
58This basically implies that everybody on the team is a fucking idiot that needs to have a todo list that they can not write themselves. How about spoon feeding the team at launch because besides the team leader everybody must be a retarded idiot at best.
59
60I prefer milestones as they give developers much more freedom and creativity developing and not waste their time checking some bizarre todo list that was not even thought through. Project always changes through development cycle and all you are left at the end is a list of unchecked tasks and the wrath of management why they are not completed. Best WTF moment!
61
62## Human contact, no need for it!
63
64We are vigorously trying to eliminate physical contact by replacing short meetings with software with no regards that we are not machines. Many times a simple 5min meeting at morning can solve most of the problems. In rapid development short bursts of man to man communication is possibly the best way to go.
65
66We now have all this software available and all what we get out of it is a huge clusterfuck. An obstacle and not a solution. So why we still use them? Because we strive to better ourselves.
67
68## MVP is killing innovation
69
70Many will disagree with me on this one but I stand strong by this statement. What I noticed in my experience that all this buzz words surrounding us only mislead and capture you in a circle of solving a problem that already has a solution but we are unable to see it without using some fancy word for it. The toughest this to do for a developer is to minimize requirements. Well this is though only for bad developers. Yes, I said is. There are many types of developers out there. And those unable to minimize feature scope are the ones you don’t need on your team. Their only goal is to solve problems that exist only in their fucking heads. And than you have to argue with them and waste energy on them instead of developing your awesome product. They are a cancer and I suggest you cut them off.
71
72MVP as an idea is great but sadly people don’t understand underlaying philosophy and they spent too much time focusing and fixating on something that every sane person with normal IQ will understand without some made up acronym. And the result is a lot of talking and barely no execution.
73
74Well MVP is not directly killing innovation but stupid people do when they try to understand it.
75
76## Pressure wasteland
77
78You must never allow to be pressured into confirming a deadline if you are not sure. We often feel a need that we are in service of others which is true to some extent. But it is also true that others are in service to us to some extent. And we forget this. We are all pressured all the time to make decisions just to calm other people down. And when they leave your office you experience WTF moment :) How the hell did they manage to fuck me up again :)
79
80People need to realize that more pressure you put on somebody less they will be able todo. So 5 min update email requests will only resolve in mental breakdown and inability to work that day. Constant poking is probably the only thing I loose my mind instantly. For all you that are doing this: “We are not fucking idiots and stop bothering us with your own insecurities and let us do our job. We will do it quicker and better without you moron breathing on our necks.”
81
82If this happens to me I end up with no energy at the end. Don’t you get it? You will get much more from and out of me if you ask me like a human person and not your personal butler. On a long run you are destroying your relationships and nobody would want to work with you. Your schizophrenic approach will damage only you in a long run. Nobody is anybody’s property.
83
84## Conclusion
85
86I am guilty of many things described in this post. And I find it hard sometimes to acknowledge this. And I lie to myself and try vigorously to find some explanation why I do this things. There is always space for growth. And maybe you will also find some of yourself in this post and realize what needs to change in order to evolve.
diff --git a/content/2016-10-14-how-we-destroyed-development.md b/content/2016-10-14-how-we-destroyed-development.md
deleted file mode 100644
index 25ad46f..0000000
--- a/content/2016-10-14-how-we-destroyed-development.md
+++ /dev/null
@@ -1,40 +0,0 @@
1---
2layout: post
3title: How we successfully destroyed the joy of product development
4description: My take on project development.
5slug: how-we-successfully-destroyed-the-joy-of-product-development
6type: note
7date: 2016-10-14
8---
9
10No matter how hard we try to reinvent processes in software development we still haven’t found perfect solution for this. And to dismiss SDLC just because it’s something old is as ridiculous as the concept of designers being user experience gurus. As I have written couple of times before designers have their place and is not in the UX community. Most of them probably never heard of Jakob Nielsen and this proves a lot. Don’t get me wrong. There are designers out there that are absolutely amazing in what they do, but most of them are not. Good design has little to do with how things look in my opinion. But it has very much to do with how product behaves. And to take a chance on design look only is scary to me.
11
12I have this huge beef with so called UX “experts”. I really do. From the bottom of my heart. I almost hate them. Well, not the pure ghetto ones. There are many of them out there I am sure of. But I have not had the pleasure to work with such person.
13
14Good UX expert should have programming background and an eye for design. Being UX expert requires you to be analytical and precise. Not really qualities of designers. Design is much more about the feeling and emotional perception. And this two don’t dance well together.
15
16Natural progression of project focused on user should be:
17
18- detailed requirements and fantastic prototypes/wireframes with detailed user journey diagrams,
19- design focused and restricted to serve requirements,
20- code written just to fulfill design and requirements → nothing more and nothing less → no additional dead code should be allowed,
21- testing should be done on all targeted devices → avoid bugs and you will avoid brand failure.
22
23Designer should never be allowed to have blank canvas. Good software is written because there are many restrictions either in requirements or real world. And most importantly → good software is solving only one problem at the time. I don’t see why this shouldn’t apply to design as well.
24
25Yes yes we get it, but we don’t have the time or the money to do project development like that. Well, you better find it or you will slowly decline into abyss of mediocre companies that have nothing to show for. Clients are not dumb and are in need of quality products and services. It is not enough anymore for a product that just works. It has to be technically precise and functionally on the spot.
26
27When developers and designers are forced to think and work from the scratch many new doors open. New ideas are born how to solve problems that were previously not possible because they were living in a box of limited thought and patterns. If you solve problems always only with your knowledge nothing new can be invented. When there is no room for experimentation there is no room for improvement. You want your developers and designers to be this fountain of innovation and you don’t really let them innovate, you are just slowly closing front doors of your company. Good developers and designers are hard to find and even easier to loose.
28
29Being agile does not mean to be a slave of constant changes. It does not mean that project managers can constantly change requirements at their will. And it sure does not mean that clear vision on product direction should be something we said goodby to. We have perverted initial intention of Manifesto for Agile Software Development as we always do. We have taken it so far and we have all become slaves of advertisement by consulting companies trying to cash in on this “new - but old” concept.
30
31Manifesto for Agile Software Development states:
32
33- individuals and interactions over processes and tools,
34- working software over comprehensive documentation,
35- customer collaboration over contract negotiation,
36- responding to change over following a plan.
37
38This was written in times when software was developed very differently than how we do it now. We have eliminated many of the problems from old age just by listening to reason and not trendy hyped words that are just tools of marketing strategist to avoid the real issues. Being flat, being agile, being stupid is what I say.
39
40Development and design should be about improving yourself and consequently product you are working on. When this becomes a chore you should probably start thinking about changing companies. People make products not management.
diff --git a/content/2017-01-12-gce-aws-docker-digitalocean.md b/content/2017-01-12-gce-aws-docker-digitalocean.md
deleted file mode 100644
index cd6811c..0000000
--- a/content/2017-01-12-gce-aws-docker-digitalocean.md
+++ /dev/null
@@ -1,51 +0,0 @@
1---
2layout: post
3title: GCE, AWS, Docker and why I choose classic VM’s and DigitalOcean for my current project
4description: Reasons why I choose DigitalOcean for my project
5slug: gce-aws-docker-and-why-i-choose-classic-vms-and-digitalocean
6type: note
7date: 2017-01-12
8---
9
10**Table of contents**
11
121. [Docker tools and complexity that comes with it](#docker-tools-and-complexity-that-comes-with-it)
132. [Lack of real life examples of Docker in action](#lack-of-real-life-examples-of-docker-in-action)
143. [Ease of deployment](#ease-of-deployment)
154. [Where to go from here](#where-to-go-from-here)
16
17I have been developing a product for the past few months and one of product’s requirement is the ability to automatically scale quickly on system’s demand.
18
19As most of you probably know system design is much more important then actual code that will drive the product. And this was my main concern when developing this product. I have read anything I could get my hands on about Docker as it was hyped so much in media for the past two years. At a first glance Docker was ideal fit for this platform. But then as I started to seriously experiment with it and developing around it several problems occurred. Well, it would be unfair to call them problems but lets say drawbacks when developing rapidly.
20
21To put it in perspective: this project is basically MVP that needs to automatically scale when new customers signs up. These customers are sending metrics to my system that is later visualized and analyzed. There were some basic requirements that I needed the answer before I choose technology.
22
23- Pricing involving hardware and infrastructure.
24- Ease of implementation/deployment and scaling.
25- How much will this cost me per customer?
26
27The way I envisioned the architecture was straight forward → simple nodes in cluster that take care of x number of customers (1 node ~ 10 customers). I found that pricing in GCE and AWS is very hard to predict → what the cost will be when system would scale. And this was necessary for me to know in order to make financial projection of costs. This is the most important thing for me at this time as I am deciding on prices we should charge future customers and establish healthy revenue model and subsequently business model. I want this product to organically scale and fuel its future development with money made by product itself → very little startup capital (10 nodes for six months & capital for company expanses). I have made many simulations but could not figure out with at least some certainty what will that cost be. Based on this both of the providers are currently not suited for me. So I choose DigitalOcean. They have really straight forward pricing model and this allowed me to make pretty accurate cost matrix for my infrastructure.
28
29I love hard metrics. By this I mean metrics I can test now and have trust they will hold in the future. This was the reason I found Docker too volatile as containers are spawned and halted and there is really no way in predicting this numbers. I have no problem with spawning multiple VMs and not using them but having basically limited control over that is at this time unacceptable for me.
30
31## Docker tools and complexity that comes with it
32
33Probably some of you will correct me on this one, but I find all this management tools like Kubernetes, Swarm etc a bit overkill for a startup project. All this tools are able to scale really massively but they all require extensive knowledge of DevOps. When you are a one man band trying to push a product out, there just is no time to learn these tools and concepts in depth in order to really take advantage of their features. It is much easier to use internal metrics of your app (uwsgi stats server, golang middleware stats) and simply fetch them to one server and visualize them. That task alone took me couple of hours and I had simple metrics system in place that with collaboration of DigitalOcean API enabled me to auto spawn new VMs on demand when users reached max number of users supported by current number of nodes. There is something to say about simplicity of this solution. And I love simple solutions.
34
35## Lack of real life examples of Docker in action
36
37I found many HelloWorld examples and tutorials showing how to spawn containers and deploying simple python apps but I haven’t found really clear example of showing how to battle permanent storage with containers, load balancing, disk management, ip & port management.
38
39This is not Docker’s nor community’s fault to be absolutely clear. It just shows that it is not that simple to deploy real-world application with Docker. Maybe my software architecture is not designed with Docker in mind.
40
41## Ease of deployment
42
43What I really love about Docker is ease of deployment of your application code via container. Multilayered architecture of Docker images also adds to pros list. And the fact that containers sit on top of host OS makes it very intriguing. But if you use container engine from Google you basically spawn VM’s and run containers in this machines and this takes bare-metal approach out of the equation. So at the end you still use hypervisior. I guess if I had my own hardware servers I would be able to fully take advantage of containers.
44
45Because most of my code in nodes is written in Golang and C++ deployment becomes pretty easy. All I have to do is replace binaries on node and that’s that. To avoid downtime I have two instances of one node and I load balance between them. So when I am updating software I first update on node1.A and then node1.B if first one is successful.
46
47## Where to go from here
48
49Docker is amazing technology. But the weird pricing model and steep learning curve for deployment of real live application at this time is too much of a hassle for me. I am sure I could lower costs with Docker approach but it would just took too much time at this stage to implement it properly.
50
51I am currently trying to adapt my project to fit Docker and I believe this would be an interesting solution. Idea is to use one container for one customer. I would just need to find the solution for auto-spawning containers on demand for a specific customer. I would then need a flexible load balancer to correctly forward traffic to container designated for this customer. The problem I have is that I need very flexible storage solution because the amount of data that will be aggregated will scale exponentially and I need to permanently store this on disk. And VM approach is allowing me to precisely calculate per customer per VM how much disk I need. Maybe one of you may have a better solution.
diff --git a/content/2017-03-07-golang-profiling-simplified.md b/content/2017-03-07-golang-profiling-simplified.md
deleted file mode 100644
index fc79020..0000000
--- a/content/2017-03-07-golang-profiling-simplified.md
+++ /dev/null
@@ -1,122 +0,0 @@
1---
2layout: post
3title: Golang profiling simplified
4description: Golang profiling made easy
5slug: golang-profiling-simplified
6type: note
7date: 2017-03-07
8---
9
10**Table of contents**
11
121. [Where are my pprof files?](#where-are-my-pprof-files)
132. [Why is my cpu profile empty?](#why-is-my-cpu-profile-empty)
143. [Profiling](#profiling)
15 1. [Memory profiling](#memory-profiling)
16 2. [CPU profiling](#cpu-profiling)
17 3. [Generating profiling reports](#generating-profiling-reports)
18
19Many posts have been written regarding profiling in Golang and I haven’t found proper tutorial regarding this. Almost all of them are missing some part of important information and it gets pretty frustrating when you have a deadline and are not finding simple distilled solution.
20
21Nevertheless, after searching and experimenting I have found a solution that works for me and probably should also for you.
22
23## Where are my pprof files?
24
25By default pprof files are generated in /tmp/ folder. You can override folder where this files are generated programmatically in your golang code as we will see below in example.
26
27## Why is my cpu profile empty?
28
29I have found out that sometimes CPU profile is empty because program was not executing long enough. Programs, that execute too quickly don’t produce pprof file in my cases. Well, file is generated but only contains 4KB of information.
30
31## Profiling
32
33As you can see from examples we are executing dummy_benchmark functions to ensure some sort of execution. Memory profiling can be done without such a “complex” function. But CPU profiling needs it.
34
35Both memory and CPU profiling examples are almost the same. Only parameters in main function when calling profile.Start are different. When we set profile.ProfilePath(“.”) we tell profiler to store pprof files in the same folder as our program.
36
37### Memory profiling
38
39```go
40package main
41
42import (
43 "fmt"
44 "time"
45 "github.com/pkg/profile"
46)
47
48func dummy_benchmark() {
49
50 fmt.Println("first set ...")
51 for i := 0; i < 918231333; i++ {
52 i *= 2
53 i /= 2
54 }
55
56 <-time.After(time.Second*3)
57
58 fmt.Println("sencond set ...")
59 for i := 0; i < 9182312232; i++ {
60 i *= 2
61 i /= 2
62 }
63}
64
65func main() {
66 defer profile.Start(profile.MemProfile, profile.ProfilePath("."), profile.NoShutdownHook).Stop()
67 dummy_benchmark()
68}
69```
70
71### CPU profiling
72
73```go
74package main
75
76import (
77 "fmt"
78 "time"
79 "github.com/pkg/profile"
80)
81
82func dummy_benchmark() {
83
84 fmt.Println("first set ...")
85 for i := 0; i < 918231333; i++ {
86 i *= 2
87 i /= 2
88 }
89
90 <-time.After(time.Second*3)
91
92 fmt.Println("sencond set ...")
93 for i := 0; i < 9182312232; i++ {
94 i *= 2
95 i /= 2
96 }
97}
98
99func main() {
100 defer profile.Start(profile.CPUProfile, profile.ProfilePath("."), profile.NoShutdownHook).Stop()
101 dummy_benchmark()
102}
103```
104
105### Generating profiling reports
106
107```bash
108# memory profiling
109go build mem.go
110./mem
111go tool pprof -pdf ./mem mem.pprof > mem.pdf
112
113# cpu profiling
114go build cpu.go
115./cpu
116go tool pprof -pdf ./cpu cpu.pprof > cpu.pdf
117```
118
119This will generate PDF document with visualized profile.
120
121- [Memory PDF profile example](/files/golang-profiling-mem.pdf)
122- [CPU PDF profile example](/files/golang-profiling-cpu.pdf)
diff --git a/content/2017-04-10-what-its-like-to-be-a-software-developer.md b/content/2017-04-10-what-its-like-to-be-a-software-developer.md
deleted file mode 100644
index c6b6010..0000000
--- a/content/2017-04-10-what-its-like-to-be-a-software-developer.md
+++ /dev/null
@@ -1,34 +0,0 @@
1---
2layout: post
3title: What it's like to be a software developer
4description: Couple of observations regarding project management
5slug: what-its-like-to-be-a-software-developer
6type: note
7date: 2017-04-10
8---
9
10I get asked a lot what the hell I actually do. I find it funny but I guess it is my fault in most cases. I try not to be the kind of a man that is always talking about his work. I live in a small village and most of my neighbours probably have no idea what I actually do. And I am ok with that. I prefer this. But on some occasions I find it disturbing how people judge other people just because they don't understand what they are all about. Many of them probably think I am some strange kind of a looser that is awake all the time and works from home. He probably plays games and type on a computer :) What kind of a job is that? That is no job at all! :) You work for eight hours, then you go home and drink a beer and go work in your workshop. This is what real men do!
11
12Well, you know. It's just the way it is. And it takes time for people to understand. Being home after many years in living elsewhere really grounded me in some cases. Coming back to the place where you grew up brings some sort of a humility back in your life. And this is ok. Nobody want's to be Icarus anyways.
13
14What I am meaning to say is if you are in a similar situation as me it will take time for people to start understanding you. Don't get discouraged by this. Take it as it is. People judge what they don't understand.
15
16I have this saying that sleeping is for pussies and we will sleep when we die. I am 32 years old now and I haven't slowed down regarding my work hours. I have steped up the pace. I usually work for about 16-18 hours a day every day. It doesn't matter if it's Monday or Saturday. Work needs to be done.
17
18I know that there are other ways. But if you want to be good there really is no other way. There are no shortcuts. There is no easier way to get to the point where you really know what the hell you are doing. Myth about this genius programmer truly is one huge bullshit. Without putting in the hours nothing can be achieved. There is no success without dedication.
19
20My friends and coworkers often ask me how the hell did I learn so much stuff. Where do I find the time to go through all this material. And I have a simple response for them: "When you go to sleep I begin reading and prototyping. When you go on a trip I make prototype projects just for the sake of learning. When you take your time for fucking around I read articles and books hunting that single small piece of information that will help me one day." And often they don't believe me. They think I am just that smart and everything is easy for me. They have this misguided belief that I just had all this knowledge implanted in me at birth. And this is not the case. I have read so much in my lifetime and most of this information was useful to me later in my life. But that didn't stop me even though I had no immediate use of it. This probably is the main difference between me and my friends. I don't learn because I need to but because I am piecing together this huge puzzle and I threat is like a game. This amazing game of enlightenment.
21
22I had many burn-downs in my career. Most of them come around new years. I guess around this time things slow down a bit and right then when you relax for a minute or two things get real :). They say when you enter your retirment you should never ever park your ass on a couch. You will die there :) When my burndown happens I fall into this huge depression and I start questioning my sanity. I question my decisions. I question my progress in life. I question everything. I try to understand if all this is worth it?! And every time this happens I struggle with this kind of questions. And by the time all this is over I come to the same conclusion every single time. Yes it fucking is worth it. And through the years I have noticed that this is some sort of a reset for me. This helps me maintain my sanity in the long run :) I love it when things get tough. It gets me to the next level. This teaches me progress is life.
23
24I don't even count anymore how many programming languages I have learned. I even stop noticing projects. They just fly by. It's like I am hunting this revelation that is set for me. And this drives me. This helps me every day to step up my game. Every single problem I solve I come little closer to my goal. My never reaching goal. And it's ok with me if I never reach this goal.
25
26The only problem I have now is time. There just ain't enough time to learn everything day has to offer. It's like I am on a quest to become this mini search machine :).
27
28This obsession with learning has come to the point where I stopped watching TV and news all together. I find this as noise that clutters your mind. The whole point about news is to frighten you and put your mind into a dangerous loop where you thinks that nothing matters anyways → world is going to shit. And the truth is so far away from this. We are living in this times where all this amazing possibilities are at hand. We just need to take control of our mindset and everything starts to look possible again.
29
30What else can say after more than 10 years in this space? What else can be said anyways? I still love what I do as much as I did 10 years ago. I love it even more. And if I would have a single suggestion for all of you is to stop worrying about immediate benefits and focus on the long run. Learn, prototype, experiment and have fun. We all get frustrated at times but that doesn't mean we should stop. Doing this kind of work is a privilege. We are making and creating. In the most pure sense we are creators. And there really is no better way to live your life.
31
32> A life without challenge, a life without hardship, a life without purpose, seems pale and pointless. With challenge come perseverance and gumption. With hardship come resilience and resolve. With purpose come strength and understanding.
33>
34> — Terry Fallis, The High Road
diff --git a/content/2017-04-17-what-i-ve-learned-developing-ad-server.md b/content/2017-04-17-what-i-ve-learned-developing-ad-server.md
deleted file mode 100644
index c186484..0000000
--- a/content/2017-04-17-what-i-ve-learned-developing-ad-server.md
+++ /dev/null
@@ -1,145 +0,0 @@
1---
2layout: post
3title: What I've learned developing ad server
4description: Lessons I learned developing contextual ad server
5slug: what-i-ve-learned-developing-ad-server
6type: note
7date: 2017-04-17
8---
9
10**Table of contents**
11
121. [Aggregate everything](#aggregate-everything)
132. [Measure everything](#measure-everything)
143. [Cache control is your friend](#cache-control-is-your-friend)
154. [Learn NGINX](#learn-nginx)
165. [Use Redis/Memcached](#use-redismemcached)
176. [Conclusion](#conclusion)
18
19For the past year and half I have been developing native advertising server that contextually matches ads and displays them in different template forms on variety of websites. This project grew from serving thousands of ads per day to millions.
20
21The system is made from couple of core components:
22
23- API for serving ads,
24- Utils - cronjobs and queue management tools,
25- Dashboard UI.
26
27Initial release was using [MongoDB](https://www.mongodb.com/) for full-text search but was later replaced by [Elasticsearch](https://www.elastic.co/) for better CPU utilization and better search performance. This provided us with many amazing functionalities of [Elasticsearch](https://www.elastic.co/). You should check it out if you do any search related operations.
28
29Because the premise of the server is to provide native ad experience, they are rendered on the client side via simple templating engine. This ensures that ads can be displayed number of different ways based on the visual style of the page. And this makes Javascript client library quite complex.
30
31So now that you know basic information about the product lets get into the lessons we learned.
32
33## Aggregate everything
34
35After beta version was released everything (impressions, clicks, etc) was written in nanosecond resolution in the database. At that time we were using [PostgreSQL](https://www.postgresql.org/) and database quickly grew way above 200GB in disk space. And that was problematic. Statistics took disturbingly long time to aggregate. Also using indexes on stats table in database was no help after we reached 500 million datapoints.
36
37> There is a marketing product information and there is real life experience. And the tend to be quite the opposite.
38
39This was the reason that now everything is aggregated on daily basis and this data is then fed to Elastic in form of daily summary. With this we achieved we can now track many more dimensions such as zone, channel and platform information. And with this information we can now adapt occurrences of ads on specific places more precisely.
40
41We have also adapted [Redis](https://redis.io/) as a full-time citizen in our stack. Because Redis also stores information on a local disk we have some sort of backup if server would accidentally suffer some failure.
42
43All the real-time statistics for ad serving and redirecting is presented as counters in Redis instance and daily extracted and pushed to Elastic.
44
45## Measure everything
46
47The thing about software is that we really don't know how well it is performing under load until such load is presented. When testing locally everything is fine but when on production things tend to fall apart.
48
49As a solution for this we are measuring everything we can. Function execution time (by encapsulating functions with timers), server performance (cpu, memory, disk, etc), Nginx and [uWSGI](https://uwsgi-docs.readthedocs.io/) performance. We sacrifice a bit of performance for the sake of this information. And we store all this information for later analysis.
50
51**Example of function execution time**
52
53```json
54{
55 "get_final_filtered_ads": {
56 "counter": 1931250,
57 "avg": 0.0066143431,
58 "elapsed": 12773.9500310003
59 },
60 "store_keywords_statistics": {
61 "counter": 1931011,
62 "avg": 0.0004605267,
63 "elapsed": 889.2821669996
64 },
65 "match_by_context": {
66 "counter": 1931011,
67 "avg": 0.0055960716,
68 "elapsed": 10806.0758889999
69 },
70 "match_by_high_performance": {
71 "counter": 262,
72 "avg": 0.0152770229,
73 "elapsed": 4.00258
74 },
75 "store_impression_stats": {
76 "counter": 1931250,
77 "avg": 0.0006189991,
78 "elapsed": 1195.4419869999
79 }
80}
81```
82
83We have also started profiling with [cProfile](https://pymotw.com/2/profile/) and then visualizing with [KCachegrind](http://kcachegrind.sourceforge.net/). This provides much more detailed look into code execution.
84
85## Cache control is your friend
86
87Because we use Javascript library for rendering ads we rely on this script extensively and when in need we need to be able to change behavior of the script quickly.
88
89In our case we can not simply replace javascript url in html code. It usually takes a day or two for the guys who maintain sites to change code or add ?ver=xxx attribute. And this makes rapid deployment and testing very difficult and time consuming. There is a limitation of how much you can test locally.
90
91We are now in the process of integrating [Google Tag Manager](https://www.google.com/analytics/tag-manager/) but couple of websites are developed on ASP.net platform that have some problems with tag manager. With a solution below we are certain that we are serving latest version of the script.
92
93And it only takes one mistake and users have the script cached and in case of caching it for 1 year you probably know where the problem is.
94
95```nginx
96# nginx ➜ /etc/nginx/sites-available/default
97location /static/ {
98 alias /path-to-static-content/;
99 autoindex off;
100 charset utf-8;
101 gzip on;
102 gzip_types text/plain application/javascript application/x-javascript text/javascript text/xml text/css;
103 location ~* \.(ico|gif|jpeg|jpg|png|woff|ttf|otf|svg|woff2|eot)$ {
104 expires 1y;
105 add_header Pragma public;
106 add_header Cache-Control "public";
107 }
108 location ~* \.(css|js|txt)$ {
109 expires 3600s;
110 add_header Pragma public;
111 add_header Cache-Control "public, must-revalidate";
112 }
113}
114```
115
116Also be careful when redirecting to url in your python code. We noticed that if we didn't precisely setup cache control and expire headers in response we didn't get the request on the server and therefore couldn't measure clicks. So when redirecting do as follows and there will be no problems.
117
118```python
119# python ➜ bottlepy web micro-framework
120response = bottle.HTTPResponse(status=302)
121response.set_header("Cache-Control", "no-store, no-cache, must-revalidate")
122response.set_header("Expires", "Thu, 01 Jan 1970 00:00:00 GMT")
123response.set_header("Location", url)
124return response
125```
126
127> Cache control in browsers is quite aggressive and you need to be precise to avoid future problems. We learned that lesson the hard way.
128
129## Learn NGINX
130
131When deciding on a web server we went with Nginx as a reverse proxy for our applications. We adapted micro-service oriented architecture early in the project to ensure when we scale we can easily add additional servers to our cluster. And Nginx was crucial to perform load balancing and static content delivery.
132
133At first our config file was quite simple and later grew larger. After patching and adding new settings I sat down and learned more about the guts of Nginx. This proved to be very useful and we were able to squeeze much more out of our setup. So I advise you to take your time and read through the [documentation](https://nginx.org/en/docs/). This saved us a lot of headache. Googling for solutions only goes so far.
134
135## Use Redis/Memcached
136
137As explained above we are using caching basically for everything. It is the corner stone of our services. At first we were very careful about the quantity of things we stored in [Redis](https://redis.io/). But we later found out that the memory footprint is very low even when storing large amount of data in it.
138
139So we gradually increased our usage to caching whole HTML outputs of dashboard. This improved our performance in order of magnitude. And by using native TTL support this goes hand in hand with our needs.
140
141The reason why we choose [Redis](https://redis.io/) over [Memcached](https://memcached.org/) was the nature of scalability of Redis out of the box. But all this can be achieved with Memcached.
142
143## Conclusion
144
145There are a lot more details that could have been written and every single topic in here deserves it's own post but you probably got the idea about the problems we faced.
diff --git a/content/2017-04-21-profiling-python-web-applications-with-visual-tools.md b/content/2017-04-21-profiling-python-web-applications-with-visual-tools.md
deleted file mode 100644
index 6e52ee0..0000000
--- a/content/2017-04-21-profiling-python-web-applications-with-visual-tools.md
+++ /dev/null
@@ -1,193 +0,0 @@
1---
2layout: post
3title: Profiling Python web applications with visual tools
4description: Missing link when debugging and profiling python web applications
5slug: profiling-python-web-applications-with-visual-tools
6type: note
7date: 2017-04-21
8---
9
10**Table of contents**
11
121. [Simple web-service](#simple-web-service)
132. [Visualize profile](#visualize-profile)
143. [Update 2017-04-22](#update-2017-04-22)
15
16I have been profiling my software with KCachegrind for a long time now and I was missing this option when I am developing API's or other web services. I always knew that this is possible but never really took the time and dive into it.
17
18Before we begin there are some requirements. We will need to:
19
20- implement [cProfile](https://docs.python.org/2/library/profile.html#module-cProfile) into our web app,
21- convert output to [callgrind](http://valgrind.org/docs/manual/cl-manual.html) format with [pyprof2calltree](https://pypi.python.org/pypi/pyprof2calltree/),
22- visualize data with [KCachegrind](http://kcachegrind.sourceforge.net/html/Home.html) or [Profiling Viewer](http://www.profilingviewer.com/).
23
24
25If you are using MacOS you should check out [Profiling Viewer](http://www.profilingviewer.com/) or [MacCallGrind](http://www.maccallgrind.com/).
26
27![KCachegrind](/files/kcachegrind.png)
28
29We will be dividing this post into two main categories:
30
31- writing simple web-service,
32- visualize profile of this web-service.
33
34## Simple web-service
35
36Let's use virtualenv so we won't pollute our base system. If you don't have virtualenv installed on your system you can install it with pip command.
37
38```bash
39# let's install virtualenv globally
40$ sudo pip install virtualenv
41
42# let's also install pyprof2calltree globally
43$ sudo pip install pyprof2calltree
44
45# now we create project
46$ mkdir demo-project
47$ cd demo-project/
48
49# now let's create folder where we will store profiles
50$ mkdir prof
51
52# now we create empty virtualenv in venv/ folder
53$ virtualenv --no-site-packages venv
54
55# we now need to activate virtualenv
56$ source venv/bin/activate
57
58# you can check if virtualenv was correctly initialized by
59# checking where your python interpreter is located
60# if command bellow points to your created directory and not some
61# system dir like /usr/bin/python then everything is fine
62$ which python
63
64# we can check now if all is good ➜ if ok couple of
65# lines will be displayed
66$ pip freeze
67# appdirs==1.4.3
68# packaging==16.8
69# pyparsing==2.2.0
70# six==1.10.0
71
72# now we are ready to install bottlepy ➜ web micro-framework
73$ pip install bottle
74
75# you can deactivate virtualenv but you will then go
76# under system domain ➜ for now don't deactivate
77$ deactivate
78```
79
80We are now ready to write simple web service. Let's create file app.py and paste code bellow in this newly created file.
81
82```python
83# -*- coding: utf-8 -*-
84
85import bottle
86import random
87import cProfile
88
89app = bottle.Bottle()
90
91# this function is a decorator and encapsulates function
92# and performs profiling and then saves it to subfolder
93# prof/function-name.prof
94# in our example only awesome_random_number function will
95# be profiled because it has do_cprofile defined
96def do_cprofile(func):
97 def profiled_func(*args, **kwargs):
98 profile = cProfile.Profile()
99 try:
100 profile.enable()
101 result = func(*args, **kwargs)
102 profile.disable()
103 return result
104 finally:
105 profile.dump_stats("prof/" + str(func.__name__) + ".prof")
106 return profiled_func
107
108
109# we use profiling over specific function with including
110# @do_cprofile above function declaration
111@app.route("/")
112@do_cprofile
113def awesome_random_number():
114 awesome_random_number = random.randint(0, 100)
115 return "awesome random number is " + str(awesome_random_number)
116
117@app.route("/test")
118def test():
119 return "dummy test"
120
121if __name__ == '__main__':
122 bottle.run(
123 app = app,
124 host = "0.0.0.0",
125 port = 4000
126 )
127
128# run with 'python app.py'
129# open browser 'http://0.0.0.0:4000'
130```
131
132When browser hits awesome\_random\_number() function profile is created in prof/ subfolder.
133
134## Visualize profile
135
136Now let's create callgrind format from this cProfile output.
137
138```bash
139$ cd prof/
140$ pyprof2calltree -i awesome_random_number.prof
141# this creates 'awesome_random_number.prof.log' file in the same folder
142```
143
144This file can be opened with visualizing tools listed above. In this case we will be using Profilling Viewer under MacOS. You can open image in new tab. As you can see from this example there is hierarchy of execution order of your code.
145
146![Profilling Viewer](/files/profiling-viewer.png)
147
148> Make sure you convert output of the cProfile output every time you want to refresh and take a look at your possible optimizations because cProfile updates .prof file every time browser hits the function.
149
150This is just a simple example but when you are developing real-life applications this can be very illuminating, especially to see which parts of your code are bottlenecks and need to be optimized.
151
152## Update 2017-04-22
153
154Reddit user [mvt](https://www.reddit.com/user/mvt) also recommended this awesome web based profile visualizer [SnakeViz](https://jiffyclub.github.io/snakeviz/) that directly takes output from [cProfile](https://docs.python.org/2/library/profile.html#module-cProfile) module.
155
156<div class="reddit-embed" data-embed-media="www.redditmedia.com" data-embed-parent="false" data-embed-live="false" data-embed-uuid="583880c1-002e-41ed-a373-020a0ef2cff9" data-embed-created="2017-04-22T19:46:54.810Z"><a href="https://www.reddit.com/r/Python/comments/66v373/profiling_python_web_applications_with_visual/dgljhsb/">Comment</a> from discussion <a href="https://www.reddit.com/r/Python/comments/66v373/profiling_python_web_applications_with_visual/">Profiling Python web applications with visual tools</a>.</div><script async src="https://www.redditstatic.com/comment-embed.js"></script>
157
158```bash
159# let's install it globally as well
160$ sudo pip install snakeviz
161
162# now let's visualize
163$ cd prof/
164$ snakeviz awesome_random_number.prof
165# this automatically opens browser window and
166# shows visualized profile
167```
168
169![SnakeViz](/files/snakeviz.png)
170
171Reddit user [ccharles](https://www.reddit.com/user/ccharles) suggested a better way for installing pip software by targeting user level instead of using sudo.
172
173<div class="reddit-embed" data-embed-media="www.redditmedia.com" data-embed-parent="false" data-embed-live="false" data-embed-uuid="f4f0459e-684d-441e-bebe-eb49b2f0a31d" data-embed-created="2017-04-22T19:46:10.874Z"><a href="https://www.reddit.com/r/Python/comments/66v373/profiling_python_web_applications_with_visual/dglpzkx/">Comment</a> from discussion <a href="https://www.reddit.com/r/Python/comments/66v373/profiling_python_web_applications_with_visual/">Profiling Python web applications with visual tools</a>.</div><script async src="https://www.redditstatic.com/comment-embed.js"></script>
174
175```bash
176# now we need to add this path to our $PATH variable
177# we do this my adding this line at the end of your
178# ~/.bashrc file
179PATH=$PATH:$HOME/.local/bin/
180
181# in order to use this new configuration you can close
182# and reopen terminal or reload .bashrc file
183$ source ~/.bashrc
184
185# now let's test if new directory is present in $PATH
186$ echo $PATH
187
188# now we can install on user level by adding --user
189# without use of sudo
190$ pip install snakeviz --user
191```
192
193Or as suggested by [mvt](https://www.reddit.com/user/mvt) you can use [pipsi](https://github.com/mitsuhiko/pipsi).
diff --git a/content/2017-08-11-simple-iot.md b/content/2017-08-11-simple-iot.md
deleted file mode 100644
index 2eac869..0000000
--- a/content/2017-08-11-simple-iot.md
+++ /dev/null
@@ -1,500 +0,0 @@
1---
2layout: post
3title: Simple IOT application supported by real-time monitoring and data history
4description: Develop simple IOT application with Arduino MKR1000 and Python
5slug: simple-iot-application
6type: note
7date: 2017-08-11
8---
9
10**Table of contents**
11
121. [Initial thoughts](#initial-thoughts)
132. [Simple Python API](#simple-python-api)
14 1. [Basic web application](#basic-web-application)
15 2. [Web application security](#web-application-security)
16 3. [Simple API for writing data-points](#simple-api-for-writing-data-points)
173. [Sending data to API with Arduino MKR1000](#sending-data-to-api-with-arduino-mkr1000)
184. [Data visualization](#data-visualization)
195. [Conclusion](#conclusion)
20
21## Initial thoughts
22
23I have been developing these kind of application for the better part of my last 5 years and people keep asking me how to approach developing such application and I will give a try explaining it here.
24
25IOT applications are really no different than any other kind of applications. We have data that needs to be collected and visualized in some form of tables or charts. The main difference here is that most of the times these data is collected by some kind of device foreign to developer that mainly operates in web domain. But fear not, it's not that different than writing some JavaScript.
26
27There are many devices able to transmit data via wireless or wired network by default but for the sake of example we will be using commonly known Arduino with wireless module already on the board → [Arduino MKR1000](https://store.arduino.cc/arduino-mkr1000).
28
29In order to make this little project as accessible to others as possible I will try to make it as inexpensive as possible. And by this I mean that I will avoid using hosted virtual servers and will be using my own laptop as a server. But you must buy Arduino MKR1000 to follow steps below. But if you would want to deploy this software I would suggest using [DigitalOcean](https://www.digitalocean.com) → smallest VPS is only per month making this one of the most affordable option out there. Please notice that this software will not run on stock web hosting that only supports LAMP (Linux, Apache, MySQL, and PHP).
30
31_But before we begin please take notice that this is strictly experimental code and not well optimized and there are much better ways in handling some aspects of the application but that requires much deeper knowledge of technology that is not needed for an example like this._
32
33**Development steps**
34
351. Simple Python API that will receive and store incoming data.
362. Prototype C++ code that will read "sensor data" and transmit it to API.
373. Data visualization with charts → extends Python web application.
38
39Step 1. and 3. will share the same web application. One route will be dedicated to API and another to serving HTML with chart.
40
41Schema below represents what we will try to achieve and how different parts correlates to each other.
42
43![Overview](/files/simple-iot-application-overview.svg)
44
45## Simple Python API
46
47I have always been a fan of simplicity so we will be using [Bottle: Python Web Framework](https://bottlepy.org/docs/dev/). It is a single file web framework that seriously simplifies working with routes, templating and has built-in web server that satisfies our need in this case.
48
49First we need to install bottle package. This can be done by downloading ```bottle.py``` and placing it in the root of your application or by using pip software ```pip install bottle --user```.
50
51If you are using Linux or MacOS then Python is already installed. If you will try to test this on Windows please install [Python for Windows](https://www.python.org/downloads/windows/). There may be some problems with path when you will try to launch ```python webapp.py``` so please take care of this before you continue.
52
53### Basic web application
54
55Most basic bottle application is quite simple. Paste code below in ```webapp.py``` file and save.
56
57```python
58# -*- coding: utf-8 -*-
59
60import bottle
61
62# initializing bottle app
63app = bottle.Bottle()
64
65# triggered when / is accessed from browser
66# only accepts GET → no POST allowed
67@app.route("/", method=["GET"])
68def route_default():
69 return "howdy from python"
70
71# starting server on http://0.0.0.0:5000
72if __name__ == "__main__":
73 bottle.run(
74 app = app,
75 host = "0.0.0.0",
76 port = 5000,
77 debug = True,
78 reloader = True,
79 catchall = True,
80 )
81```
82
83To run this simple application you should open command prompt or terminal on your machine and go to the folder containing your file and type ```python webapp.py```. If everything goes ok then open your web browser and point it to ```http://0.0.0.0:5000```.
84
85If you would like change the port of your application (like port 80) and not use root to run your app this will present a problem. The TCP/IP port numbers below 1024 are privileged ports → this is a security feature. So in order of simplicity and security use a port number above 1024 like I have used port 5000.
86
87If this fails at any time please fix it before you continue, because nothing below will work otherwise.
88
89> We use 0.0.0.0 as default host so that this app is available over your local network. If you find your local ip ```ifconfig``` and try accessing this site with your phone (if on same network/router as your machine) this should work as well (example of such ip ```http://192.168.1.15:5000```). This is a must have because Arduino will be accessing this application to send it's data.
90
91### Web application security
92
93There is a lot to be said about security and is a topic of many books. Of course all this can not be written here but to just establish some basic security → you should always use SSL with your application. Some fantastic free certificates are available by [Let's Encrypt - Free SSL/TLS Certificates](https://letsencrypt.org). With SSL certificate installed you should then make use of HTTP headers and send your "API key" via a header. If your key is send via header then this key is encrypted by SSL and send encrypted over the network. Never send your api keys by GET parameter like ```http://example.com/?api_key=somekeyvalue```. The problem that this kind of sending presents is that this key is visible in logs and by network sniffers.
94
95There is a fantastic article describing some aspects about security: [11 Web Application Security Best Practices](https://www.keycdn.com/blog/web-application-security-best-practices/). Please check it out.
96
97### Simple API for writing data-points
98
99We will now be using boilerplate code from example above and extend it to be able to write data received by API to local storage. For example use I will use SQLite3 because it plays well with Python and can store quite large amount of data. I have been using it to collect gigabytes of data in a single database without any corruption or problems → your experience may vary.
100
101To avoid learning SQLite I will be using [Dataset: databases for lazy people](https://dataset.readthedocs.io/en/latest/index.html). This package abstracts SQL and simplifies writing and reading data from database. You should install this package with pip software ```pip install dataset --user```.
102
103Because API will use POST method I will be testing if code works correctly by using [Restlet Client for Google Chrome](https://chrome.google.com/webstore/detail/restlet-client-rest-api-t/aejoelaoggembcahagimdiliamlcdmfm). This software also allows you to set headers → for basic security with API_KEY.
104
105To quickly generate passwords or API keys I usually use this nifty website [RandomKeygen](https://randomkeygen.com/).
106
107Copy and paste code below over your previous code in file ```webapp.py```.
108
109```python
110# -*- coding: utf-8 -*-
111
112import time
113import bottle
114import random
115import dataset
116
117# initializing bottle app
118app = bottle.Bottle()
119
120# connects to sqlite database
121# check_same_thread=False allows using it in multi-threaded mode
122app.config["dsn"] = dataset.connect("sqlite:///data.db?check_same_thread=False")
123
124# api key that will be used in Arduino code
125app.config["api_key"] = "JtF2aUE5SGHfVJBCG5SH"
126
127# triggered when /api is accessed from browser
128# only accepts POST → no GET allowed
129@app.route("/api", method=["POST"])
130def route_default():
131 status = 400
132 ts = int(time.time()) # current timestamp
133 value = bottle.request.body.read() # data from device
134 api_key = bottle.request.get_header("Api_Key") # api key from header
135
136 # outputs to console received data for debug reason
137 print ">>> {} :: {}".format(value, api_key)
138
139 # if api_key is correct and value is present
140 # then writes attribute to point table
141 if api_key == app.config["api_key"] and value:
142 app.config["dsn"]["point"].insert(dict(ts=ts, value=value))
143 status = 200
144
145 # we only need to return status
146 return bottle.HTTPResponse(status=status, body="")
147
148# starting server on http://0.0.0.0:5000
149if __name__ == "__main__":
150 bottle.run(
151 app = app,
152 host = "0.0.0.0",
153 port = 5000,
154 debug = True,
155 reloader = True,
156 catchall = True,
157 )
158```
159
160To run this simply go to folder containing python file and run ```python webapp.py``` from terminal. If everything goes ok you should have simple API available via POST method on /api route.
161
162After testing the service with Restlet Client you should be able to view your data in a database file ```data.db```.
163
164![REST settings example](/files/iot-rest-example.png)
165
166You can also check the contents of new database file by using desktop client for SQLite → [DB Browser for SQLite](http://sqlitebrowser.org/).
167
168![SQLite database example](/files/iot-sqlite-db.png)
169
170Table structure is as simple as it can be. We have ts (timestamp) and value (value from Arduino). As you can see timestamp is generated on API side. If you would happen to have atomic clock on Arduino it would be then better to generate and send timestamp with the value. This would be particularity useful if we would be collecting sensor data at a higher frequency and then sending this data in bulk to API.
171
172> If you will deploy this app with uWSGI and multi-threaded, use DSN (Data Source Name) url with ```?check_same_thread=False```.
173
174Ok, now that we have some sort of a working API with some basic security so unwanted people can not post data to your database can we proceed further and try to program Arduino to send data to API.
175
176## Sending data to API with Arduino MKR1000
177
178First of all you should have MKR1000 module and microUSB cable to proceed. If you have ever done any work with Arduino you should know that you also need [Arduino IDE](https://www.arduino.cc/en/Main/Software). On provided link you should be able to download and install IDE. Once that task is completed and you have successfully run blink example you should proceed to the next step.
179
180In order to use wireless capabilities of MKR1000 you need to first install [WiFi101 library](https://www.arduino.cc/en/Reference/WiFi101) in Arduino IDE. Please check before you install, you may already have it installed.
181
182Code below is a working example that sends data to API. Before you try to test your code make sure you have run Python web application. Then change settings for wifi, api endpoint and api_key. If by some reason code bellow doesn't work for you please leave a comment and I'll try to help.
183
184Once you have opened IDE and copied this code try to compile and upload it. Then open "Serial monitor" to see if any output is presented by Arduino.
185
186```c
187#include <WiFi101.h>
188
189// wifi settings
190char ssid[] = "ssid-name";
191char pass[] = "ssid-password";
192
193// api server enpoint
194char server[] = "192.168.6.22";
195int port = 5000;
196
197// api key that must be the same as the one in Python code
198String api_key = "JtF2aUE5SGHfVJBCG5SH";
199
200// frequency data is sent in ms - every 5 seconds
201int timeout = 1000 * 5;
202
203int status = WL_IDLE_STATUS;
204
205void setup() {
206
207 // initialize serial and wait for port to open:
208 Serial.begin(9600);
209 delay(1000);
210
211 // check for the presence of the shield
212 if (WiFi.status() == WL_NO_SHIELD) {
213 Serial.println("WiFi shield not present");
214 while (true);
215 }
216
217 // attempt to connect to wifi network
218 while (status != WL_CONNECTED) {
219 Serial.print("Attempting to connect to SSID: ");
220 Serial.println(ssid);
221 status = WiFi.begin(ssid, pass);
222 // wait 10 seconds for connection
223 delay(10000);
224 }
225
226 // output wifi status to serial monitor
227 Serial.print("SSID: ");
228 Serial.println(WiFi.SSID());
229
230 IPAddress ip = WiFi.localIP();
231 Serial.print("IP Address: ");
232 Serial.println(ip);
233
234 long rssi = WiFi.RSSI();
235 Serial.print("signal strength (RSSI):");
236 Serial.print(rssi);
237 Serial.println(" dBm");
238}
239
240void loop() {
241
242 WiFiClient client;
243
244 if (client.connect(server, port)) {
245
246 // I use random number generator for this example
247 // but you can use analog or digital inputs from arduino
248 String content = String(random(1000));
249
250 client.println("POST /api HTTP/1.1");
251 client.println("Connection: close");
252 client.println("Api-Key: " + api_key);
253 client.println("Content-Length: " + String(content.length()));
254 client.println();
255 client.println(content);
256
257 delay(100);
258 client.stop();
259 Serial.println("Data sent successfully ...");
260
261 } else {
262 Serial.println("Problem sending data ...");
263 }
264
265 // waits for x seconds and continue looping
266 delay(timeout);
267
268}
269```
270
271As seen from example you can notice that Arduino is generating random integer between [ 0 .. 1000 ]. You can easily replace this with a temperature sensor or any other kind of sensor.
272
273Now that we have API under the hood and Arduino is sending demo data we can now focus on data visualization.
274
275## Data visualization
276
277Before we continue we should examine our project folder structure. Currently we only have two files in our project:
278
279_simple-iot-app/_
280
281* _webapp.py_
282* _data.db_
283
284We will now add HTML template that will contain CSS and JavaScript code inline for the simplicity reason. And for the bottle framework to be able to scan root application folder for templates we will add ```bottle.TEMPLATE_PATH.insert(0, "./")``` in ```webapp.py```. By default bottle framework uses ```views/``` subfolder to store templates. This is not the ideal situation and if you will use bottle to develop web applications you should use native behavior and store templates in it's predefined folder. But for the sake of example we will over-ride this. Be careful to fully replace your code with new code that is provided below. Avoid partially replacing code in file :) Also new code for reading data-points is provided in Python example below.
285
286First we add new route to our web application. It should be trigger when browser hits root of application ```http://0.0.0.0:5000/```. This route will do nothing more than render ```frontend.html``` template. This is done by ```return bottle.template("frontend.html")```. Check code below to further examine how exactly this is done.
287
288Now we will expand ```/api``` route and use different methods to write or read data-points. For writing data-point we will use POST method and for reading points we will use GET method. GET method will return JSON object with latest readings and historical data.
289
290There is a fantastic JavaScript library for plotting time-series charts called [MetricsGraphics.js](https://www.metricsgraphicsjs.org) that is based on [D3.js](https://d3js.org/) library for visualizing data.
291
292Data schema required by MetricsGraphics.js → to achieve this we need to transform data from database into this format:
293
294```json
295[
296 {
297 "date": "2017-08-11 01:07:20",
298 "value": 933
299 },
300 {
301 "date": "2017-08-11 01:07:30",
302 "value": 743
303 }
304]
305```
306
307Web application is now complete and we only need ```frontend.html``` that we will develop now. If you would try to start web app now and go to root app this will return error because we don't have frontend.html yet.
308
309```python
310# -*- coding: utf-8 -*-
311
312import time
313import bottle
314import json
315import datetime
316import random
317import dataset
318
319# initializing bottle app
320app = bottle.Bottle()
321
322# adds root directory as template folder
323bottle.TEMPLATE_PATH.insert(0, "./")
324
325# connects to sqlite database
326# check_same_thread=False allows using it in multi-threaded mode
327app.config["db"] = dataset.connect("sqlite:///data.db?check_same_thread=False")
328
329# api key that will be used in Arduino code
330app.config["api_key"] = "JtF2aUE5SGHfVJBCG5SH"
331
332# triggered when / is accessed from browser
333# only accepts GET → no POST allowed
334@app.route("/", method=["GET"])
335def route_default():
336 return bottle.template("frontend.html")
337
338# triggered when /api is accessed from browser
339# accepts POST and GET
340@app.route("/api", method=["GET", "POST"])
341def route_default():
342
343 # if method is POST then we write datapoint
344 if bottle.request.method == "POST":
345 status = 400
346 ts = int(time.time()) # current timestamp
347 value = bottle.request.body.read() # data from device
348 api_key = bottle.request.get_header("Api-Key") # api key from header
349
350 # outputs to console recieved data for debug reason
351 print ">>> {} :: {}".format(value, api_key)
352
353 # if api_key is correct and value is present
354 # then writes attribute to point table
355 if api_key == app.config["api_key"] and value:
356 app.config["db"]["point"].insert(dict(ts=ts, value=value))
357 status = 200
358
359 # we only need to return status
360 return bottle.HTTPResponse(status=status, body="")
361
362 # if method is GET then we read datapoint
363 else:
364 response = []
365 datapoints = app.config["db"]["point"].all()
366
367 for point in datapoints:
368 response.append({
369 "date": datetime.datetime.fromtimestamp(int(point["ts"])).strftime("%Y-%m-%d %H:%M:%S"),
370 "value": point["value"]
371 })
372
373 bottle.response.content_type = "application/json"
374 return json.dumps(response)
375
376# starting server on http://0.0.0.0:5000
377if __name__ == "__main__":
378 bottle.run(
379 app = app,
380 host = "0.0.0.0",
381 port = 5000,
382 debug = True,
383 reloader = True,
384 catchall = True,
385 )
386```
387
388And now finally we can implement ```frontend.html```. Create file with this name and copy code below. When you are done you can start web application. Steps for this part are listed below the code.
389
390```html
391<!DOCTYPE html>
392<html>
393
394 <head>
395 <meta charset="utf-8">
396 <title>Simple IOT application</title>
397 </head>
398
399 <body>
400
401 <h1>Simple IOT application</h1>
402
403 <div class="chart-placeholder">
404 <div id="chart"></div>
405 </div>
406
407 <!-- application main script -->
408 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
409 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
410 <script src="https://cdnjs.cloudflare.com/ajax/libs/metrics-graphics/2.11.0/metricsgraphics.min.js"></script>
411 <script>
412 function fetch_and_render() {
413 d3.json("/api", function(data) {
414 data = MG.convert.date(data, "date", "%Y-%m-%d %H:%M:%S");
415 MG.data_graphic({
416 data: data,
417 chart_type: "line",
418 full_width: true,
419 height: 270,
420 target: document.getElementById("chart"),
421 x_accessor: "date",
422 y_accessor: "value"
423 });
424 });
425 }
426 window.onload = function() {
427 // initial call for rendering
428 fetch_and_render();
429
430 // updates chart every 5 seconds
431 setInterval(function() {
432 fetch_and_render();
433 }, 5000);
434 }
435 </script>
436
437 <!-- application styles -->
438 <style>
439 body {
440 font: 13px sans-serif;
441 padding: 20px 50px;
442 }
443 .chart-placeholder {
444 border: 2px solid #ccc;
445 width: 100%;
446 user-select: none;
447 }
448 /* chart styles */
449 .mg-line1-color {
450 stroke: red;
451 stroke-width: 2;
452 }
453 .mg-main-area, .mg-main-line {
454 fill: #fff;
455 }
456 .mg-x-axis line, .mg-y-axis line {
457 stroke: #b3b2b2;
458 stroke-width: 1px;
459 }
460 </style>
461
462 </body>
463
464</html>
465```
466
467Now the folder structure should look like:
468
469_simple-iot-app/_
470
471* _webapp.py_
472* _data.db_
473* _frontend.html_
474
475Ok, lets now start application and start feeding it data.
476
4771. ```python webapp.py```
4782. connect Arduino MKR1000 to power source
4793. open browser and go to ```http://0.0.0.0:5000```
480
481If everything goes well you should be seeing new data-points rendered on chart every 5 seconds.
482
483If you navigate to ```http://0.0.0.0:5000``` you should see rendered chart as shown on picture below.
484
485![Application output](/files/iot-app-output.png)
486
487Complete application with all the code is available for [download](/files/simple-iot-application.zip).
488
489## Conclusion
490
491I hope this clarifies some aspects of IOT application development. Of course this is a minimal example and is far from what can be done in real life with some further dive into other technologies.
492
493If you would like to continue exploring IOT world here are some interesting resources for you to examine:
494
495* [Reading Sensors with an Arduino](https://www.allaboutcircuits.com/projects/reading-sensors-with-an-arduino/)
496* [MQTT 101 – How to Get Started with the lightweight IoT Protocol](http://www.hivemq.com/blog/how-to-get-started-with-mqtt)
497* [Stream Updates with Server-Sent Events](https://www.html5rocks.com/en/tutorials/eventsource/basics/)
498* [Internet of Things (IoT) Tutorials](http://www.tutorialspoint.com/internet_of_things/)
499
500Any comment or additional ideas are welcomed in comments below.)
diff --git a/content/2018-01-16-using-digitalocean-spaces-object-storage-with-fuse.md b/content/2018-01-16-using-digitalocean-spaces-object-storage-with-fuse.md
deleted file mode 100644
index f1c893a..0000000
--- a/content/2018-01-16-using-digitalocean-spaces-object-storage-with-fuse.md
+++ /dev/null
@@ -1,272 +0,0 @@
1---
2layout: post
3title: Using DigitalOcean Spaces Object Storage with FUSE
4description: Using DigitalOcean Spaces Object Storage with FUSE
5slug: using-digitalocean-spaces-object-storage-with-fuse
6type: research
7date: 2018-01-16
8---
9
10**Table of contents**
11
121. [Is it possible to use them as a mounted drive with FUSE?](#is-it-possible-to-use-them-as-a-mounted-drive-with-fuse)
132. [Will the performance degrade over time and over different sizes of objects?](#will-the-performance-degrade-over-time-and-over-different-sizes-of-objects)
14 1. [Measurement experiment 1: File copy](#measurement-experiment-1-file-copy)
15 2. [Measurement experiment 2: SQLite performanse](#measurement-experiment-2-sqlite-performanse)
163. [Can storage be mounted on multiple machines at the same time and be writable?](#can-storage-be-mounted-on-multiple-machines-at-the-same-time-and-be-writable)
174. [Observations and conslusion](#observations-and-conslusion)
18
19Couple of months ago [DigitalOcean](https://www.digitalocean.com) introduced new product called [Spaces](https://blog.digitalocean.com/introducing-spaces-object-storage/) which is Object Storage very similar to Amazon's S3. This really peaked my interest, because this was something I was missing and even the thought of going over the internet for such functionality was in no interest to me. Also in fashion with their previous pricing this also is very cheap and pricing page is a no-brainer compared to AWS or GCE. [Prices are clearly and precisely defined and outlined](https://www.digitalocean.com/pricing/). You must love them for that :)
20
21### Initial requirements
22
23* Is it possible to use them as a mounted drive with FUSE? (tl;dr YES)
24* Will the performance degrade over time and over different sizes of objects? (tl;dr NO&YES)
25* Can storage be mounted on multiple machines at the same time and be writable? (tl;dr YES)
26
27> Let me be clear. This scripts I use are made just for benchmarking and are not intended to be used in real-life situations. Besides that, I am looking into using this approaches but adding caching service in front of it and then dumping everything as an object to storage. This could potentially be some interesting post of itself. But in case you would need real-time data without eventual consistency please take this scripts as they are: not usable in such situations.
28
29## Is it possible to use them as a mounted drive with FUSE?
30
31Well, actually they can be used in such manor. Because they are similar to [AWS S3](https://aws.amazon.com/s3/) many tools are available and you can find many articles and [Stackoverflow items](https://stackoverflow.com/search?q=s3+fuse).
32
33To make this work you will need DigitalOcean account. If you don't have one you will not be able to test this code. But if you have an account then you go and [create new Droplet](https://cloud.digitalocean.com/droplets/new?size=s-1vcpu-1gb&region=ams3&distro=debian&distroImage=debian-9-x64&options=private_networking,install_agent). If you click on this link you will already have preselected Debian 9 with smallest VM option.
34
35* Please be sure to add you SSH key, because we will login to this machine remotely.
36* If you change your region please remember which one you choose because we will need this information when we try to mount space to our machine.
37
38Instuctions on how to use SSH keys and how to setup them are available in article [How To Use SSH Keys with DigitalOcean Droplets](https://www.digitalocean.com/community/tutorials/how-to-use-ssh-keys-with-digitalocean-droplets).
39
40![DigitalOcean Droplets](/files/fuse-droplets.png)
41
42After we created Droplet it's time to create new Space. This is done by clicking on a button [Create](https://cloud.digitalocean.com/spaces/new) (right top corner) and selecting Spaces. Choose pronounceable ```Unique name``` because we will use it in examples below. You can either choose Private or Public, it doesn't matter in our case. And you can always change that in the future.
43
44When you have created new Space we should [generate Access key](https://cloud.digitalocean.com/settings/api/tokens). This link will guide to the page when you can generate this key. After you create new one, please save provided Key and Secret because Secret will not be shown again.
45
46![DigitalOcean Spaces](/files/fuse-spaces.png)
47
48Now that we have new Space and Access key we should SSH into our machine.
49
50```bash
51# replace IP with the ip of your newly created droplet
52ssh root@IP
53
54# this will install utilities for mounting storage objects as FUSE
55apt install s3fs
56
57# we now need to provide credentials (access key we created earlier)
58# replace KEY and SECRET with your own credentials but leave the colon between them
59# we also need to set proper permissions
60echo "KEY:SECRET" > .passwd-s3fs
61chmod 600 .passwd-s3fs
62
63# now we mount space to our machine
64# replace UNIQUE-NAME with the name you choose earlier
65# if you choose different region for your space be careful about -ourl option (ams3)
66s3fs UNIQUE-NAME /mnt/ -ourl=https://ams3.digitaloceanspaces.com -ouse_cache=/tmp
67
68# now we try to create a file
69# once you mount it may take a couple of seconds to retrieve data
70echo "Hello cruel world" > /mnt/hello.txt
71```
72
73After all this you can return to your browser and go to [DigitalOcean Spaces](https://cloud.digitalocean.com/spaces) and click on your created space. If file hello.txt is present you have successfully mounted space to your machine and wrote data to it.
74
75I choose the same region for my Droplet and my Space but you don't have to. You can have different regions. What this actually does to performance I don't know.
76
77Additional information on FUSE:
78
79* [Github project page for s3fs](https://github.com/s3fs-fuse/s3fs-fuse)
80* [FUSE - Filesystem in Userspace](https://en.wikipedia.org/wiki/Filesystem_in_Userspace)
81
82## Will the performance degrade over time and over different sizes of objects?
83
84For this task I didn't want to just read and write text files or uploading images. I actually wanted to figure out if using something like SQlite is viable in this case.
85
86### Measurement experiment 1: File copy
87
88```bash
89# first we create some dummy files at different sizes
90dd if=/dev/zero of=10KB.dat bs=1024 count=10 #10KB
91dd if=/dev/zero of=100KB.dat bs=1024 count=100 #100KB
92dd if=/dev/zero of=1MB.dat bs=1024 count=1024 #1MB
93dd if=/dev/zero of=10MB.dat bs=1024 count=10240 #10MB
94
95# now we set time command to only return real
96TIMEFORMAT=%R
97
98# now lets test it
99(time cp 10KB.dat /mnt/) |& tee -a 10KB.results.txt
100
101# and now we automate
102# this will perform the same operation 100 times
103# this will output results into separated files based on objecty size
104n=0; while (( n++ < 100 )); do (time cp 10KB.dat /mnt/10KB.$n.dat) |& tee -a 10KB.results.txt; done
105n=0; while (( n++ < 100 )); do (time cp 100KB.dat /mnt/100KB.$n.dat) |& tee -a 100KB.results.txt; done
106n=0; while (( n++ < 100 )); do (time cp 1MB.dat /mnt/1MB.$n.dat) |& tee -a 1MB.results.txt; done
107n=0; while (( n++ < 100 )); do (time cp 10MB.dat /mnt/10MB.$n.dat) |& tee -a 10MB.results.txt; done
108```
109
110Files of size 100MB were not successfully transferred and ended up displaying error (cp: failed to close '/mnt/100MB.1.dat': Operation not permitted).
111
112As I suspected, object size is not really that important. Sadly I don't have the time to test performance over periods of time. But if some of you would do it please send me your data. I would be interested in seeing results.
113
114**Here are plotted results**
115
116You can download [raw result here](/files/copy-benchmarks.tsv). Measurements are in seconds.
117
118<script src="//cdn.plot.ly/plotly-latest.min.js"></script>
119<div id="copy-benchmarks"></div>
120<script>
121(function(){
122 var request = new XMLHttpRequest();
123 request.open("GET", "/files/copy-benchmarks.tsv", true);
124 request.onload = function() {
125 if (request.status >= 200 && request.status < 400) {
126 var payload = request.responseText.trim();
127 var tsv = payload.split("\n");
128 for (var i=0; i<tsv.length; i++) { tsv[i] = tsv[i].split("\t"); }
129 var traces = [];
130 var headers = tsv[0];
131 tsv.shift();
132 Array.prototype.forEach.call(headers, function(el, idx) {
133 var x = [];
134 var y = [];
135 for (var j=0; j<tsv.length; j++) {
136 x.push(j);
137 y.push(parseFloat(tsv[j][idx].replace(",", ".")));
138 }
139 traces.push({ x: x, y: y, type: "scatter", name: el, line: { width: 1, shape: "spline" } });
140 });
141 var copy = Plotly.newPlot("copy-benchmarks", traces, { legend: {"orientation": "h"}, height: 400, margin: { l: 40, r: 0, b: 20, t: 30, pad: 0 }, yaxis: { title: "execution time in seconds", titlefont: { size: 12 } }, xaxis: { title: "fn(i)", titlefont: { size: 12 } } });
142 } else { }
143 };
144 request.onerror = function() { };
145 request.send(null);
146})();
147</script>
148
149As far as these tests show, performance is quite stable and can be predicted which is fantastic. But this is a small test and spans only over couple of hours. So you should not completely trust them.
150
151### Measurement experiment 2: SQLite performanse
152
153I was unable to use database file directly from mounted drive so this is a no-go as I suspected. So I executed code below on a local disk just to get some benchmarks. I inserted 1000 records with DROPTABLE, CREATETABLE, INSERTMANY, FETCHALL, COMMIT for 1000 times to generate statistics. As you can see performance of SQLite is quite amazing. You could then potentially just copy file to mounted drive and be done with it.
154
155```python
156import time
157import sqlite3
158import sys
159
160if len(sys.argv) < 3:
161 print("usage: python sqlite-benchmark.py DB_PATH NUM_RECORDS REPEAT")
162 exit()
163
164def data_iter(x):
165 for i in range(x):
166 yield "m" + str(i), "f" + str(i*i)
167
168header_line = "%s\t%s\t%s\t%s\t%s\n" % ("DROPTABLE", "CREATETABLE", "INSERTMANY", "FETCHALL", "COMMIT")
169with open("sqlite-benchmarks.tsv", "w") as fp:
170 fp.write(header_line)
171
172start_time = time.time()
173conn = sqlite3.connect(sys.argv[1])
174c = conn.cursor()
175end_time = time.time()
176result_time = CONNECT = end_time - start_time
177print("CONNECT: %g seconds" % (result_time))
178
179start_time = time.time()
180c.execute("PRAGMA journal_mode=WAL")
181c.execute("PRAGMA temp_store=MEMORY")
182c.execute("PRAGMA synchronous=OFF")
183result_time = PRAGMA = end_time - start_time
184print("PRAGMA: %g seconds" % (result_time))
185
186for i in range(int(sys.argv[3])):
187 print("#%i" % (i))
188
189 start_time = time.time()
190 c.execute("drop table if exists test")
191 end_time = time.time()
192 result_time = DROPTABLE = end_time - start_time
193 print("DROPTABLE: %g seconds" % (result_time))
194
195 start_time = time.time()
196 c.execute("create table if not exists test(a,b)")
197 end_time = time.time()
198 result_time = CREATETABLE = end_time - start_time
199 print("CREATETABLE: %g seconds" % (result_time))
200
201 start_time = time.time()
202 c.executemany("INSERT INTO test VALUES (?, ?)", data_iter(int(sys.argv[2])))
203 end_time = time.time()
204 result_time = INSERTMANY = end_time - start_time
205 print("INSERTMANY: %g seconds" % (result_time))
206
207 start_time = time.time()
208 c.execute("select count(*) from test")
209 res = c.fetchall()
210 end_time = time.time()
211 result_time = FETCHALL = end_time - start_time
212 print("FETCHALL: %g seconds" % (result_time))
213
214 start_time = time.time()
215 conn.commit()
216 end_time = time.time()
217 result_time = COMMIT = end_time - start_time
218 print("COMMIT: %g seconds" % (result_time))
219
220 print
221 log_line = "%f\t%f\t%f\t%f\t%f\n" % (DROPTABLE, CREATETABLE, INSERTMANY, FETCHALL, COMMIT)
222 with open("sqlite-benchmarks.tsv", "a") as fp:
223 fp.write(log_line)
224
225start_time = time.time()
226conn.close()
227end_time = time.time()
228result_time = CLOSE = end_time - start_time
229print("CLOSE: %g seconds" % (result_time))
230```
231
232You can download [raw result here](/files/sqlite-benchmarks.tsv). And again, these results are done on a local block storage and do not represent capabilities of object storage. With my current approach and state of the test code these can not be done. I would need to make Python code much more robust and check locking etc.
233
234<div id="sqlite-benchmarks"></div>
235<script>
236(function(){
237 var request = new XMLHttpRequest();
238 request.open("GET", "/files/sqlite-benchmarks.tsv", true);
239 request.onload = function() {
240 if (request.status >= 200 && request.status < 400) {
241 var payload = request.responseText.trim();
242 var tsv = payload.split("\n");
243 for (var i=0; i<tsv.length; i++) { tsv[i] = tsv[i].split("\t"); }
244 var traces = [];
245 var headers = tsv[0];
246 tsv.shift();
247 Array.prototype.forEach.call(headers, function(el, idx) {
248 var x = [];
249 var y = [];
250 for (var j=0; j<tsv.length; j++) {
251 x.push(j);
252 y.push(parseFloat(tsv[j][idx].replace(",", ".")));
253 }
254 traces.push({ x: x, y: y, type: "scatter", name: el, line: { width: 1, shape: "spline" } });
255 });
256 var sqlite = Plotly.newPlot("sqlite-benchmarks", traces, { legend: {"orientation": "h"}, height: 400, margin: { l: 50, r: 0, b: 20, t: 30, pad: 0 }, yaxis: { title: "execution time in seconds", titlefont: { size: 12 } } });
257 } else { }
258 };
259 request.onerror = function() { };
260 request.send(null);
261})();
262</script>
263
264## Can storage be mounted on multiple machines at the same time and be writable?
265
266Well, this one didn't take long to test. And the answer is **YES**. I mounted space on both machines and measured same performance on both machines. But because file is downloaded before write and then uploaded on complete there could potentially be problems is another process is trying to access the same file.
267
268## Observations and conslusion
269
270Using Spaces in this way makes it easier to access and manage files. But besides that you would need to write additional code to make this one play nice with you applications.
271
272Nevertheless, this was extremely simple to setup and use and this is just another excellent product in DigitalOcean product line. I found this exercise very valuable and am thinking about implementing some sort of mechanism for SQLite, so data can be stored on Spaces and accessed by many VM's. For a project where data doesn't need to be accessible in real-time and can have couple of minutes old data this would be very interesting. If any of you find this proposal interesting please write in a comment box below or shoot me an email and I will keep you posted.
diff --git a/content/2018-08-05-the-bullshit-web-developments-pov.md b/content/2018-08-05-the-bullshit-web-developments-pov.md
deleted file mode 100644
index 04094c2..0000000
--- a/content/2018-08-05-the-bullshit-web-developments-pov.md
+++ /dev/null
@@ -1,94 +0,0 @@
1---
2layout: post
3title: The Bullshit Web - Development's Point of View
4description: State of front-end development and what this does to the future of web
5slug: the-bullshit-web-developments-pov
6type: note
7date: 2018-08-05
8---
9
10**Table of contents**
11
121. [Initial thoughts](#initial-thoughts)
132. [Front-end frameworks](#front-end-frameworks)
143. [Obsolescence to the rescue](#obsolescence-to-the-rescue)
154. [Unnecessary complexity](#unnecessary-complexity)
165. [Speed of development trumps code quality](#speed-of-development-trumps-code-quality)
176. [Load times of most popular websites](#load-times-of-most-popular-websites)
18
19## Initial thoughts
20
21I have recently read an amazing essay by Nick Heer on the web called [The Bullshit Web](https://pxlnv.com/blog/bullshit-web/) and it got me thinking about the future of the web as it is today.
22
23> The average internet connection in the United States is about six times as fast as it was just ten years ago, but instead of making it faster to browse the same types of websites, we’re simply occupying that extra bandwidth with more stuff.
24>
25> **-- Nick Heer**
26
27I really try to stray away from frond-end development as much as possible. The reason is nowhere close to me having any bad opinions but having to work with clients on visual stuff drains me to the point of sheer horror.
28
29I have observed silently the progress that was made in this field because I thought things will get better with time. I was so wrong. So wrong. Not only that things got extremely complicated to work with, the whole stack became so massive even simple pages have insanely large footprint.
30
31The Bullshit Web essay concentrates mostly on page sizes and AMP but I would like to address tooling and technologies for development in this post.
32
33Currently we have two types of websites:
34
35- informational websites,
36- web applications.
37
38The problem that occurs is that more and more websites are treathed as web application where simple web page would suffice. And this in my opinion adds insult to the injury.
39
40We talk about progressive web applications, AMP, and other technologies that are solving the problems of bandwidth, usability and in general making web faster but in reality this rarely gets applied in real life scenarios. Most of the time this are just demos on conferences.
41
42## Front-end frameworks
43
44I am not of those purists that denies usage of JavaScript frameworks or SASS but there are limits to where this obsession should go. In order to use these technologies properly one should ask himself where exactly they are needed and not use them like hammer for nails.
45
46Whenever I need to do front-end UI I usually check specification before embarking on journey of coding. And most of the times I really don't need frameworks. Most of the code I need to write in JavaScript is done in couple of hundred lines of code and does exactly what specification requires. And developer that will be working on this code after me doesn't need to learn new framework, tooling, etc. Just pure vanilla JavaScript. In all of my years as a developer I can count on fingers on my one hand when I used some sort of a framework. And even in this exceptions we later rewrote code to vanilla JavaScript because maintaining complex code was just to time consuming.
47
48There is an argument to be made for using frameworks in cases where multiple people are working a project and code must be easily transferable and on-boarding process must be swift. But in reality this is just another bullshit excuse to stick with what is "cool". I stand by Function over Form. And this also conflicts with the notion that frameworks never change. Frameworks evolve and adapt to market needs and most of the times get massive and hard to maintain. And we get stuck with massive codebase that is developed with many hacks and workarounds, because framework didn't support some feature at the time of development. I personally hate workarounds and being a smart-ass that intentionally makes code harder to read. I find frameworks similar to the story about Cain and Abel. Either you get murdered or framework gets. Most of the times framework dies and leaves legacy nobody would want.
49
50Huge strives have been made to address this problem and many fantastic frameworks emerged and some of theme are absolutely amazing. But there needs to be a strong case for using them in a project. We should never blindly use them regardless of the problem we are trying to solve.
51
52I must admit that tooling around front-end is getting better and better and we are slowly getting there but there still is a long road ahead.
53
54## Obsolescence to the rescue
55
56We can all agree that frameworks or libraries usually are there to fill the gap what currently is widely supported by the standard. Most of this so called frameworks are just libraries that unifies browser compatibility. The prime example of this is jQuery. There was a time almost everybody was using jQuery. But through time HTML5 specs were updated to include ideas from jQuery and this filled the browser compatibility gap. There is this awesome article [The Rise and Fall of jQuery](https://www.evolutionjobs.com/uk/media/the-rise-and-fall-of-jquery-117981/).
57
58Don't get me wrong. Yes, I dislike jQuery but I find it indispensable and without it our web would be very different. For the worst in my opinion. It was a huge stepping stone for front-end development. But there comes a time where technologies get obsolete and standards catch up with the requirements of the field.
59
60And because libraries and frameworks have short lifespan I try to stay away from them and if possible use vanilla code. There is a wonderfull article about [The Brutal Lifecycle of JavaScript Frameworks](https://stackoverflow.blog/2018/01/11/brutal-lifecycle-javascript-frameworks/) that explains how quick they popup and become obsolete.
61
62> JavaScript UI frameworks and libraries work in cycles. Every six months or so, a new one pops up, claiming that it has revolutionized UI development. Thousands of developers adopt it into their new projects, blog posts are written, Stack Overflow questions are asked and answered, and then a newer (and even more revolutionary) framework pops up to usurp the throne.
63>
64> **-- Ian Allen**
65
66## Unnecessary complexity
67
68Libraries have a tendency to speed up development which is ok but there are a huge drawbacks in the future. Most of the times we work on simple projects. Not everybody is working on Facebook, Google or that kind of mamuth apps and by using libraries provided to us by these companies we introduce complexity these companies need in order to make their apps. And usually these libraries include edge case functionalities that only apply to them and by providing simpler way to use libraries very complex approaches get implemented.
69
70Another reason for me to not use frameworks and libraries is that there usually is a team behind a project and by working on a feature by your own it takes too much time to read through the documentation and properly understand what the reasoning was behind a feature in a library. Most of the stuff (dashboarding, tables, widgets) that I work on are done much faster by pure using JS. Codebase footprint is smaller and doesn't require other developers to learn a completly new framework.
71
72This freameworks are heavily opinionated. No question about it. And by using them you accept their dogma. And by doing so you put yourself in a wierd position when new "disruptive" framework comes to life. If we think about it these frameworks should rather be called "approaches".
73
74> *Just to be completely honest*
75>
76> There are use-cases for such frameworks. And there are situations where they are indispensable. I am not saying that they don't make sense. All I am saying that in my line of work I noticed that not every project is fit for a framework and it's better to not use them in such cases.
77
78An awesome talk about [Learning from JavaScript Libraries by Trevor Landau](https://www.youtube.com/watch?v=u2PgPWj8KrM).
79
80## Speed of development trumps code quality
81
82I have found out that most of these frameworks or libraries have become very difficult to undestand in a matter of hours. In the past this was diifferent somehow. You could learn jQuery in a matter of hours and use it the next day like you were a pro. I know that it's not fair to compare framework and library but for our case this is acceptable.
83
84Every developer should have the knowledge and experience when selecting or not selection framework. I always stay true to [Occam's razor](https://en.wikipedia.org/wiki/Occam%27s_razor). And when prototyping I always use as barebone setup as I can. I see no problem with completly dumping a block of code and replacing it with something more complex if this makes sense. But there needs to be a huge reason behind this decision.
85
86Workarounds are one of the nessesary evils perticulary when dealing with frameworks. Either because the lack of time of just plain reason that framework doesn't support something. And this is the my main problem with them. In real life we don't have the time to properly implement ideas behind a framework. And when shit hits the fan we butcher up the code and mix different ideas just to catch a deadline. And this is in contadiction with the whole idea of using a framework.
87
88The impact that this has on quality and readability of code is massive. And threating this just as a symptom is probably the worst thing you can do. Through time these hacked-up code becomes legacy and additional code is molded to the code that already is in the codebase. And by doing this our code becomes more and more foregin of the initial concept.
89
90Code quality and readability should come first regardless of frameworks and libraries. Code should be as close to bare-metal as possible so when frameworks change our code is still usable and can be refreshed by any developer with the basic knowledge of desired programming language.
91
92## Load times of most popular websites
93
94All this directly impacts performanse. Terabytes of bandwidth wasted because there was a decision made early in the development cycle. Laggy performance, slow loading, bad experience just because development team was not cautious enough.
diff --git a/content/2019-01-03-encoding-binary-data-into-dna-sequence.md b/content/2019-01-03-encoding-binary-data-into-dna-sequence.md
deleted file mode 100644
index d3c1396..0000000
--- a/content/2019-01-03-encoding-binary-data-into-dna-sequence.md
+++ /dev/null
@@ -1,416 +0,0 @@
1---
2layout: post
3title: Encoding binary data into DNA sequence
4description: Imagine a world where you could go outside and take a leaf from a tree and put it through your personal DNA sequencer and get data like music, videos or computer programs from it.
5slug: encoding-binary-data-into-dna-sequence
6type: research
7date: 2019-01-03
8---
9
10**Table of contents**
11
121. [Initial thoughts](#initial-thoughts)
132. [Glossary](#glossary)
143. [Data encoding](#data-encoding)
154. [Quick history of DNA](#quick-history-of-dna)
165. [What is DNA?](#what-is-dna)
176. [Encode binary data into DNA sequence](#encode-binary-data-into-dna-sequence)
18 1. [Basic Encoding](#basic-encoding)
19 2. [FASTA file format](#fasta-file-format)
20 3. [PNG encoded DNA sequence](#png-encoded-dna-sequence)
217. [Encoding text file in practice](#encoding-text-file-in-practice)
228. [Toolkit for encoding data](#toolkit-for-encoding-data)
23 1. [dnae-encode](#dnae-encode)
24 2. [dnae-png](#dnae-png)
259. [Benchmarks](#benchmarks)
2610. [References](#references)
27
28## Initial thoughts
29
30Imagine a world where you could go outside and take a leaf from a tree and put it through your personal DNA sequencer and get data like music, videos or computer programs from it. Well, this is all possible now. It was not done on a large scale because it is quite expensive to create DNA strands but it's possible.
31
32Encoding data into DNA sequence is relatively simple process once you understand the relationship between binary data and nucleotides and scientists have been making large leaps in this field in order to provide viable long-term storage solution for our data that would potentially survive our specie if case of global disaster. We could imprint all the world's knowledge into plants and ensure the survival of our knowledge.
33
34More optimistic usage for this technology would be easier storage of ever growing data we produce every day. Once machines for sequencing DNA become fast enough and cheaper this could mean the next evolution of storing data and abandoning classical hard and solid state drives in data warehouses.
35
36As we currently stand this is still not viable but it is quite an amazing and cool technology.
37
38My interests in this field are purely in encoding processes and experimental testing mainly because I don't have the access to this expensive machines. My initial goal was to create a toolkit that can be used by everybody to encode their data into a proper DNA sequence.
39
40## Glossary
41
42**deoxyribose**
43: A five-carbon sugar molecule with a hydrogen atom rather than a hydroxyl group in the 2′ position; the sugar component of DNA nucleotides.
44
45**double helix**
46: The molecular shape of DNA in which two strands of nucleotides wind around each other in a spiral shape.
47
48**nitrogenous base**
49: A nitrogen-containing molecule that acts as a base; often referring to one of the purine or pyrimidine components of nucleic acids.
50
51**phosphate group**
52: A molecular group consisting of a central phosphorus atom bound to four oxygen atoms.
53
54**RGB**
55: The RGB color model is an additive color model in which red, green and blue light are added together in various ways to reproduce a broad array of colors.
56
57**GCC**
58: The GNU Compiler Collection is a compiler system produced by the GNU Project supporting various programming languages.
59
60## Data encoding
61
62**TL;DR:** Encoding involves the use of a code to change original data into a form that can be used by an external process [^1].
63
64Encoding is the process of converting data into a format required for a number of information processing needs, including:
65
66- Program compiling and execution
67- Data transmission, storage and compression/decompression
68- Application data processing, such as file conversion
69
70Encoding can have two meanings[^1]:
71
72- In computer technology, encoding is the process of applying a specific code, such as letters, symbols and numbers, to data for conversion into an equivalent cipher.
73- In electronics, encoding refers to analog to digital conversion.
74
75## Quick history of DNA
76
77- **1869** - Friedrich Miescher identifies "nuclein".
78- **1900s** - The Eugenics Movement.
79- **1900** – Mendel's theories are rediscovered by researchers.
80- **1944** - Oswald Avery identifies DNA as the 'transforming principle'.
81- **1952** - Rosalind Franklin photographs crystallized DNA fibres.
82- **1953** - James Watson and Francis Crick discover the double helix structure of DNA.
83- **1965** - Marshall Nirenberg is the first person to sequence the bases in each codon.
84- **1983** - Huntington's disease is the first mapped genetic disease.
85- **1990** - The Human Genome Project begins.
86- **1995** - Haemophilus Influenzae is the first bacterium genome sequenced.
87- **1996** - Dolly the sheep is cloned.
88- **1999** - First human chromosome is decoded.
89- **2000** – Genetic code of the fruit fly is decoded.
90- **2002** – Mouse is the first mammal to have its genome decoded.
91- **2003** – The Human Genome Project is completed.
92- **2013** – DNA Worldwide and Eurofins Forensic discover identical twins have differences in their genetic makeup [^2].
93
94## What is DNA?
95
96Deoxyribonucleic acid, a self-replicating material which is **present in nearly all living organisms** as the main constituent of chromosomes. It is the **carrier of genetic information**.
97
98> The nitrogen in our DNA, the calcium in our teeth, the iron in our blood, the carbon in our apple pies were made in the interiors of collapsing stars. We are made of starstuff.
99>
100> **-- Carl Sagan, Cosmos**
101
102The nucleotide in DNA consists of a sugar (deoxyribose), one of four bases (cytosine (C), thymine (T), adenine (A), guanine (G)), and a phosphate. Cytosine and thymine are pyrimidine bases, while adenine and guanine are purine bases. The sugar and the base together are called a nucleoside.
103
104![DNA](/files/dna-sequence/dna-basics.jpg#center)
105
106*DNA (a) forms a double stranded helix, and (b) adenine pairs with thymine and cytosine pairs with guanine. (credit a: modification of work by Jerome Walker, Dennis Myts) [^3]*
107
108## Encode binary data into DNA sequence
109
110As an input file you can use any file you want:
111- ASCII files,
112- Compiled programs,
113- Multimedia files (MP3, MP4, MVK, etc),
114- Images,
115- Database files,
116- etc.
117
118Note: If you would copy all the bytes from RAM to file or pipe data to file you could encode also this data as long as you provide file pointer to the encoder.
119
120### Basic Encoding
121
122As already mentioned, the Basic Encoding is based on a simple mapping. Since DNA is composed of 4 nucleotides (Adenine, Cytosine, Guanine, Thymine; usually referred using the first letter). Using this technique we can encode
123
124$$ log_2(4) = log_2(2^2) = 2 bits $$
125
126using a single nucleotide. In this way, we are able to use the 4 bases that compose the DNA strand to encode each byte of data.
127
128| Two bits | Nucleotides |
129| -------- | ---------------- |
130| 00 | **A** (Adenine) |
131| 10 | **G** (Guanine) |
132| 01 | **C** (Cytosine) |
133| 11 | **T** (Thymine) |
134
135With this in mind we can simply encode any data by using two-bit to Nucleotides conversion
136
137```pascal
138{ Algorithm 1: Naive byte array to DNA encode }
139procedure EncodeToDNASequence(f) string
140begin
141 enc string
142 while not eof(f) do
143 c byte := buffer[0] { Read 1 byte from buffer }
144 bin integer := sprintf('08b', c) { Convert to string binary }
145 for e in range[0, 2, 4, 6] do
146 if e[0] == 48 and e[1] == 48 then { 0x00 - A (Adenine) }
147 enc += 'A'
148 else if e[0] == 48 and e[1] == 49 then { 0x01 - G (Guanine) }
149 enc += 'G'
150 else if e[0] == 49 and e[1] == 48 then { 0x10 - C (Cytosine) }
151 enc += 'C'
152 else if e[0] == 49 and e[1] == 49 then { 0x11 - T (Thymine) }
153 enc += 'T'
154 return enc { Return DNA sequence }
155end
156```
157
158Another encoding would be **Goldman encoding**. Using this encoding helps with Nonsense mutation (amino acids replaced by a stop codon) that occurs and is the most problematic during translation because it leads to truncated amino acid sequences, which in turn results in truncated proteins. [^4]
159
160[Where to store big data? In DNA: Nick Goldman at TEDxPrague](https://www.youtube.com/watch?v=a4PiGWNsIEU)
161
162### FASTA file format
163
164In bioinformatics, FASTA format is a text-based format for representing either nucleotide sequences or peptide sequences, in which nucleotides or amino acids are represented using single-letter codes. The format also allows for sequence names and comments to precede the sequences. The format originates from the FASTA software package, but has now become a standard in the field of bioinformatics. [^5]
165
166The first line in a FASTA file started either with a ">" (greater-than) symbol or, less frequently, a ";" (semicolon) was taken as a comment. Subsequent lines starting with a semicolon would be ignored by software. Since the only comment used was the first, it quickly became used to hold a summary description of the sequence, often starting with a unique library accession number, and with time it has become commonplace to always use ">" for the first line and to not use ";" comments (which would otherwise be ignored).
167
168```text
169;LCBO - Prolactin precursor - Bovine
170; a sample sequence in FASTA format
171MDSKGSSQKGSRLLLLLVVSNLLLCQGVVSTPVCPNGPGNCQVSLRDLFDRAVMVSHYIHDLSS
172EMFNEFDKRYAQGKGFITMALNSCHTSSLPTPEDKEQAQQTHHEVLMSLILGLLRSWNDPLYHL
173VTEVRGMKGAPDAILSRAIEIEEENKRLLEGMEMIFGQVIPGAKETEPYPVWSGLPSLQTKDED
174ARYSAFYNLLHCLRRDSSKIDTYLKLLNCRIIYNNNC*
175
176>MCHU - Calmodulin - Human, rabbit, bovine, rat, and chicken
177ADQLTEEQIAEFKEAFSLFDKDGDGTITTKELGTVMRSLGQNPTEAELQDMINEVDADGNGTID
178FPEFLTMMARKMKDTDSEEEIREAFRVFDKDGNGYISAAELRHVMTNLGEKLTDEEVDEMIREA
179DIDGDGQVNYEEFVQMMTAK*
180
181>gi|5524211|gb|AAD44166.1| cytochrome b [Elephas maximus maximus]
182LCLYTHIGRNIYYGSYLYSETWNTGIMLLLITMATAFMGYVLPWGQMSFWGATVITNLFSAIPYIGTNLV
183EWIWGGFSVDKATLNRFFAFHFILPFTMVALAGVHLTFLHETGSNNPLGLTSDSDKIPFHPYYTIKDFLG
184LLILILLLLLLALLSPDMLGDPDNHMPADPLNTPLHIKPEWYFLFAYAILRSVPNKLGGVLALFLSIVIL
185GLMPFLHTSKHRSMMLRPLSQALFWTLTMDLLTLTWIGSQPVEYPYTIIGQMASILYFSIILAFLPIAGX
186IENY
187```
188
189FASTA format was extended by [FASTQ](https://en.wikipedia.org/wiki/FASTQ_format) format from the [Sanger Centre](https://www.sanger.ac.uk/) in Cambridge.
190
191### PNG encoded DNA sequence
192
193| Nucleotides | RGB | Color name |
194| ------------- | ----------- | ---------- |
195| A -> Adenine | (0,0,255) | Blue |
196| G -> Guanine | (0,100,0) | Green |
197| C -> Cytosine | (255,0,0) | Red |
198| T -> Thymine | (255,255,0) | Yellow |
199
200With this in mind we can create a simple algorithm to create PNG representation of a DNA sequence.
201
202```pascal
203{ Algorithm 2: Naive DNA to PNG encode from FASTA file }
204procedure EncodeDNASequenceToPNG(f)
205begin
206 i image
207 while not eof(f) do
208 c char := buffer[0] { Read 1 char from buffer }
209 case c of
210 'A': color := RGB(0, 0, 255) { Blue }
211 'G': color := RGB(0, 100, 0) { Green }
212 'C': color := RGB(255, 0, 0) { Red }
213 'T': color := RGB(255, 255, 0) { Yellow }
214 drawRect(i, [x, y], color)
215 save(i) { Save PNG image }
216end
217```
218
219## Encoding text file in practice
220
221In this example we will take a simple text file as our input stream for encoding. This file will have a quote from Niels Bohr and saved as txt file.
222
223> How wonderful that we have met with a paradox. Now we have some hope of making progress.
224> ― Niels Bohr
225
226First we encode text file into FASTA file.
227
228```bash
229./dnae-encode -i quote.txt -o quote.fa
2302019/01/10 00:38:29 Gathering input file stats
2312019/01/10 00:38:29 Starting encoding ...
232 106 B / 106 B [==================================] 100.00% 0s
2332019/01/10 00:38:29 Saving to FASTA file ...
2342019/01/10 00:38:29 Output FASTA file length is 438 B
2352019/01/10 00:38:29 Process took 987.263µs
2362019/01/10 00:38:29 Done ...
237```
238
239Output of `quote.fa` file contains the encoded DNA sequence in ASCII format.
240
241```text
242>SEQ1
243GACAGCTTGTGTACAAGTGTGCTTGCTCGCGAGCGGGTACGCGCGTGGGCTAACAAGTGA
244GCCAGCAGGTGAACAAGTGTGCGGACAAGCCAGCAGGTGCGCGGACAAGCTGGCGGGTGA
245ACAAGTGTGCCGGTGAGCCAACAAGCAGACAAGTAAGCAGGTACGCAGGCGAGCTTGTCA
246ACTCACAAGATCGCTTGTGTACAAGTGTGCGGACAAGCCAGCAGGTGCGCGGACAAGTAT
247GCTTGCTGGCGGACAAGCCAGCTTGTAAGCGGACAAGCTTGCGCACAAGCTGGCAGGCCT
248GCCGGCTCGCGTACAAATTCACAAGTAAGTACGCTTGCGTGTACGCGGGTATGTATACTC
249AACCTCACCAAACGGGACAAGATCGCCGGCGGGCTAGTATACAAGAACGCTTGCCAGTAC
250AACC
251```
252
253Then we encode FASTA file from previous operation to encode this data into PNG.
254
255```bash
256./dnae-png -i quote.fa -o quote.png
2572019/01/10 00:40:09 Gathering input file stats ...
2582019/01/10 00:40:09 Deconstructing FASTA file ...
2592019/01/10 00:40:09 Compositing image file ...
260 424 / 424 [==================================] 100.00% 0s
2612019/01/10 00:40:09 Saving output file ...
2622019/01/10 00:40:09 Output image file length is 1.1 kB
2632019/01/10 00:40:09 Process took 19.036117ms
2642019/01/10 00:40:09 Done ...
265```
266
267After encoding into PNG format this file looks like this.
268
269![Encoded Quote in PNG format](/files/dna-sequence/quote.png)
270
271The larger the input stream is the larger the PNG file would be.
272
273Compiled basic Hello World C program with [GCC](https://www.gnu.org/software/gcc/) would [look like](/files/dna-sequence/sample.png).
274
275```c
276// gcc -O3 -o sample sample.c
277#include <stdio.h>
278
279main() {
280 printf("Hello, world!\n");
281 return 0;
282}
283```
284
285## Toolkit for encoding data
286
287I have created a toolkit with two main programs:
288- dnae-encode (encodes file into FASTA file)
289- dnae-png (encodes FASTA file into PNG)
290
291Toolkit with full source code is available on [github.com/mitjafelicijan/dna-encoding](https://github.com/mitjafelicijan/dna-encoding).
292
293### dnae-encode
294
295```bash
296> ./dnae-encode --help
297usage: dnae-encode --input=INPUT [<flags>]
298
299A command-line application that encodes file into DNA sequence.
300
301Flags:
302 --help Show context-sensitive help (also try --help-long and --help-man).
303 -i, --input=INPUT Input file (ASCII or binary) which will be encoded into DNA sequence.
304 -o, --output="out.fa" Output file which stores DNA sequence in FASTA format.
305 -s, --sequence=SEQ1 The description line (defline) or header/identifier line, gives a name and/or a unique identifier for the sequence.
306 -c, --columns=60 Row characters length (no more than 120 characters). Devices preallocate fixed line sizes in software.
307 --version Show application version.
308```
309
310### dnae-png
311
312```bash
313> ./dnae-png --help
314usage: dnae-png --input=INPUT [<flags>]
315
316A command-line application that encodes FASTA file into PNG image.
317
318Flags:
319 --help Show context-sensitive help (also try --help-long and --help-man).
320 -i, --input=INPUT Input FASTA file which will be encoded into PNG image.
321 -o, --output="out.png" Output file in PNG format that represents DNA sequence in graphical way.
322 -s, --size=10 Size of pairings of DNA bases on image in pixels (lower resolution lower file size).
323 --version Show application version.
324```
325
326## Benchmarks
327
328First we generate some binary sample data with dd.
329
330```bash
331dd if=<(openssl enc -aes-256-ctr -pass pass:"$(dd if=/dev/urandom bs=128 count=1 2>/dev/null | base64)" -nosalt < /dev/zero) of=1KB.bin bs=1KB count=1 iflag=fullblock
332```
333
334Our freshly generated 1KB file looks something like this (its full of garbage data as intended).
335
336![Sample binary file 1KB](/files/dna-sequence/sample-binary-file.png)
337
338We create following binary files:
339- 1KB.bin
340- 10KB.bin
341- 100KB.bin
342- 1MB.bin
343- 10MB.bin
344- 100MB.bin
345
346After this we create FASTA files for all the binary files by encoding them into DNA sequence.
347
348```bash
349./dnae-encode -i 100MB.bin -o 100MB.fa
350```
351
352Then we GZIP all the FASTA files to see how much the can be compressed.
353
354```bash
355gzip -9 < 10MB.fa > 10MB.fa.gz
356```
357
358<script src="//cdn.plot.ly/plotly-latest.min.js"></script>
359
360**Speed of encoding binary file into FASTA format.**
361
362<div id="encoding-benchmarks"></div>
363<script>
364(function(){
365 var trace1 = {
366 x: ['1KB.bin', '10KB.bin', '100KB.bin', '1MB.bin', '10MB.bin', '100MB.bin'],
367 y: [5.625224, 32.679975, 112.864416, 872.887675, 8472.693202, 85525.178217],
368 type: 'scatter',
369 };
370 var data = [trace1];
371 Plotly.newPlot("encoding-benchmarks", data, {
372 legend: {"orientation": "h"},
373 height: 300,
374 margin: { l: 50, r: 0, b: 50, t: 30, pad: 0 },
375 yaxis: { title: "execution time in milliseconds", titlefont: { size: 12 } },
376 });
377})();
378</script>
379
380**File sizes of encoded files and also GZIP-ed variations.**
381
382<div id="size-benchmarks"></div>
383<script>
384(function(){
385 var trace1 = {
386 x: ['1KB.bin', '10KB.bin', '100KB.bin', '1MB.bin', '10MB.bin', '100MB.bin'],
387 y: [4.1, 40.7, 406.7, 4100, 40700, 406700],
388 name: 'FASTA file size',
389 type: 'bar',
390 };
391 var trace2 = {
392 x: ['1KB.bin', '10KB.bin', '100KB.bin', '1MB.bin', '10MB.bin', '100MB.bin'],
393 y: [1.4, 13, 121, 1200, 12000, 118000],
394 name: 'FASTA GZIPPED file size',
395 type: 'bar',
396 };
397 var data = [trace1, trace2];
398 Plotly.newPlot("size-benchmarks", data, {
399 legend: {"orientation": "h"},
400 height: 300,
401 margin: { l: 50, r: 0, b: 50, t: 30, pad: 0 },
402 yaxis: { title: "size in kilobytes", titlefont: { size: 12 } },
403 barmode: 'stack'
404 });
405})();
406</script>
407
408[Download ODS file with benchmarks](/files/dna-sequence/benchmarks.ods).
409
410## References
411
412[^1]: https://www.techopedia.com/definition/948/encoding
413[^2]: https://www.dna-worldwide.com/resource/160/history-dna-timeline
414[^3]: https://opentextbc.ca/biology/chapter/9-1-the-structure-of-dna/
415[^4]: https://arxiv.org/abs/1801.04774
416[^5]: https://en.wikipedia.org/wiki/FASTA_format
diff --git a/content/2019-05-11-bci.md b/content/2019-05-11-bci.md
deleted file mode 100644
index c055b65..0000000
--- a/content/2019-05-11-bci.md
+++ /dev/null
@@ -1,71 +0,0 @@
1---
2layout: draft
3title: BCI
4description: Imagine a world where you could go outside and take a leaf from a tree and put it through your personal DNA sequencer and get data like music, videos or computer programs from it.
5slug: bci
6type: research
7date: 2019-05-11
8---
9
10**Table of contents**
11
121. [Intefacing with Bluetooth device](#intefacing-with-bluetooth-device)
13 1. [Basic Concepts](#basic-concepts)
14 1. [Attributes](#attributes)
15 2. [Structure](#structure)
16 3. [Services](#services)
17 4. [Characteristics](#characteristics)
182. [Generic text for testing CSS styles](#generic-text-for-testing-css-styles)
193. [Resources](#resources)
20
21
22## Intefacing with Bluetooth device
23
24A Bluetooth device contains a table of data called an Attribute Table which can be accessed by other connected devices in various possible ways. That table of data and the ways in which it can be exploited falls into a technical area of Bluetooth called the Generic Attribute profile or GATT for short and you may see the term GATT in some of the documentation for APIs such as those provided by the Android platform.
25
26The Attribute Table contains something like a series of records of various types. The main types are called Services, Characteristics, and Descriptors. Let’s look at each of these terms in turn.
27
28### Basic Concepts
29
30#### Attributes
31
32Services, Characteristics and Descriptors are all types of Attribute. Hence Generic Attribute Profile, Attribute Table and something called the Attribute Protocol. All attributes have a type which is identified by a UUID (Universally Unique Identifer). Some Attributes are defined by the Bluetooth SIG, the technical standards body for Bluetooth and these have UUIDs which are 16 bits in length. Some Attributes are custom designed for a particular device by the product team and these have 128 bit UUIDs.
33
34#### Structure
35
36Services, Characteristics and Descriptors are organised in a hierarchy with Services at the top and Descriptors at the bottom. Services contain one or more Characteristics. A Characteristic owns zero or more Descriptors because Descriptors are completely optional whereas a Service must contain at least one Characteristic.
37
38#### Services
39
40A Service is a container for logically related Bluetooth data items. Those data items are in fact called Characteristics. A Service can be thought of as the owner of the Characteristics inside it. Often a Service represents a particular feature (e.g. a hardware feature) of a device like the buttons or a particular sensor. An example of a Bluetooth SIG defined Service is the Device Information Service which, as the name suggests, is a container for various items of information about the device such as its manufacturer and serial number.
41
42#### Characteristics
43
44Characteristics are items of data which relate to a particular internal state of the device or perhaps some state of the environment which the device can measure using a sensor. The current battery level is an example of internal state data whereas the ambient temperature could perhaps be measured by a sensor. Sometimes Characteristics represent configuration data such as the frequency at which you want something to be measured. In any of these cases, the way a device can expose such data to other devices to use via Bluetooth is by making them available as a Characteristic. An example of a Bluetooth SIG defined Characteristic is the Serial Number String which you’ll find inside the Device Information service.
45
46Characteristics contain various parts. They have a type, a value, some properties and some permissions.
47
48Type is something already explained above, a UUID value which indicates which particular type of Characteristic an Attribute is. Value is the value of the associated state data item.
49
50Properties define what another device can do with the characteristic over Bluetooth in terms of various defined operations such as READ, WRITE or NOTIFY. Reading a characteristic means transferring its current value from the attribute table to the connected device over Bluetooth. Writing allows the connected device to change that value in the state table. Notifications are a special message type which a device can send to a connected device whenever the value of the associated characteristic changes or perhaps periodically, controlled by a timer. Not all Characteristics support all operations. The Characteristic’s properties tell you which operations are supported.
51
52Sometimes the device will have been programmed to respond in a special way when it processes an operation like reading or writing a value from the attribute table so operations can result in more happening than simply transferring data across the connection. Perhaps changing the value of a Characteristic will result in the device changing the frequency with which it samples readings from the device accelerometer for example.
53
54Permissions are to do with security and further describe the security conditions that must be met before read or write access to the characteristic is to be granted.
55
56## Generic text for testing CSS styles
57
58Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus pulvinar finibus ipsum, vitae mattis neque elementum nec. Cras vel lacinia diam, a porttitor nisl. Sed ullamcorper convallis bibendum. Ut id lectus risus. Morbi aliquam eros condimentum volutpat pretium. Praesent malesuada congue eros, vitae mollis erat laoreet nec. Quisque porta tempus turpis a mollis. Nulla at mollis sem, at scelerisque velit. Mauris non ex lectus. Morbi eget erat interdum lacus pretium vehicula vitae ac justo. Quisque vulputate interdum semper. Duis dignissim porta magna, vel faucibus leo pulvinar at. Donec nibh purus, vestibulum vel velit a, ultricies volutpat ipsum.
59
60![spikes](/files/bci/spike-waves.png)
61
62Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus pulvinar finibus ipsum, vitae mattis neque elementum nec. Cras vel lacinia diam, a porttitor nisl. Sed ullamcorper convallis bibendum. Ut id lectus risus. Morbi aliquam eros condimentum volutpat pretium. Praesent malesuada congue eros, vitae mollis erat laoreet nec. Quisque porta tempus turpis a mollis. Nulla at mollis sem, at scelerisque velit. Mauris non ex lectus. Morbi eget erat interdum lacus pretium vehicula vitae ac justo. Quisque vulputate interdum semper. Duis dignissim porta magna, vel faucibus leo pulvinar at. Donec nibh purus, vestibulum vel velit a, ultricies volutpat ipsum.
63
64![banner](http://satyr.io/1100x300/eee#large)
65
66Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus pulvinar finibus ipsum, vitae mattis neque elementum nec. Cras vel lacinia diam, a porttitor nisl. Sed ullamcorper convallis bibendum. Ut id lectus risus. Morbi aliquam eros condimentum volutpat pretium. Praesent malesuada congue eros, vitae mollis erat laoreet nec. Quisque porta tempus turpis a mollis. Nulla at mollis sem, at scelerisque velit. Mauris non ex lectus. Morbi eget erat interdum lacus pretium vehicula vitae ac justo. Quisque vulputate interdum semper. Duis dignissim porta magna, vel faucibus leo pulvinar at. Donec nibh purus, vestibulum vel velit a, ultricies volutpat ipsum.
67
68
69## Resources
70
71- https://www.bluetooth.com/blog/a-developers-guide-to-bluetooth/
diff --git a/content/cv.md b/content/cv.md
deleted file mode 100644
index ca02245..0000000
--- a/content/cv.md
+++ /dev/null
@@ -1,68 +0,0 @@
1---
2layout: page
3title: Curriculum Vitae
4description: Summary of my experiences, skills and major projects I have worked on through year
5slug: curriculum-vitae
6---
7
8**Mitja Felicijan**
9*[mitja.felicijan@gmail.com](mailto:mitja.felicijan@gmail.com?subject=Website+CV+Contact)*
10*Slovenia, EU*
11
12## Technical experience
13
14- **Key languages:** Golang, Python, C, Bash.
15- **Platforms:** GNU/Linux, macOS.
16- **Fields of study:** Zigbee, KNX, Modbus, Machine to Machine, Embedded systems, Operating systems, Distributed systems, IOT, RDBMS, Algorithms, Database engine design, SQL, NoSQL, NewSQL, Big data analytics, Machine learning, Prediction algorithms, Realtime analytics, Systems automation, Natural language processing, Bioinformatics.
17
18## Major projects
19
20- SMS marketing system (2007)
21- Yacht management software (2008)
22- Smart Home Gateway (2009)
23- Moxa UPort 1130 USB to RS485 Universal Linux driver (2009)
24- Remote management of electricity meter (2009)
25- Remote management of blood pressure monitor (2010)
26- Infomat automation system (2010)
27- GPS Tourist - GIS Software (2011)
28- Minimal GNU/Linux distribution for embedded platforms (2011)
29- Digital Jukebox system (2012)
30- NanoCloudLogger - Machine to Machine (2012)
31- Street Lightning System (2012)
32- Smart cabins with hardware sensor management (2013)
33- Contextual advertising server (2015)
34- Network accessible database engine for caching and in-memory storage (2016)
35- Tick database engine specifically designed for storing and processing large amount of sensor data with high write throughput (2016)
36- Wireless industrial lighting management system - hardware and software (2016)
37- Minimal configuration reverse proxy (2017)
38- Industrial IOT platform for deployment on on-premise (2018)
39- Custom Platform as a service based on Docker Swarm (2018)
40- Toolkit for encoding binary data into DNA sequence (2019)
41- Minimal configuration reverse proxy with load balancing and rate limiting (2019)
42- E-ink conference room occupancy display, hadrware and software solution (2019)
43
44## Employment history
45
46- Freelancer (2001 – Present)
47- Software developer at Mobinia (2005 – 2007)
48- CTO at Milk (2007 – 2009)
49- Co-Founder of UTS (2009 – 2014)
50- Senior Software Engineer at TSmedia (2015 - 2017)
51- Senior Software Engineer at Renderspace (2017 - 2019)
52- IT Consultant (2017 – Present)
53
54## Awards
55
56- Regional Award for Innovation by Chamber of Commerce and Industry of Slovenia for project Intelligent system management and regulation of Street Lighting, 2010
57- National Award for Innovation by Chamber of Commerce and Industry of Slovenia for project Intelligent system management and regulation of Street Lighting, 2010
58
59## Key responsibilities
60
61- Embedded platform development.
62- Hardware design and driver development.
63- Designing, developing and testing systems.
64- Implementation of the systems.
65- Writing and maintaining user and technical documents.
66- Development and maintenance of the project.
67- Code revision, testing and output.
68- Work on the enhancement suggested by the customers and fixes the bugs reported.
diff --git a/content/files/avatar-512x512.png b/content/files/avatar-512x512.png
deleted file mode 100644
index 1ebe6f2..0000000
--- a/content/files/avatar-512x512.png
+++ /dev/null
Binary files differ
diff --git a/content/files/avatar-64x64.png b/content/files/avatar-64x64.png
deleted file mode 100644
index 86e840e..0000000
--- a/content/files/avatar-64x64.png
+++ /dev/null
Binary files differ
diff --git a/content/files/bci/spike-waves.png b/content/files/bci/spike-waves.png
deleted file mode 100644
index b0fc0b3..0000000
--- a/content/files/bci/spike-waves.png
+++ /dev/null
Binary files differ
diff --git a/content/files/copy-benchmarks.tsv b/content/files/copy-benchmarks.tsv
deleted file mode 100644
index c7a7af4..0000000
--- a/content/files/copy-benchmarks.tsv
+++ /dev/null
@@ -1,101 +0,0 @@
110KB 100KB 1MB 10MB
20.15 0.187 0.317 0.653
30.158 0.237 0.192 0.659
40.134 0.359 0.236 0.604
50.136 0.292 0.196 0.501
64.411 4.479 4.376 0.649
70.134 0.481 0.265 0.608
80.146 0.266 0.28 0.516
94.282 0.307 4.549 0.562
100.152 0.28 0.229 0.512
110.162 0.37 0.315 0.652
120.13 4.735 0.222 5.171
134.29 8.767 0.283 5.076
144.555 4.682 0.318 4.941
154.658 4.691 0.177 9.624
164.778 4.791 4.415 5.114
178.794 8.604 0.311 5.223
184.582 4.727 0.234 9.28
194.596 4.638 0.212 5.064
204.7 4.65 4.458 5.221
218.822 9.159 0.191 5.032
224.628 4.641 0.324 9.226
234.6 4.921 0.197 5.22
248.85 4.58 4.405 5.245
254.65 9.142 0.215 5.168
264.884 6.67 0.248 9.273
274.581 4.594 0.248 5.082
288.864 4.844 4.502 5.121
294.704 4.656 0.177 5.173
304.616 8.883 0.209 9.334
314.729 4.962 4.366 4.966
328.918 4.682 0.186 6.702
334.686 4.58 0.168 5.111
345.123 8.84 4.747 5.084
354.846 4.732 8.85 5.065
368.887 4.639 4.824 9.286
374.681 8.897 4.791 5.104
384.649 4.682 4.835 5.194
398.847 4.663 8.929 5.271
404.568 4.604 4.762 9.444
414.657 8.74 4.772 5.076
424.636 4.724 4.838 5.168
438.778 4.846 9.065 5.057
444.995 4.571 5.074 9.314
452.343 9.222 4.818 5.732
464.742 4.646 8.909 5.32
474.82 4.842 4.778 5.167
488.791 4.66 4.759 5.157
494.835 8.944 4.804 9.323
504.599 5.594 8.952 5.299
514.809 4.628 1.567 5.294
528.744 4.771 5.59 5.018
534.71 8.919 4.771 9.257
544.704 4.7 9.003 5.064
554.765 4.605 4.781 5.185
568.866 4.669 4.844 5.392
574.897 8.925 4.786 9.279
584.568 5.168 8.893 5.1
594.679 4.757 5.41 5.232
608.922 4.702 4.7 1.984
614.669 8.721 4.906 5.366
624.707 4.555 8.96 5.245
638.938 4.615 4.89 5.216
644.608 4.621 4.677 9.237
654.58 8.954 4.908 5.194
664.707 4.575 8.968 5.017
678.822 4.781 4.882 9.714
684.674 8.833 4.834 5.02
695.005 4.689 4.762 5.312
704.732 4.799 9.111 5.286
718.894 4.675 4.936 5.185
724.747 8.764 4.739 9.312
734.785 4.749 4.845 5.34
744.656 4.705 9.181 5.256
758.899 4.601 4.739 5.261
764.594 8.813 4.576 9.329
774.585 4.716 8.813 5.343
788.718 4.723 4.819 5.092
794.725 4.757 4.83 5.061
804.737 8.899 4.772 9.488
814.692 4.717 8.831 5.13
828.841 4.951 4.787 5.309
834.66 8.895 4.746 5.228
844.749 4.595 4.833 5.26
854.715 4.615 8.928 9.381
868.849 4.651 4.826 5.289
874.66 8.897 4.802 5.197
884.588 4.844 4.883 9.311
894.753 4.888 9.053 5.072
908.841 4.737 4.75 5.157
914.794 8.976 5.063 5.196
924.544 4.673 9.036 9.335
938.74 4.654 6.377 5.29
944.729 4.752 5.001 5.048
954.654 8.98 4.873 5.544
964.9 4.606 4.723 5.192
978.757 4.802 5.427 9.056
984.859 8.969 4.816 5.3
994.701 4.662 9.002 5.138
1004.943 4.813 4.894 5.15
1018.772 4.721 4.785 9.168
diff --git a/content/files/dev101-git-topics-1.png b/content/files/dev101-git-topics-1.png
deleted file mode 100644
index bb09380..0000000
--- a/content/files/dev101-git-topics-1.png
+++ /dev/null
Binary files differ
diff --git a/content/files/dev101-git-topics-2.png b/content/files/dev101-git-topics-2.png
deleted file mode 100644
index 39a370a..0000000
--- a/content/files/dev101-git-topics-2.png
+++ /dev/null
Binary files differ
diff --git a/content/files/dna-sequence/benchmarks.ods b/content/files/dna-sequence/benchmarks.ods
deleted file mode 100644
index 62a8e30..0000000
--- a/content/files/dna-sequence/benchmarks.ods
+++ /dev/null
Binary files differ
diff --git a/content/files/dna-sequence/chart-encoding-speed.png b/content/files/dna-sequence/chart-encoding-speed.png
deleted file mode 100644
index 7fb106d..0000000
--- a/content/files/dna-sequence/chart-encoding-speed.png
+++ /dev/null
Binary files differ
diff --git a/content/files/dna-sequence/chart-file-sizes.png b/content/files/dna-sequence/chart-file-sizes.png
deleted file mode 100644
index 31bfa66..0000000
--- a/content/files/dna-sequence/chart-file-sizes.png
+++ /dev/null
Binary files differ
diff --git a/content/files/dna-sequence/dna-basics.jpg b/content/files/dna-sequence/dna-basics.jpg
deleted file mode 100644
index c2e7f52..0000000
--- a/content/files/dna-sequence/dna-basics.jpg
+++ /dev/null
Binary files differ
diff --git a/content/files/dna-sequence/quote.png b/content/files/dna-sequence/quote.png
deleted file mode 100644
index 09fb01c..0000000
--- a/content/files/dna-sequence/quote.png
+++ /dev/null
Binary files differ
diff --git a/content/files/dna-sequence/sample-binary-file.png b/content/files/dna-sequence/sample-binary-file.png
deleted file mode 100644
index 1e4622a..0000000
--- a/content/files/dna-sequence/sample-binary-file.png
+++ /dev/null
Binary files differ
diff --git a/content/files/dna-sequence/sample.png b/content/files/dna-sequence/sample.png
deleted file mode 100644
index 30f12da..0000000
--- a/content/files/dna-sequence/sample.png
+++ /dev/null
Binary files differ
diff --git a/content/files/fuse-droplets.png b/content/files/fuse-droplets.png
deleted file mode 100644
index d7ce243..0000000
--- a/content/files/fuse-droplets.png
+++ /dev/null
Binary files differ
diff --git a/content/files/fuse-spaces.png b/content/files/fuse-spaces.png
deleted file mode 100644
index 4dcc1c5..0000000
--- a/content/files/fuse-spaces.png
+++ /dev/null
Binary files differ
diff --git a/content/files/golang-profiling-cpu.pdf b/content/files/golang-profiling-cpu.pdf
deleted file mode 100644
index 15241cb..0000000
--- a/content/files/golang-profiling-cpu.pdf
+++ /dev/null
Binary files differ
diff --git a/content/files/golang-profiling-mem.pdf b/content/files/golang-profiling-mem.pdf
deleted file mode 100644
index 822e445..0000000
--- a/content/files/golang-profiling-mem.pdf
+++ /dev/null
Binary files differ
diff --git a/content/files/iot-app-output.png b/content/files/iot-app-output.png
deleted file mode 100644
index 1c80589..0000000
--- a/content/files/iot-app-output.png
+++ /dev/null
Binary files differ
diff --git a/content/files/iot-rest-example.png b/content/files/iot-rest-example.png
deleted file mode 100644
index 3ed86aa..0000000
--- a/content/files/iot-rest-example.png
+++ /dev/null
Binary files differ
diff --git a/content/files/iot-sqlite-db.png b/content/files/iot-sqlite-db.png
deleted file mode 100644
index 82e1e29..0000000
--- a/content/files/iot-sqlite-db.png
+++ /dev/null
Binary files differ
diff --git a/content/files/kcachegrind.png b/content/files/kcachegrind.png
deleted file mode 100644
index 0dc48ab..0000000
--- a/content/files/kcachegrind.png
+++ /dev/null
Binary files differ
diff --git a/content/files/profiling-viewer.png b/content/files/profiling-viewer.png
deleted file mode 100644
index a450513..0000000
--- a/content/files/profiling-viewer.png
+++ /dev/null
Binary files differ
diff --git a/content/files/simple-iot-application-overview.svg b/content/files/simple-iot-application-overview.svg
deleted file mode 100644
index 817666d..0000000
--- a/content/files/simple-iot-application-overview.svg
+++ /dev/null
@@ -1,2 +0,0 @@
1<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
2<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="623px" height="482px" version="1.1" content="&lt;mxfile userAgent=&quot;Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36&quot; version=&quot;7.1.3&quot; editor=&quot;www.draw.io&quot; type=&quot;google&quot;&gt;&lt;diagram id=&quot;d1a10cf0-d877-4170-d86f-ec45460d7050&quot; name=&quot;Page-1&quot;&gt;7Vnbbts4EP0aPzYQdbP9mKTNFtjtokgWSPpIi7RNrCRqKfq2X79DiZREUU5sV267RREgoI6o4XDmkHNIT4L7bP+bwMX6Eyc0nfge2U+C9xPfn8Yz+K+AQw1Ecw2sBCM1hFrgif1LNehpdMMILa2OkvNUssIGE57nNJEWhoXgO7vbkqf2qAVeUQd4SnDqos+MyHWNziKvxT9StlqbkZGn32TYdNZAucaE7zpQ8GES3AvOZd3K9vc0VbEzcam/ezjytnFM0Fye8oFff7DF6UbP7T2WeIFLqv2TBzNpcLVQzeSQspxQMQnudmsm6VOBE4XvINWArWWWwhOC5oJvoCP5Y2GAUgr+dxMymOzdkufySY+hnd9SIen+6HxQEyVgF+UZleIAXfQHwVzPSDMrjHWgd22e4qiG1p0UzXQ3rJmxaiy3wYOGjt9wLAMnlhM/TqUKBDRWqmEANW0ruvE/G25evCsrwt9CBxQV+/alsfJMF8rVokhZgiXjuTELHtaW7dEAdjwgbNuHjnpp1p/xI3RdamyIgcFP9QmwAbdO8XRw2Dft9wguarrCg/c2t10qj8Fesy0ces8d9vpmL+nSt9lgvoa/4QB/eyGiOblV+yc85TynVRywkAZLUlyWLLEjBXMXhxcV1RsUzgzwpQLm8VQBeyZfdNhVu34XVV3JA1MOV+/cmFemPlPBYLJqR6q61V5T4uzhvTTAzPhGJNTaCWE6Kyo7C9pNVicZ0UAuDCZoCotzazsxlB89wmfOquXWcCGyuBD1t6jaef1Vd4vvG5r2DAU9Q/WUHUOQVHzodCtUh/IVhyObvJFnlR5o1BZbLjYxPYme0Vn0bKloMVSzdpies2japSe68VCXnsihZ2X6F0H/JwQN5+iqBI1RMItmOF7OEY0hPO9cxj4LKCoDhY2A6Cpqb08qVVBi5FA9uucpFy3Nl0DNHoRTtsrV+gCqVRpOFSyQEemtfpExQtQwgwVwhBrn9xVa6Na4cIC1/ggVzsnQ1MnQI8XktQSVP3+GIhT9OBmaORm6FWTDcj6QpE+/P4IQ8s6We+gSubdSBUZv6GOfYvzYLqVo4BSD/IEUxNdIwdzdxqoDyEIdpIGhIwc24Zmq21cJbPhDBdZcZ4ytuI/IkJeOrDYSp6u+b/yoq3Ac+X2ZbAlc2TK8yL+Xjukvtst1DOoZupbQ7p0SzeXF1XQMMkvvq6T3qFSd9ql6PXLOf5HzDHJG35yc/iWbKMHluilRr/LRlm0TP7ir/s6g3PfiTjwbTsXZ3EHxG4aOcOeC9CK8REmYYN+fYoo9OnCG6t1OLnFi305+pOmWKsHs3lI+8o3UN6vKyWM3lKNLeVHn9jwlb8uortzsK6QHnLFU5eYvllFYm96fdAf/H3mG82uIqGBq0SGYuyJqeqXzgcOP+Hr8wAX7dhRJ6fLnYUgQeG8yZD4OQ+Cx/bWs3nDanxyDD/8B&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><g transform="translate(0.5,0.5)"><path d="M 283 367 C 283 345.67 348 345.67 348 367 L 348 415 C 348 436.33 283 436.33 283 415 Z" fill="#ffffff" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 283 367 C 283 383 348 383 348 367" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(287.5,395.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="54" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 54px; white-space: nowrap; word-wrap: normal; font-weight: bold; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Database</div></div></foreignObject><text x="27" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica" font-weight="bold">Database</text></switch></g><rect x="211" y="211" width="200" height="100" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(252.5,234.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="115" height="51" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 115px; white-space: nowrap; word-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><b><font style="font-size: 15px">Web application</font></b><div><b><font size="4"><br /></font></b></div><div><b><br /></b></div></div></div></foreignObject><text x="58" y="32" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><path d="M 274.76 391 L 251 391 Q 241 391 241 381 L 241 308" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 280.76 391 L 272.76 395 L 274.76 391 L 272.76 387 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 348 391 L 372 391 Q 382 391 382 381 L 382 321.24" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 382 315.24 L 386 323.24 L 382 321.24 L 378 323.24 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(177.5,327.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="50" height="26" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 50px; white-space: nowrap; word-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Write<div>datapoint</div></div></div></foreignObject><text x="25" y="19" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><g transform="translate(397.5,327.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="56" height="26" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 56px; white-space: nowrap; word-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Read<div>datapoints</div></div></div></foreignObject><text x="28" y="19" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><rect x="151" y="51" width="120" height="60" rx="9" ry="9" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(182.5,67.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="55" height="26" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 55px; white-space: nowrap; word-wrap: normal; font-weight: bold; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Arduino<div>MKR1000</div></div></div></foreignObject><text x="28" y="19" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica" font-weight="bold">[Not supported by viewer]</text></switch></g><rect x="351" y="51" width="120" height="60" rx="9" ry="9" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(372.5,74.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="75" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 77px; white-space: nowrap; word-wrap: normal; font-weight: bold; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Web browser</div></div></foreignObject><text x="38" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica" font-weight="bold">Web browser</text></switch></g><path d="M 254.57 205.86 L 218.81 177.25 Q 211 171 211 161 L 211 111" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 259.25 209.6 L 250.51 207.73 L 254.57 205.86 L 255.51 201.48 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 367.43 205.86 L 403.19 177.25 Q 411 171 411 161 L 411 119.24" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 362.75 209.6 L 366.49 201.48 L 367.43 205.86 L 371.49 207.73 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 411 113.24 L 415 121.24 L 411 119.24 L 407 121.24 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 571 171 L 51 171" fill="none" stroke="#b3b3b3" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="none"/><g transform="translate(350.5,284.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="45" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: &quot;Times New Roman&quot;; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 46px; white-space: nowrap; word-wrap: normal; font-weight: bold; text-align: right;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><font face="Helvetica">Route: /</font></div></div></foreignObject><text x="23" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Times New Roman" font-weight="bold">[Not supported by viewer]</text></switch></g><g transform="translate(222.5,284.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="62" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: &quot;Times New Roman&quot;; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 63px; white-space: nowrap; word-wrap: normal; font-weight: bold;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><font face="Helvetica">Route: /api</font></div></div></foreignObject><text x="31" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Times New Roman" font-weight="bold">[Not supported by viewer]</text></switch></g></g></svg> \ No newline at end of file
diff --git a/content/files/simple-iot-application.zip b/content/files/simple-iot-application.zip
deleted file mode 100644
index 46d3205..0000000
--- a/content/files/simple-iot-application.zip
+++ /dev/null
Binary files differ
diff --git a/content/files/snakeviz.png b/content/files/snakeviz.png
deleted file mode 100644
index 5bab395..0000000
--- a/content/files/snakeviz.png
+++ /dev/null
Binary files differ
diff --git a/content/files/sqlite-benchmarks.tsv b/content/files/sqlite-benchmarks.tsv
deleted file mode 100644
index daa2c21..0000000
--- a/content/files/sqlite-benchmarks.tsv
+++ /dev/null
@@ -1,1001 +0,0 @@
1DROPTABLE CREATETABLE INSERTMANY FETCHALL COMMIT
20.000732 0.000400 0.008133 0.000065 0.000166
30.000200 0.000214 0.003105 0.000043 0.000171
40.000246 0.000170 0.006594 0.000044 0.000101
50.000182 0.000166 0.003892 0.000043 0.000112
60.000248 0.000654 0.002308 0.000041 0.000090
70.000240 0.000184 0.002253 0.000053 0.000110
80.000698 0.000483 0.003737 0.000041 0.000165
90.000217 0.000179 0.002470 0.000049 0.000107
100.000243 0.000160 0.002668 0.000054 0.000340
110.000196 0.000169 0.002247 0.000040 0.000096
120.000191 0.000162 0.003522 0.000260 0.000102
130.000195 0.000188 0.002325 0.000041 0.000132
140.000194 0.000202 0.002291 0.000039 0.000091
150.000195 0.000196 0.004114 0.000042 0.000108
160.000204 0.000200 0.002971 0.000040 0.000106
170.000227 0.000159 0.002208 0.000039 0.000117
180.000207 0.000176 0.003558 0.000040 0.000124
190.000255 0.000179 0.002870 0.000040 0.000125
200.000209 0.000176 0.002248 0.000040 0.000176
210.000211 0.000174 0.002661 0.000039 0.000180
220.000208 0.000219 0.002321 0.000039 0.000151
230.000212 0.000178 0.002609 0.000040 0.000132
240.000205 0.000209 0.002666 0.000039 0.000126
250.000205 0.000176 0.002501 0.000041 0.000133
260.000243 0.000183 0.002220 0.000037 0.000117
270.000504 0.000173 0.002230 0.000121 0.000414
280.000270 0.000200 0.002325 0.000040 0.000154
290.000208 0.000176 0.002386 0.000038 0.000123
300.000229 0.000182 0.002245 0.000039 0.000127
310.000211 0.000176 0.002544 0.000039 0.000136
320.000204 0.000180 0.002133 0.000037 0.000129
330.000205 0.000178 0.002330 0.000048 0.000146
340.000210 0.000178 0.002242 0.000039 0.000109
350.000210 0.000259 0.002766 0.000039 0.000118
360.000317 0.000495 0.002237 0.000039 0.000195
370.000454 0.000246 0.002447 0.000040 0.000172
380.000936 0.000200 0.002305 0.000057 0.000173
390.000263 0.000178 0.002251 0.000038 0.000166
400.000240 0.000183 0.002169 0.000068 0.000176
410.000251 0.000189 0.002221 0.000038 0.000141
420.000268 0.000215 0.002322 0.000039 0.000226
430.000287 0.000223 0.002696 0.000045 0.000247
440.000362 0.000229 0.002551 0.000043 0.000133
450.000239 0.000200 0.002621 0.000045 0.000133
460.000634 0.000208 0.002619 0.000046 0.000138
470.000236 0.000205 0.002589 0.000046 0.000137
480.000262 0.000205 0.002607 0.000045 0.000142
490.000239 0.000198 0.002754 0.000044 0.000185
500.000238 0.000198 0.002593 0.000057 0.000160
510.000242 0.000221 0.003784 0.000122 0.000174
520.000242 0.000201 0.002625 0.000054 0.000148
530.000296 0.000225 0.002934 0.000044 0.000134
540.000239 0.000245 0.003428 0.000046 0.000158
550.000261 0.000251 0.002569 0.000046 0.000139
560.000260 0.000230 0.002603 0.000045 0.000145
570.000302 0.000212 0.002580 0.000045 0.000176
580.000794 0.000197 0.002856 0.000046 0.000141
590.000273 0.000209 0.003173 0.000045 0.000217
600.000240 0.000201 0.002844 0.000043 0.000167
610.000389 0.000175 0.004315 0.000055 0.000091
620.000275 0.000534 0.004991 0.000053 0.000092
630.000229 0.000215 0.004084 0.000045 0.000074
640.000172 0.000474 0.002611 0.000043 0.000069
650.000201 0.000174 0.002485 0.000043 0.000069
660.000173 0.000220 0.002541 0.000045 0.000068
670.000167 0.000161 0.002827 0.000043 0.000071
680.000168 0.000160 0.003512 0.000068 0.000075
690.000211 0.000167 0.002530 0.000044 0.000069
700.000193 0.000230 0.003664 0.000046 0.000074
710.000171 0.000161 0.002575 0.000076 0.000075
720.000169 0.000161 0.002595 0.000044 0.000076
730.000981 0.000174 0.002556 0.000045 0.000072
740.000168 0.000163 0.002568 0.000043 0.000072
750.000163 0.000158 0.002579 0.000043 0.000386
760.000168 0.000160 0.002579 0.000059 0.000088
770.000176 0.000163 0.002559 0.000044 0.000075
780.000167 0.000161 0.002558 0.000043 0.000075
790.000169 0.000161 0.002599 0.000043 0.000095
800.000174 0.000163 0.002633 0.000046 0.000076
810.000170 0.000165 0.002576 0.000858 0.000079
820.000169 0.000162 0.002611 0.000044 0.000075
830.000170 0.000199 0.002621 0.000043 0.000074
840.000170 0.000167 0.003611 0.000043 0.000073
850.000171 0.000159 0.002764 0.000046 0.000076
860.000171 0.000165 0.002639 0.000044 0.000073
870.000168 0.000162 0.003131 0.000046 0.000075
880.000170 0.000162 0.002858 0.000044 0.000074
890.000171 0.000164 0.002841 0.000043 0.000075
900.000167 0.000161 0.002971 0.000043 0.000074
910.000170 0.000226 0.002842 0.000044 0.000074
920.000171 0.000165 0.002822 0.000044 0.000075
930.000173 0.000160 0.002895 0.000045 0.000073
940.000167 0.000217 0.002697 0.000044 0.000076
950.000170 0.000197 0.002699 0.000044 0.000075
960.000171 0.000163 0.003230 0.000045 0.000097
970.000170 0.000164 0.003167 0.000046 0.000082
980.000172 0.000196 0.002559 0.000043 0.000075
990.000168 0.000165 0.003006 0.000045 0.000075
1000.000176 0.000160 0.002567 0.000043 0.000075
1010.000167 0.000163 0.002757 0.000045 0.000076
1020.000171 0.000162 0.002802 0.000045 0.000076
1030.000169 0.000162 0.003102 0.000043 0.000072
1040.000167 0.000162 0.002624 0.000043 0.000075
1050.000170 0.000161 0.002589 0.000043 0.000072
1060.000222 0.000253 0.002657 0.000045 0.000075
1070.000172 0.000162 0.002586 0.000044 0.000084
1080.000172 0.000165 0.002933 0.000044 0.000075
1090.000169 0.000192 0.002609 0.000044 0.000074
1100.000194 0.000162 0.003020 0.000045 0.000081
1110.000170 0.000164 0.002908 0.000045 0.000076
1120.000169 0.000163 0.002567 0.000042 0.000073
1130.000167 0.000159 0.003071 0.000042 0.000074
1140.000222 0.000163 0.003175 0.000043 0.000076
1150.000167 0.000160 0.002641 0.000046 0.000099
1160.000171 0.000168 0.002586 0.000057 0.000075
1170.000170 0.000168 0.003148 0.000046 0.000075
1180.000171 0.000159 0.002770 0.000041 0.000074
1190.000173 0.000158 0.002643 0.000055 0.000077
1200.000313 0.000174 0.002920 0.000045 0.000075
1210.000170 0.000163 0.002551 0.000044 0.000072
1220.000173 0.000161 0.002599 0.000045 0.000073
1230.000167 0.000160 0.003505 0.000046 0.000075
1240.000171 0.000161 0.002894 0.000045 0.000074
1250.000171 0.000166 0.002572 0.000042 0.000073
1260.000166 0.000160 0.004099 0.000044 0.000102
1270.000181 0.000160 0.002499 0.000046 0.000071
1280.000174 0.000175 0.002560 0.000043 0.000068
1290.000165 0.000168 0.003083 0.000044 0.000070
1300.000210 0.000163 0.002535 0.000040 0.000068
1310.000164 0.000177 0.002906 0.000044 0.000075
1320.000175 0.000227 0.002971 0.000043 0.000073
1330.000167 0.000175 0.003409 0.000046 0.000078
1340.000172 0.000166 0.002640 0.000046 0.000074
1350.000177 0.000164 0.002574 0.000046 0.000076
1360.000170 0.000163 0.002631 0.000046 0.000075
1370.000216 0.000168 0.002596 0.000046 0.000076
1380.000170 0.000163 0.002659 0.000045 0.000074
1390.000172 0.000162 0.002677 0.000046 0.000075
1400.000170 0.000159 0.002604 0.000044 0.000081
1410.000171 0.000161 0.003163 0.000046 0.000076
1420.000171 0.000162 0.002574 0.000313 0.000075
1430.000170 0.000186 0.002988 0.000046 0.000074
1440.000171 0.000162 0.002596 0.000043 0.000077
1450.000168 0.000160 0.002640 0.000055 0.000074
1460.000169 0.000161 0.002567 0.000043 0.000371
1470.000170 0.000162 0.002704 0.000057 0.000078
1480.000255 0.000185 0.002453 0.000293 0.000066
1490.000148 0.000143 0.002169 0.000037 0.000066
1500.000173 0.000141 0.002238 0.000039 0.000085
1510.000154 0.000174 0.002679 0.000041 0.000065
1520.000149 0.000144 0.002187 0.000037 0.000065
1530.000146 0.000140 0.002760 0.000039 0.000071
1540.000147 0.000151 0.002193 0.000039 0.000065
1550.000150 0.000172 0.002207 0.000039 0.000067
1560.000147 0.000141 0.002126 0.000037 0.000060
1570.000191 0.000141 0.002119 0.000036 0.000086
1580.000149 0.000144 0.002440 0.000039 0.000065
1590.000148 0.000143 0.003287 0.000041 0.000068
1600.000152 0.000149 0.002555 0.000040 0.000069
1610.000148 0.000141 0.002203 0.000038 0.000065
1620.000147 0.000139 0.002371 0.000052 0.000075
1630.000148 0.000143 0.002201 0.000037 0.000066
1640.000149 0.000140 0.002186 0.000038 0.000062
1650.000152 0.000154 0.002215 0.000038 0.000062
1660.000149 0.000144 0.002505 0.000039 0.000067
1670.000148 0.000140 0.002216 0.000038 0.000101
1680.000160 0.000144 0.002574 0.000039 0.000067
1690.000150 0.000144 0.002266 0.000040 0.000068
1700.000151 0.000142 0.003640 0.000040 0.000068
1710.000150 0.000142 0.002207 0.000038 0.000066
1720.000148 0.000140 0.002337 0.000041 0.000068
1730.000151 0.000144 0.002138 0.000038 0.000063
1740.000146 0.000178 0.002369 0.000039 0.000060
1750.000150 0.000141 0.002290 0.000039 0.000067
1760.000149 0.000143 0.002569 0.000050 0.000070
1770.000149 0.000143 0.002797 0.000040 0.000068
1780.000149 0.000143 0.002720 0.000039 0.000066
1790.000273 0.000154 0.002255 0.000039 0.000066
1800.000147 0.000141 0.002180 0.000037 0.000065
1810.000884 0.000142 0.002164 0.000036 0.000060
1820.000188 0.000143 0.002248 0.000039 0.000062
1830.000148 0.000142 0.002178 0.000038 0.000064
1840.000151 0.000140 0.002705 0.000038 0.000063
1850.000145 0.000144 0.002588 0.000039 0.000064
1860.000147 0.000142 0.002196 0.000037 0.000064
1870.000147 0.000139 0.002169 0.000035 0.000060
1880.000151 0.000894 0.002267 0.000039 0.000061
1890.000152 0.000145 0.002178 0.000038 0.000061
1900.000185 0.000142 0.002148 0.000036 0.000062
1910.000147 0.000141 0.002845 0.000040 0.000065
1920.000159 0.000178 0.002193 0.000039 0.000063
1930.000145 0.000141 0.002571 0.000039 0.000066
1940.000149 0.000141 0.003380 0.000038 0.000065
1950.000200 0.000149 0.002439 0.000039 0.000066
1960.000152 0.000140 0.002193 0.000037 0.000065
1970.000147 0.000139 0.002239 0.000037 0.000066
1980.000200 0.000143 0.002190 0.000039 0.000066
1990.000147 0.000139 0.002243 0.000038 0.000062
2000.000421 0.000144 0.002229 0.000038 0.000062
2010.000147 0.000149 0.002715 0.000038 0.000063
2020.000151 0.000176 0.002144 0.000036 0.000060
2030.000145 0.000138 0.002184 0.000038 0.000064
2040.000146 0.000207 0.002526 0.000040 0.000067
2050.000163 0.000142 0.002366 0.000038 0.000070
2060.000149 0.000143 0.002143 0.000038 0.000065
2070.000150 0.000142 0.002146 0.000035 0.000059
2080.000162 0.000147 0.002736 0.000038 0.000067
2090.000149 0.000146 0.002383 0.000040 0.000071
2100.000147 0.000139 0.002485 0.000038 0.000065
2110.000147 0.000143 0.002811 0.000039 0.000098
2120.000181 0.000142 0.002503 0.000039 0.000066
2130.000150 0.000143 0.002227 0.000039 0.000065
2140.000149 0.000143 0.002182 0.000036 0.000061
2150.000148 0.000387 0.002159 0.000036 0.000059
2160.000147 0.000173 0.002267 0.000039 0.000063
2170.000147 0.000143 0.002729 0.000039 0.000066
2180.000149 0.000142 0.002574 0.000040 0.000069
2190.000149 0.000143 0.002560 0.000040 0.000068
2200.000152 0.000141 0.002203 0.000038 0.000066
2210.000151 0.000139 0.002234 0.000038 0.000087
2220.000148 0.000140 0.002152 0.000036 0.000060
2230.000185 0.000140 0.002274 0.000039 0.000063
2240.000148 0.000144 0.002211 0.000038 0.000066
2250.000149 0.000141 0.002692 0.000039 0.000066
2260.000148 0.000145 0.002519 0.000039 0.000066
2270.000147 0.000143 0.002188 0.000038 0.000066
2280.000149 0.000171 0.002171 0.000038 0.000093
2290.000150 0.000182 0.002185 0.000038 0.000068
2300.000191 0.000154 0.002172 0.000037 0.000061
2310.000145 0.000140 0.002253 0.000043 0.000065
2320.000147 0.000139 0.002673 0.000038 0.000066
2330.000191 0.000144 0.002740 0.000038 0.000066
2340.000147 0.000142 0.002187 0.000038 0.000064
2350.000146 0.000181 0.002180 0.000038 0.000066
2360.000176 0.000142 0.002152 0.000039 0.000061
2370.000149 0.000142 0.002164 0.000037 0.000064
2380.000245 0.000150 0.002771 0.000055 0.000084
2390.000149 0.000145 0.003006 0.000040 0.000069
2400.000153 0.000144 0.002701 0.000040 0.000067
2410.000149 0.000144 0.002192 0.000038 0.000065
2420.000148 0.000143 0.002220 0.000038 0.000063
2430.000146 0.000140 0.002210 0.000038 0.000062
2440.000157 0.000144 0.002174 0.000038 0.000060
2450.000148 0.000171 0.002208 0.000039 0.000061
2460.000146 0.000141 0.002685 0.000039 0.000064
2470.000146 0.000139 0.002811 0.000038 0.000064
2480.000147 0.000140 0.002234 0.000037 0.000063
2490.000143 0.000143 0.002209 0.000040 0.000066
2500.000149 0.000144 0.002162 0.000037 0.000091
2510.000408 0.000141 0.002140 0.000036 0.000060
2520.000142 0.000149 0.002208 0.000132 0.000061
2530.000148 0.000142 0.002706 0.000040 0.000066
2540.000148 0.000142 0.002502 0.000039 0.000065
2550.000176 0.000144 0.002265 0.000039 0.000066
2560.000150 0.000142 0.002199 0.000039 0.000065
2570.000147 0.000154 0.002201 0.000040 0.000067
2580.000150 0.000142 0.002164 0.000036 0.000094
2590.000183 0.000177 0.002253 0.000039 0.000063
2600.000189 0.000143 0.002480 0.000039 0.000066
2610.000148 0.000141 0.002212 0.000037 0.000064
2620.000150 0.000137 0.002192 0.000037 0.000065
2630.000144 0.000140 0.002271 0.000039 0.000062
2640.000190 0.000171 0.002145 0.000037 0.000061
2650.000146 0.000141 0.005865 0.000099 0.000083
2660.000178 0.000165 0.002792 0.000040 0.000066
2670.000148 0.000233 0.002742 0.000039 0.000079
2680.000157 0.000151 0.002225 0.000039 0.000066
2690.000149 0.000142 0.002215 0.000039 0.000081
2700.000165 0.000141 0.002239 0.000039 0.000081
2710.000150 0.000154 0.002154 0.000036 0.000060
2720.000152 0.000151 0.002216 0.000039 0.000075
2730.000172 0.000141 0.004471 0.000060 0.000092
2740.000250 0.000210 0.002881 0.000040 0.000066
2750.000176 0.000152 0.002262 0.000038 0.000337
2760.000164 0.000154 0.002485 0.000039 0.000074
2770.000149 0.000180 0.002148 0.000039 0.000078
2780.000194 0.000145 0.002345 0.000044 0.000064
2790.000164 0.000201 0.002483 0.000040 0.000062
2800.000148 0.000140 0.002249 0.000038 0.000076
2810.000155 0.000144 0.002504 0.000039 0.000067
2820.000166 0.000150 0.002780 0.000040 0.000079
2830.000150 0.000142 0.002194 0.000038 0.000086
2840.000178 0.000153 0.002360 0.000039 0.000079
2850.000160 0.000154 0.002159 0.000036 0.000079
2860.000195 0.000445 0.002203 0.000038 0.000074
2870.000171 0.000161 0.002220 0.000038 0.000087
2880.000165 0.000151 0.002231 0.000038 0.000088
2890.000149 0.000141 0.003445 0.000040 0.000068
2900.000148 0.000143 0.002465 0.000039 0.000081
2910.000165 0.000150 0.002228 0.000038 0.000067
2920.000160 0.000142 0.003231 0.000039 0.000066
2930.000149 0.000141 0.002215 0.000038 0.000078
2940.000146 0.000152 0.002152 0.000038 0.000077
2950.000168 0.000140 0.002258 0.000040 0.000076
2960.000193 0.000142 0.002266 0.000039 0.000085
2970.000261 0.000164 0.002160 0.000037 0.000061
2980.000151 0.000419 0.002217 0.000037 0.000073
2990.000163 0.000148 0.002856 0.000038 0.000106
3000.000258 0.000204 0.002267 0.000040 0.000075
3010.000178 0.000159 0.002266 0.000038 0.000070
3020.000158 0.000149 0.002665 0.000039 0.000085
3030.000164 0.000154 0.002478 0.000039 0.000077
3040.000148 0.000140 0.002459 0.000038 0.000066
3050.000161 0.000142 0.002206 0.000038 0.000074
3060.000155 0.000151 0.002230 0.000039 0.000083
3070.000161 0.000142 0.002225 0.000037 0.000072
3080.000161 0.000187 0.002450 0.000038 0.000063
3090.000145 0.000155 0.002438 0.000039 0.000079
3100.000166 0.000138 0.002296 0.000039 0.000076
3110.000170 0.000156 0.002446 0.000038 0.000078
3120.000160 0.000159 0.002211 0.000038 0.000078
3130.000159 0.000142 0.002190 0.000036 0.000110
3140.000157 0.000150 0.002336 0.000039 0.000073
3150.000165 0.000182 0.002132 0.000038 0.000072
3160.000160 0.000140 0.002641 0.000066 0.000066
3170.000147 0.000153 0.002153 0.000039 0.000080
3180.000148 0.000156 0.002165 0.000037 0.000077
3190.000147 0.000151 0.002201 0.000038 0.000067
3200.000162 0.000143 0.002216 0.000040 0.000080
3210.000165 0.000148 0.002223 0.000055 0.000080
3220.000193 0.000143 0.002155 0.000037 0.000078
3230.000165 0.000143 0.003005 0.000040 0.000067
3240.000151 0.000145 0.002511 0.000039 0.000070
3250.000149 0.000173 0.002246 0.000039 0.000066
3260.000148 0.000143 0.002808 0.000040 0.000067
3270.000148 0.000142 0.002513 0.000038 0.000066
3280.000148 0.000143 0.002203 0.000037 0.000065
3290.000146 0.000138 0.002123 0.000038 0.000061
3300.000170 0.000149 0.002165 0.000036 0.000062
3310.000144 0.000145 0.002186 0.000037 0.000059
3320.000144 0.000139 0.002520 0.000037 0.000065
3330.000146 0.000139 0.002559 0.000038 0.000066
3340.000153 0.000142 0.002537 0.000038 0.000067
3350.000168 0.000144 0.002217 0.000048 0.000066
3360.000147 0.000141 0.002120 0.000037 0.000063
3370.000188 0.001725 0.002541 0.000040 0.000067
3380.000149 0.000143 0.002229 0.000038 0.000076
3390.000147 0.000143 0.002233 0.000037 0.000062
3400.000182 0.000142 0.002150 0.000037 0.000061
3410.000148 0.000140 0.002196 0.000037 0.000065
3420.000145 0.000140 0.002473 0.000037 0.000065
3430.000147 0.000139 0.002725 0.000040 0.000067
3440.000149 0.000142 0.002217 0.000039 0.000065
3450.000146 0.000140 0.002167 0.000037 0.000061
3460.000176 0.000144 0.002415 0.000039 0.000064
3470.000171 0.000144 0.002925 0.000040 0.000068
3480.000152 0.000167 0.002190 0.000039 0.000066
3490.000149 0.000142 0.002530 0.000039 0.000067
3500.000150 0.000142 0.003059 0.000040 0.000068
3510.000149 0.000142 0.002417 0.000038 0.000072
3520.000149 0.000143 0.002569 0.000038 0.000068
3530.000148 0.000141 0.002262 0.000040 0.000068
3540.000152 0.000144 0.002253 0.000038 0.000066
3550.000149 0.000142 0.002134 0.000037 0.000061
3560.000277 0.000427 0.002186 0.000036 0.000060
3570.000145 0.000139 0.002791 0.000039 0.000065
3580.000149 0.000144 0.002238 0.000039 0.000066
3590.000147 0.000144 0.002514 0.000039 0.000066
3600.000148 0.000143 0.002683 0.000038 0.000063
3610.000147 0.000139 0.002214 0.000037 0.000068
3620.000145 0.000139 0.002149 0.000036 0.000059
3630.000185 0.000139 0.002214 0.000037 0.000060
3640.000145 0.000140 0.003549 0.000039 0.000066
3650.000187 0.000142 0.002160 0.000037 0.000059
3660.000147 0.000158 0.002212 0.000038 0.000065
3670.000148 0.000140 0.002483 0.000039 0.000067
3680.000147 0.000142 0.003034 0.000039 0.000066
3690.000148 0.000142 0.002228 0.000039 0.000066
3700.000145 0.000151 0.002225 0.000040 0.000067
3710.000149 0.000142 0.002858 0.000048 0.000083
3720.000203 0.000185 0.004022 0.000049 0.000086
3730.000212 0.000188 0.005086 0.000056 0.000093
3740.000220 0.000203 0.004209 0.000051 0.000085
3750.000208 0.000247 0.009261 0.000098 0.000089
3760.000211 0.000262 0.002546 0.000041 0.000066
3770.000198 0.000150 0.002534 0.000039 0.000079
3780.000159 0.000143 0.002207 0.000038 0.000094
3790.000157 0.000143 0.002173 0.000038 0.000062
3800.000198 0.000505 0.002157 0.000039 0.000079
3810.000164 0.000143 0.002172 0.000038 0.000076
3820.000156 0.000148 0.002259 0.000039 0.000080
3830.000161 0.000142 0.002219 0.000039 0.000076
3840.000161 0.000143 0.002266 0.000039 0.000085
3850.000161 0.000141 0.002150 0.000036 0.000077
3860.000179 0.000140 0.002140 0.000036 0.000071
3870.000157 0.000151 0.002316 0.000040 0.000079
3880.000149 0.000143 0.002269 0.000039 0.000066
3890.000161 0.000142 0.002206 0.000040 0.000091
3900.000172 0.000143 0.002244 0.000039 0.000067
3910.000168 0.000142 0.002189 0.000039 0.000083
3920.000163 0.000188 0.002156 0.000037 0.000077
3930.000168 0.000143 0.002266 0.000039 0.000084
3940.000166 0.000147 0.002205 0.000325 0.000078
3950.000175 0.000140 0.002173 0.000037 0.000106
3960.000170 0.000153 0.002158 0.000036 0.000083
3970.000168 0.000147 0.002825 0.000039 0.000108
3980.000172 0.000151 0.002483 0.000038 0.000085
3990.000160 0.000143 0.002163 0.000038 0.000066
4000.000161 0.000154 0.002493 0.000039 0.000084
4010.000167 0.000153 0.002564 0.000040 0.000082
4020.000159 0.000151 0.002185 0.000046 0.000088
4030.000157 0.000156 0.002175 0.000039 0.000076
4040.000150 0.000144 0.002151 0.000038 0.000063
4050.000160 0.000140 0.002429 0.000038 0.000064
4060.000160 0.000154 0.002184 0.000048 0.000077
4070.000168 0.000142 0.002686 0.000040 0.000119
4080.000164 0.000152 0.002279 0.000039 0.000075
4090.000161 0.000143 0.002192 0.000068 0.000067
4100.000161 0.000154 0.002190 0.000040 0.000092
4110.000246 0.000146 0.003064 0.000038 0.000072
4120.000163 0.000158 0.002171 0.000037 0.000073
4130.000216 0.000144 0.002209 0.000039 0.000115
4140.000159 0.000141 0.003338 0.000039 0.000079
4150.000277 0.000158 0.002464 0.000039 0.000082
4160.000168 0.000150 0.002227 0.000037 0.000079
4170.000168 0.000146 0.002775 0.000038 0.000077
4180.000146 0.000147 0.002694 0.000042 0.000084
4190.000160 0.000145 0.002807 0.000039 0.000066
4200.000162 0.000177 0.002187 0.000063 0.000066
4210.000147 0.000141 0.002220 0.000038 0.000085
4220.000160 0.000142 0.002216 0.000037 0.000077
4230.000166 0.000159 0.002224 0.000039 0.000108
4240.000147 0.000141 0.002746 0.000039 0.000078
4250.000159 0.000141 0.002194 0.000037 0.000063
4260.000164 0.000143 0.002164 0.000039 0.000067
4270.000169 0.000152 0.002278 0.000074 0.000088
4280.000157 0.000157 0.002155 0.000068 0.000076
4290.000159 0.000140 0.002170 0.000035 0.000078
4300.000156 0.000141 0.002299 0.000040 0.000066
4310.000192 0.000160 0.002241 0.000039 0.000082
4320.000149 0.000143 0.002288 0.000039 0.000079
4330.000161 0.000142 0.002185 0.000049 0.000077
4340.000147 0.000149 0.002284 0.000039 0.000063
4350.000456 0.000144 0.002203 0.000046 0.000064
4360.000187 0.000144 0.002147 0.000037 0.000061
4370.000147 0.000140 0.002238 0.000040 0.000067
4380.000147 0.000140 0.003077 0.000041 0.000068
4390.000151 0.000142 0.002226 0.000038 0.000065
4400.000146 0.000142 0.002188 0.000039 0.000065
4410.000145 0.000141 0.002156 0.000036 0.000061
4420.000143 0.000172 0.002379 0.000037 0.000060
4430.000152 0.000231 0.002172 0.000038 0.000065
4440.000153 0.000142 0.002181 0.000039 0.000065
4450.000148 0.000142 0.002567 0.000039 0.000067
4460.000150 0.000142 0.002177 0.000038 0.000072
4470.000147 0.000146 0.002328 0.000038 0.000063
4480.000146 0.000150 0.002211 0.000038 0.000063
4490.000149 0.000143 0.002222 0.000040 0.000072
4500.000150 0.000144 0.002455 0.000039 0.000065
4510.000147 0.000144 0.002206 0.000039 0.000066
4520.000145 0.000141 0.002153 0.000055 0.000070
4530.000443 0.000144 0.002139 0.000036 0.000069
4540.000147 0.000182 0.002188 0.000037 0.000061
4550.000146 0.000138 0.002248 0.000038 0.000067
4560.000147 0.000142 0.002817 0.000039 0.000067
4570.000148 0.000144 0.002230 0.000038 0.000066
4580.000148 0.000142 0.002239 0.000039 0.000067
4590.000149 0.000142 0.002197 0.000038 0.000063
4600.000181 0.000674 0.002170 0.000038 0.000061
4610.000146 0.000195 0.002204 0.000037 0.000061
4620.000146 0.000141 0.002260 0.000039 0.000067
4630.000150 0.000142 0.002193 0.000045 0.000065
4640.000147 0.000140 0.002229 0.000036 0.000066
4650.000146 0.000137 0.002197 0.000037 0.000062
4660.000152 0.000159 0.002187 0.000036 0.000060
4670.000145 0.000139 0.002224 0.000037 0.000064
4680.000149 0.000144 0.002175 0.000038 0.000066
4690.000150 0.000143 0.002187 0.000038 0.000066
4700.000148 0.000141 0.002152 0.000036 0.000061
4710.000185 0.000141 0.002176 0.000036 0.000064
4720.000169 0.000145 0.002483 0.000038 0.000067
4730.000149 0.000141 0.002225 0.000036 0.000064
4740.000244 0.000149 0.002538 0.000038 0.000065
4750.000156 0.000143 0.002317 0.000039 0.000297
4760.000228 0.000172 0.002222 0.000039 0.000300
4770.000149 0.000145 0.002173 0.000040 0.000066
4780.000154 0.000145 0.002155 0.000038 0.000093
4790.000161 0.000145 0.002178 0.000039 0.000063
4800.000147 0.000170 0.002299 0.000039 0.000066
4810.000149 0.000142 0.003494 0.000040 0.000066
4820.000149 0.000178 0.002237 0.000038 0.000062
4830.000148 0.000143 0.002150 0.000037 0.000064
4840.000146 0.000139 0.002315 0.000038 0.000065
4850.000147 0.000141 0.002269 0.000039 0.000067
4860.000173 0.000145 0.002191 0.000037 0.000065
4870.000166 0.000144 0.002247 0.000038 0.000061
4880.000146 0.000140 0.002551 0.000038 0.000065
4890.000148 0.000175 0.002202 0.000037 0.000064
4900.000145 0.000141 0.002217 0.000038 0.000063
4910.000146 0.000138 0.002164 0.000132 0.000547
4920.000148 0.000144 0.008140 0.000160 0.000893
4930.000311 0.000221 0.004526 0.000058 0.000109
4940.000238 0.000225 0.003475 0.000044 0.000094
4950.000178 0.000177 0.002537 0.000041 0.000087
4960.000172 0.000161 0.002194 0.000048 0.000084
4970.000172 0.000163 0.002177 0.000040 0.000084
4980.001177 0.000156 0.002351 0.000041 0.000325
4990.000167 0.000163 0.002273 0.000040 0.000088
5000.000170 0.000151 0.002245 0.000040 0.000077
5010.000172 0.000896 0.002181 0.000038 0.000080
5020.000202 0.000164 0.002449 0.000038 0.000076
5030.000162 0.000161 0.002188 0.000037 0.000078
5040.000165 0.000154 0.002440 0.000074 0.000091
5050.000167 0.000149 0.002185 0.000039 0.000081
5060.000176 0.000154 0.002427 0.000040 0.000093
5070.000168 0.000154 0.002304 0.000038 0.000105
5080.000672 0.000160 0.002260 0.000038 0.000088
5090.000686 0.000159 0.002207 0.000038 0.000084
5100.000163 0.000154 0.002186 0.000037 0.000077
5110.000173 0.000153 0.002399 0.000038 0.000082
5120.000166 0.000157 0.002709 0.000039 0.000077
5130.000155 0.000149 0.002143 0.000038 0.000097
5140.000166 0.000154 0.003454 0.000051 0.000106
5150.000166 0.000160 0.002539 0.000039 0.000128
5160.000169 0.000149 0.002307 0.000039 0.000085
5170.000170 0.000158 0.002225 0.000040 0.000088
5180.000170 0.000180 0.002165 0.000036 0.000103
5190.000203 0.000160 0.002345 0.000039 0.000075
5200.000173 0.000191 0.002160 0.000038 0.000074
5210.000165 0.000156 0.002243 0.000039 0.000085
5220.000172 0.000154 0.002260 0.000040 0.000090
5230.000163 0.000164 0.002258 0.000040 0.000085
5240.000168 0.000143 0.002755 0.000039 0.000086
5250.000178 0.000155 0.002202 0.000039 0.000075
5260.000164 0.000153 0.002267 0.000038 0.000081
5270.000161 0.000154 0.002158 0.000036 0.000090
5280.000169 0.000158 0.002454 0.000037 0.000061
5290.000162 0.000154 0.002543 0.000038 0.000091
5300.000170 0.000154 0.002168 0.000037 0.000085
5310.000166 0.000151 0.002852 0.000038 0.000087
5320.000167 0.000165 0.002484 0.000039 0.000089
5330.000374 0.000197 0.002217 0.000038 0.000082
5340.000156 0.000150 0.002213 0.000038 0.000112
5350.000683 0.000155 0.002131 0.000038 0.000077
5360.000162 0.000164 0.002199 0.000038 0.000076
5370.000176 0.000154 0.002345 0.000038 0.000089
5380.000175 0.000150 0.002928 0.000039 0.000082
5390.000161 0.000140 0.002528 0.000039 0.000066
5400.000159 0.000151 0.002256 0.000039 0.000075
5410.000155 0.000156 0.002233 0.000040 0.000066
5420.000171 0.000156 0.002149 0.000066 0.000084
5430.000182 0.000154 0.002233 0.000037 0.000117
5440.000166 0.000160 0.002460 0.000037 0.000088
5450.000159 0.000165 0.002891 0.000043 0.000075
5460.000169 0.000143 0.002383 0.000038 0.000084
5470.000162 0.000149 0.002313 0.000039 0.000078
5480.000166 0.000161 0.003837 0.000041 0.000092
5490.000166 0.000144 0.002389 0.000038 0.000078
5500.000185 0.000153 0.002548 0.000040 0.000090
5510.000166 0.000152 0.002943 0.000037 0.000063
5520.000147 0.000140 0.002284 0.000038 0.000066
5530.000145 0.000141 0.002555 0.000038 0.000071
5540.000189 0.000143 0.002235 0.000038 0.000359
5550.000149 0.000140 0.002779 0.000053 0.000089
5560.000211 0.000206 0.002744 0.000040 0.000067
5570.000150 0.000144 0.002471 0.000039 0.000065
5580.000151 0.000140 0.002563 0.000040 0.000064
5590.000148 0.000138 0.002305 0.000039 0.000066
5600.000148 0.000141 0.002162 0.000036 0.000060
5610.000182 0.000145 0.002403 0.000042 0.000063
5620.000152 0.000141 0.002311 0.000039 0.000065
5630.000148 0.000180 0.002192 0.000038 0.000065
5640.000149 0.000141 0.002516 0.000039 0.000066
5650.000147 0.000142 0.002193 0.000040 0.000064
5660.000146 0.000138 0.002194 0.000036 0.000060
5670.000197 0.000142 0.002291 0.000038 0.000063
5680.000148 0.000142 0.002440 0.000039 0.000066
5690.000148 0.000143 0.002228 0.000039 0.000066
5700.000149 0.000140 0.002216 0.000038 0.000067
5710.000148 0.000145 0.002196 0.000038 0.000066
5720.000148 0.000141 0.002157 0.000036 0.000061
5730.000144 0.000175 0.002491 0.000039 0.000063
5740.000147 0.000141 0.002290 0.000039 0.000066
5750.000149 0.000143 0.002508 0.000039 0.000067
5760.000149 0.000142 0.002536 0.000039 0.000067
5770.000150 0.000141 0.003132 0.000046 0.000070
5780.000153 0.000145 0.002202 0.000039 0.000067
5790.000149 0.000143 0.002102 0.000037 0.000067
5800.000989 0.000142 0.002188 0.000063 0.000068
5810.000151 0.000142 0.002229 0.000038 0.000068
5820.001481 0.000141 0.002238 0.000039 0.000070
5830.000148 0.000142 0.002204 0.000037 0.000093
5840.000160 0.000141 0.002138 0.000038 0.000062
5850.000145 0.000141 0.002708 0.000039 0.000065
5860.000147 0.000142 0.002218 0.000039 0.000067
5870.000148 0.000140 0.002759 0.000038 0.000066
5880.000148 0.000139 0.003156 0.000037 0.000067
5890.000185 0.000141 0.002259 0.000040 0.000066
5900.000148 0.000142 0.002226 0.000047 0.000068
5910.000148 0.000142 0.002305 0.000040 0.000090
5920.001000 0.000155 0.002217 0.000064 0.000068
5930.000154 0.000144 0.002554 0.000038 0.000065
5940.000148 0.000141 0.002151 0.000038 0.000066
5950.000146 0.000181 0.003031 0.000039 0.000062
5960.000146 0.000180 0.002254 0.000039 0.000061
5970.000147 0.000143 0.002188 0.000039 0.000065
5980.000147 0.000140 0.002259 0.000039 0.000063
5990.000146 0.000141 0.002238 0.000038 0.000076
6000.000148 0.000141 0.002163 0.000038 0.000061
6010.000153 0.000143 0.002195 0.000043 0.000072
6020.000149 0.000177 0.003291 0.000039 0.000063
6030.000258 0.000153 0.002150 0.000039 0.000066
6040.000157 0.000144 0.002155 0.000037 0.000060
6050.000160 0.001194 0.002269 0.000040 0.000100
6060.000164 0.000151 0.002162 0.000038 0.000078
6070.000163 0.000424 0.002178 0.000036 0.000069
6080.001333 0.000389 0.002249 0.000039 0.000066
6090.000175 0.000142 0.002208 0.000037 0.000102
6100.000443 0.000156 0.002249 0.000040 0.000062
6110.000244 0.001562 0.003049 0.000041 0.000083
6120.000208 0.000183 0.002483 0.000040 0.000068
6130.000164 0.000156 0.002220 0.000040 0.000078
6140.000169 0.000142 0.002694 0.000040 0.000083
6150.000162 0.000152 0.002453 0.000038 0.000077
6160.000157 0.000189 0.002306 0.000040 0.000077
6170.000162 0.000151 0.002200 0.000039 0.000325
6180.000150 0.000142 0.002251 0.000039 0.000066
6190.000172 0.000157 0.002184 0.000039 0.000073
6200.000160 0.000150 0.002678 0.000038 0.000326
6210.000165 0.000151 0.002292 0.000038 0.000094
6220.000162 0.000156 0.002203 0.000037 0.000083
6230.000170 0.000141 0.002175 0.000037 0.000074
6240.000149 0.000166 0.002235 0.000039 0.000071
6250.000161 0.000143 0.002423 0.000036 0.000180
6260.000164 0.000152 0.003095 0.000039 0.000076
6270.000172 0.000153 0.002466 0.000039 0.000115
6280.000151 0.000153 0.002274 0.000039 0.000066
6290.000150 0.000142 0.003179 0.000040 0.000080
6300.000172 0.000159 0.002421 0.000039 0.000083
6310.000159 0.000142 0.002165 0.000037 0.000068
6320.000155 0.000150 0.002233 0.000041 0.000123
6330.000153 0.000158 0.002253 0.000039 0.000571
6340.000203 0.000145 0.002269 0.000041 0.000077
6350.000164 0.000158 0.002176 0.000038 0.000086
6360.000197 0.000144 0.002220 0.000041 0.000080
6370.000174 0.000403 0.002224 0.000039 0.000063
6380.000218 0.000144 0.002150 0.000036 0.000069
6390.000149 0.000141 0.002479 0.000040 0.000079
6400.000163 0.000145 0.002664 0.000039 0.000082
6410.000150 0.000152 0.002446 0.000040 0.000069
6420.000203 0.000154 0.002205 0.000043 0.000077
6430.000160 0.000143 0.002210 0.000039 0.000087
6440.000194 0.000145 0.002167 0.000038 0.000069
6450.000151 0.000154 0.002137 0.000036 0.000079
6460.000162 0.000140 0.002697 0.000037 0.000085
6470.000162 0.000143 0.002233 0.000039 0.000076
6480.000148 0.000144 0.002210 0.000039 0.000065
6490.000151 0.000152 0.003015 0.000041 0.000084
6500.000158 0.000156 0.002730 0.000039 0.000079
6510.000312 0.000165 0.002207 0.000038 0.000076
6520.000167 0.000139 0.002297 0.000040 0.000065
6530.000172 0.000154 0.002205 0.000037 0.000080
6540.000146 0.000149 0.002286 0.000039 0.000076
6550.000164 0.000151 0.002214 0.000038 0.000073
6560.000162 0.000169 0.003110 0.000038 0.000067
6570.000293 0.000144 0.002182 0.000038 0.000060
6580.000157 0.000153 0.003778 0.000049 0.000095
6590.001735 0.000210 0.004360 0.000050 0.000083
6600.000297 0.000198 0.002532 0.000039 0.000072
6610.000185 0.000163 0.002173 0.000039 0.000070
6620.000183 0.000142 0.002122 0.000038 0.000062
6630.000147 0.000145 0.002443 0.000039 0.000066
6640.000149 0.000144 0.002473 0.000040 0.000066
6650.000147 0.000139 0.002949 0.000038 0.000063
6660.000147 0.000139 0.002737 0.000039 0.000066
6670.000199 0.000142 0.002927 0.000038 0.000066
6680.000149 0.000141 0.002188 0.000038 0.000065
6690.000147 0.000144 0.002203 0.000038 0.000066
6700.000149 0.000141 0.002154 0.000037 0.000062
6710.000144 0.000137 0.003526 0.000037 0.000066
6720.000151 0.000153 0.002150 0.000036 0.000060
6730.000145 0.000138 0.002202 0.000037 0.000065
6740.000272 0.000187 0.002477 0.000038 0.000306
6750.000148 0.000141 0.002421 0.000038 0.000067
6760.000147 0.000141 0.002252 0.000039 0.000065
6770.000150 0.000140 0.002144 0.000037 0.000061
6780.000191 0.000144 0.002229 0.000038 0.000060
6790.000145 0.000145 0.002202 0.000038 0.000061
6800.000146 0.000142 0.002418 0.000038 0.000065
6810.000189 0.000171 0.002568 0.000040 0.000066
6820.000150 0.000141 0.002300 0.000039 0.000067
6830.000151 0.000141 0.002199 0.000038 0.000347
6840.000147 0.000140 0.002165 0.000035 0.000061
6850.000151 0.000646 0.002310 0.000040 0.000062
6860.000161 0.000410 0.002195 0.000038 0.000061
6870.000147 0.000141 0.002466 0.000039 0.000066
6880.000147 0.000141 0.003026 0.000038 0.000066
6890.000148 0.000142 0.002223 0.000038 0.000065
6900.000147 0.000142 0.002196 0.000038 0.000067
6910.000147 0.000141 0.002155 0.000044 0.000064
6920.000146 0.000140 0.002354 0.000039 0.000067
6930.000149 0.000143 0.002186 0.000037 0.000062
6940.000150 0.000144 0.002498 0.000040 0.000063
6950.000178 0.000212 0.002453 0.000039 0.000062
6960.000149 0.000177 0.002463 0.000038 0.000063
6970.000147 0.000142 0.002507 0.000038 0.000067
6980.000149 0.000142 0.002717 0.000038 0.000066
6990.000148 0.000141 0.002452 0.000037 0.000065
7000.000147 0.000140 0.002266 0.000039 0.000066
7010.000149 0.000141 0.002183 0.000037 0.000066
7020.000153 0.000142 0.002203 0.000039 0.000067
7030.000152 0.000419 0.002245 0.000040 0.000062
7040.000149 0.000181 0.002181 0.000038 0.000063
7050.000147 0.000142 0.002224 0.000039 0.000066
7060.000147 0.000142 0.002204 0.000038 0.000066
7070.000146 0.000141 0.002250 0.000038 0.000065
7080.000148 0.000141 0.002142 0.000038 0.000063
7090.000156 0.000139 0.002176 0.000036 0.000060
7100.000243 0.000148 0.002768 0.000039 0.000069
7110.000146 0.000204 0.002194 0.000037 0.000065
7120.000147 0.000143 0.003071 0.000039 0.000066
7130.000148 0.000144 0.003489 0.000042 0.000073
7140.000151 0.000151 0.002173 0.000039 0.000064
7150.000146 0.000140 0.003509 0.000038 0.000067
7160.000148 0.000142 0.002191 0.000038 0.000064
7170.000146 0.000139 0.002441 0.000039 0.000117
7180.000174 0.000141 0.002133 0.000038 0.000065
7190.000151 0.000142 0.002257 0.000039 0.000073
7200.000163 0.000147 0.002187 0.000038 0.000061
7210.000146 0.000222 0.002193 0.000038 0.000062
7220.000145 0.000143 0.002434 0.000037 0.000064
7230.000145 0.000139 0.002933 0.000041 0.000066
7240.000146 0.000140 0.002680 0.000037 0.000065
7250.000143 0.000139 0.002217 0.001029 0.000065
7260.000145 0.000139 0.002361 0.000039 0.000067
7270.000150 0.000143 0.002186 0.000068 0.000066
7280.000148 0.000142 0.002149 0.000037 0.000061
7290.000147 0.000181 0.002183 0.000037 0.000061
7300.000146 0.000455 0.002305 0.000038 0.000074
7310.000148 0.000143 0.002223 0.000038 0.000066
7320.000148 0.000141 0.002547 0.000038 0.000066
7330.000148 0.000143 0.002180 0.000038 0.000336
7340.000146 0.000141 0.002102 0.000037 0.000063
7350.000150 0.000145 0.002170 0.000037 0.000067
7360.000152 0.000138 0.002982 0.000038 0.000067
7370.000149 0.000143 0.002419 0.000037 0.000064
7380.000145 0.000195 0.002228 0.000040 0.000067
7390.000148 0.000143 0.002193 0.000038 0.000064
7400.000155 0.000141 0.002166 0.000067 0.000066
7410.000454 0.000176 0.002193 0.000038 0.000063
7420.000186 0.000142 0.002165 0.000035 0.000066
7430.000144 0.000138 0.002542 0.000038 0.000066
7440.000148 0.000143 0.002733 0.000039 0.000066
7450.000147 0.000141 0.002227 0.000038 0.000067
7460.000145 0.000142 0.002764 0.000037 0.000064
7470.000144 0.000138 0.002207 0.000037 0.000065
7480.000147 0.000185 0.002262 0.000038 0.000062
7490.000154 0.000160 0.002163 0.000038 0.000063
7500.000150 0.000145 0.002719 0.000038 0.000065
7510.000145 0.000139 0.002226 0.000037 0.000074
7520.000148 0.000140 0.002517 0.000038 0.000067
7530.000148 0.000142 0.003734 0.000039 0.000067
7540.000147 0.000143 0.002508 0.000039 0.000067
7550.000146 0.000143 0.002288 0.000038 0.000067
7560.000149 0.000143 0.002899 0.000039 0.000067
7570.000150 0.000145 0.002232 0.000037 0.000065
7580.000148 0.000142 0.002169 0.000039 0.000067
7590.000161 0.000141 0.002196 0.000036 0.000060
7600.000145 0.000137 0.002467 0.000040 0.000064
7610.000147 0.000141 0.002168 0.000037 0.000063
7620.000147 0.000139 0.002165 0.000037 0.000064
7630.000146 0.000138 0.002167 0.000036 0.000060
7640.000150 0.000141 0.002326 0.000039 0.000063
7650.000149 0.000179 0.002197 0.000039 0.000063
7660.000148 0.000142 0.002538 0.000039 0.000067
7670.000148 0.000148 0.002555 0.000039 0.000067
7680.000150 0.000144 0.002180 0.000038 0.000066
7690.000245 0.000152 0.002203 0.000038 0.000065
7700.000146 0.000142 0.002118 0.000036 0.000091
7710.000648 0.000141 0.002173 0.000035 0.000058
7720.000142 0.000149 0.002137 0.000037 0.000059
7730.000144 0.000138 0.002191 0.000037 0.000063
7740.000143 0.000137 0.002795 0.000039 0.000065
7750.000147 0.000256 0.002250 0.000038 0.000064
7760.000148 0.000142 0.002231 0.000040 0.000075
7770.000149 0.000143 0.002174 0.000038 0.000061
7780.000182 0.000708 0.002255 0.000038 0.000061
7790.000181 0.000170 0.002222 0.000038 0.000060
7800.000148 0.000141 0.002177 0.000038 0.000065
7810.000147 0.000141 0.002478 0.000039 0.000065
7820.000148 0.000141 0.002191 0.000039 0.000065
7830.000146 0.000139 0.002161 0.000067 0.000063
7840.000157 0.000138 0.002174 0.000036 0.000059
7850.000143 0.000165 0.002396 0.000040 0.000067
7860.000148 0.000141 0.002302 0.000044 0.000067
7870.000148 0.000142 0.002226 0.000043 0.000065
7880.000149 0.000142 0.002198 0.000038 0.000087
7890.000147 0.000143 0.002221 0.000039 0.000066
7900.000146 0.000142 0.002376 0.000065 0.000063
7910.000152 0.000154 0.002201 0.000038 0.000062
7920.000150 0.000142 0.002705 0.000039 0.000067
7930.000149 0.000142 0.002267 0.000039 0.000067
7940.000194 0.000149 0.002347 0.000039 0.000066
7950.000155 0.000141 0.002594 0.000038 0.000066
7960.000148 0.000141 0.002189 0.000038 0.000064
7970.000202 0.000142 0.002155 0.000039 0.000062
7980.000182 0.000146 0.002204 0.000037 0.000061
7990.000146 0.000139 0.002466 0.000037 0.000065
8000.000146 0.000140 0.002463 0.000036 0.000065
8010.000146 0.000139 0.002209 0.000037 0.000063
8020.000145 0.000138 0.002146 0.000036 0.000060
8030.000181 0.000142 0.003356 0.000038 0.000068
8040.000161 0.000142 0.002169 0.000038 0.000062
8050.000146 0.000175 0.002538 0.000039 0.000061
8060.000148 0.000141 0.002482 0.000039 0.000067
8070.000148 0.000144 0.002450 0.000040 0.000066
8080.000149 0.000143 0.002466 0.000043 0.000068
8090.000148 0.000144 0.003551 0.000038 0.000068
8100.000149 0.000142 0.002482 0.000039 0.000066
8110.000149 0.000142 0.002220 0.000039 0.000066
8120.000151 0.000140 0.002199 0.000038 0.000064
8130.000148 0.000184 0.002185 0.000038 0.000066
8140.000145 0.000140 0.002158 0.000036 0.000092
8150.000158 0.000140 0.002262 0.000038 0.000062
8160.000148 0.000143 0.002674 0.000039 0.000066
8170.000148 0.000140 0.002421 0.000039 0.000066
8180.000149 0.000149 0.002433 0.000038 0.000065
8190.000146 0.000172 0.002187 0.000038 0.000065
8200.000146 0.000140 0.002311 0.000039 0.000323
8210.000149 0.000142 0.002180 0.000038 0.000091
8220.000420 0.000143 0.002483 0.000038 0.000063
8230.000685 0.000145 0.002136 0.000035 0.000064
8240.000146 0.000145 0.002433 0.000038 0.000062
8250.000146 0.000139 0.002496 0.000039 0.000066
8260.000149 0.000139 0.003626 0.000041 0.000068
8270.000153 0.000147 0.002272 0.000042 0.000067
8280.000248 0.000155 0.002208 0.000038 0.000063
8290.000146 0.000138 0.002524 0.000038 0.000068
8300.000147 0.000140 0.002176 0.000210 0.000065
8310.000147 0.000140 0.002166 0.000036 0.000060
8320.000144 0.000146 0.002169 0.000036 0.000057
8330.000144 0.000138 0.002207 0.000037 0.000063
8340.000145 0.000138 0.002183 0.000037 0.000062
8350.000145 0.000137 0.002167 0.000036 0.000059
8360.000148 0.000453 0.002310 0.000038 0.000061
8370.000183 0.000855 0.002326 0.000037 0.000061
8380.000146 0.000175 0.002672 0.000036 0.000060
8390.000143 0.000140 0.002238 0.000039 0.000065
8400.000146 0.000139 0.002473 0.000037 0.000064
8410.000146 0.000139 0.002196 0.000039 0.000065
8420.000145 0.000139 0.002141 0.000036 0.000061
8430.000174 0.000397 0.002175 0.000036 0.000059
8440.000143 0.000139 0.002647 0.000037 0.000065
8450.000147 0.000138 0.002196 0.000037 0.000064
8460.000146 0.000138 0.002199 0.000037 0.000063
8470.000146 0.000138 0.002167 0.000036 0.000066
8480.000169 0.000141 0.002156 0.000036 0.000060
8490.000143 0.000139 0.002180 0.000037 0.000065
8500.000144 0.000136 0.002756 0.000039 0.000066
8510.000150 0.000141 0.002919 0.000039 0.000066
8520.000147 0.000140 0.002184 0.000036 0.000065
8530.000145 0.000138 0.002168 0.000036 0.000091
8540.000156 0.000139 0.002169 0.000036 0.000059
8550.000143 0.000139 0.002741 0.000038 0.000065
8560.000147 0.000140 0.002429 0.000037 0.000063
8570.000145 0.000139 0.002226 0.000037 0.000064
8580.000145 0.000139 0.003381 0.000040 0.000066
8590.000153 0.000141 0.002262 0.000038 0.000064
8600.000145 0.000140 0.002137 0.000036 0.000062
8610.000154 0.000650 0.002217 0.000038 0.000063
8620.000184 0.000143 0.002209 0.000038 0.000062
8630.000153 0.000142 0.002907 0.000039 0.000066
8640.000147 0.000142 0.002158 0.000038 0.000064
8650.000146 0.000140 0.002953 0.000039 0.000068
8660.000148 0.000143 0.002208 0.000039 0.000065
8670.000149 0.000139 0.002187 0.000036 0.000065
8680.000144 0.000139 0.002157 0.000036 0.000061
8690.000154 0.000926 0.002139 0.000036 0.000059
8700.000183 0.000140 0.002526 0.000038 0.000062
8710.000148 0.000142 0.002207 0.000038 0.000066
8720.000147 0.000139 0.002790 0.000039 0.000069
8730.000149 0.000144 0.002251 0.000038 0.000066
8740.000151 0.000140 0.002220 0.000039 0.000066
8750.000148 0.000142 0.002523 0.000038 0.000064
8760.000151 0.000138 0.002151 0.000037 0.000065
8770.000147 0.000140 0.002251 0.000037 0.000062
8780.000149 0.000139 0.002607 0.000037 0.000065
8790.000147 0.000141 0.003380 0.000037 0.000066
8800.000147 0.000139 0.002285 0.000069 0.000066
8810.000149 0.000142 0.002566 0.000038 0.000067
8820.000147 0.000142 0.002523 0.000038 0.000067
8830.000152 0.000143 0.002215 0.000038 0.000067
8840.000150 0.000144 0.002243 0.000038 0.000075
8850.000149 0.000141 0.002148 0.000036 0.000063
8860.000182 0.000144 0.002167 0.000036 0.000062
8870.000278 0.000155 0.002631 0.000036 0.000061
8880.000149 0.000139 0.003175 0.000040 0.000066
8890.000156 0.000140 0.002660 0.000038 0.000065
8900.000148 0.000141 0.006171 0.000067 0.000069
8910.000164 0.000142 0.002713 0.000038 0.000064
8920.000161 0.000150 0.002270 0.000038 0.000081
8930.000160 0.000283 0.002276 0.000038 0.000083
8940.000168 0.000150 0.002207 0.000037 0.000072
8950.000151 0.000669 0.002160 0.000038 0.000062
8960.000196 0.000156 0.002363 0.000036 0.000061
8970.000162 0.000141 0.002160 0.000037 0.000077
8980.000147 0.000141 0.002676 0.000038 0.000096
8990.000162 0.000143 0.002263 0.000037 0.000065
9000.000162 0.000141 0.002206 0.000036 0.000080
9010.000146 0.000139 0.002149 0.000036 0.000060
9020.000169 0.000884 0.002163 0.000036 0.000076
9030.000187 0.000140 0.002222 0.000036 0.000061
9040.000145 0.000140 0.002192 0.000037 0.000084
9050.000145 0.000138 0.002619 0.000039 0.000116
9060.000158 0.000149 0.002213 0.000038 0.000089
9070.000145 0.000183 0.002154 0.000038 0.000089
9080.000162 0.000142 0.002142 0.000037 0.000061
9090.000146 0.000178 0.002401 0.000038 0.000062
9100.000145 0.000150 0.002741 0.000037 0.000081
9110.000147 0.000139 0.002360 0.000040 0.000067
9120.000151 0.000153 0.002459 0.000039 0.000075
9130.000148 0.000155 0.002459 0.000037 0.000091
9140.000153 0.000152 0.002174 0.000036 0.000064
9150.000424 0.000149 0.002116 0.000036 0.000068
9160.000166 0.000168 0.002625 0.000038 0.000076
9170.000146 0.000141 0.002957 0.000038 0.000067
9180.000160 0.000142 0.002501 0.000039 0.000079
9190.000147 0.000143 0.002219 0.000038 0.000066
9200.000160 0.000143 0.002771 0.000040 0.000079
9210.000148 0.000150 0.002426 0.000037 0.000082
9220.000146 0.000138 0.002134 0.000036 0.000103
9230.000659 0.000143 0.002197 0.000036 0.000073
9240.000179 0.000153 0.002301 0.000038 0.000074
9250.000147 0.000142 0.002258 0.000038 0.000066
9260.000146 0.000141 0.002210 0.000038 0.000066
9270.000161 0.000141 0.002235 0.000038 0.000084
9280.000145 0.000138 0.002131 0.000036 0.000060
9290.000151 0.000211 0.002265 0.000038 0.000062
9300.000147 0.000142 0.002254 0.000038 0.000067
9310.000148 0.000143 0.002217 0.000038 0.000079
9320.000160 0.000155 0.002229 0.000038 0.000066
9330.000145 0.000142 0.002129 0.000038 0.000065
9340.000165 0.000140 0.002140 0.000036 0.000076
9350.000162 0.000142 0.002452 0.000039 0.000079
9360.000148 0.000143 0.002253 0.000059 0.000068
9370.000164 0.000142 0.003378 0.000039 0.000096
9380.000150 0.000194 0.002192 0.000039 0.000067
9390.000161 0.000152 0.002202 0.000037 0.000077
9400.000160 0.000141 0.002258 0.000039 0.000067
9410.000167 0.000143 0.002706 0.000039 0.000067
9420.000149 0.000155 0.002280 0.000037 0.000100
9430.000174 0.000144 0.002134 0.000037 0.000090
9440.001167 0.000154 0.002224 0.000038 0.000067
9450.000162 0.000155 0.002181 0.000035 0.000065
9460.000773 0.000153 0.002145 0.000036 0.000060
9470.000149 0.000161 0.002160 0.000036 0.000071
9480.000208 0.000144 0.002164 0.000035 0.000060
9490.000143 0.000138 0.002156 0.000036 0.000064
9500.000143 0.000138 0.002225 0.000055 0.000066
9510.000147 0.000141 0.002734 0.000038 0.000065
9520.000145 0.000147 0.002173 0.000037 0.000064
9530.000146 0.000139 0.002112 0.000037 0.000060
9540.000144 0.000137 0.002708 0.000038 0.000064
9550.000144 0.000139 0.002421 0.000037 0.000064
9560.000145 0.000140 0.002449 0.000037 0.000063
9570.000143 0.000138 0.002278 0.000038 0.000064
9580.000145 0.000140 0.002427 0.000040 0.000130
9590.000151 0.000142 0.002155 0.000036 0.000064
9600.000181 0.000139 0.002435 0.000036 0.000060
9610.000145 0.000138 0.003527 0.000038 0.000065
9620.000146 0.000178 0.002178 0.000036 0.000060
9630.000145 0.000138 0.002139 0.000037 0.000065
9640.000145 0.000137 0.003006 0.000037 0.000064
9650.000146 0.000139 0.002204 0.000037 0.000065
9660.000145 0.000139 0.002211 0.000038 0.000062
9670.000182 0.000140 0.002221 0.000036 0.000061
9680.000145 0.000139 0.003169 0.000038 0.000068
9690.000149 0.000174 0.002414 0.000038 0.000066
9700.000147 0.000142 0.002234 0.000038 0.000066
9710.000149 0.000143 0.002678 0.000038 0.000065
9720.000148 0.000141 0.002886 0.000038 0.000066
9730.000145 0.000140 0.002250 0.000038 0.000065
9740.000148 0.000139 0.002181 0.000035 0.000065
9750.000718 0.000142 0.002141 0.000035 0.000059
9760.000189 0.000140 0.002383 0.000036 0.000059
9770.000145 0.000139 0.002206 0.000039 0.000065
9780.000154 0.000186 0.002457 0.000038 0.000066
9790.000190 0.000141 0.002224 0.000038 0.000066
9800.000149 0.000141 0.002151 0.000037 0.000066
9810.000215 0.000143 0.002151 0.000035 0.000061
9820.000144 0.000138 0.002822 0.000039 0.000065
9830.000147 0.000139 0.002275 0.000038 0.000065
9840.000148 0.000141 0.002211 0.000036 0.000064
9850.000146 0.000138 0.002201 0.000037 0.000066
9860.000148 0.000140 0.002273 0.000038 0.000068
9870.000150 0.000144 0.002188 0.000037 0.000063
9880.000152 0.000151 0.002190 0.000037 0.000062
9890.000146 0.000142 0.003145 0.000039 0.000067
9900.000151 0.000139 0.002218 0.000037 0.000065
9910.000145 0.000138 0.002264 0.000037 0.000066
9920.000148 0.000142 0.003011 0.000039 0.000067
9930.000149 0.000141 0.002196 0.000038 0.000065
9940.000146 0.000141 0.002188 0.000036 0.000060
9950.000149 0.000140 0.002190 0.000035 0.000060
9960.000144 0.000137 0.002641 0.000038 0.000064
9970.000146 0.000138 0.002182 0.000043 0.000065
9980.000146 0.000141 0.002216 0.000036 0.000064
9990.000147 0.000139 0.002294 0.000039 0.000068
10000.000657 0.000145 0.002143 0.000037 0.000062
10010.000154 0.000415 0.002237 0.000040 0.000084
diff --git a/content/files/style.css b/content/files/style.css
deleted file mode 100644
index df892e5..0000000
--- a/content/files/style.css
+++ /dev/null
@@ -1,6 +0,0 @@
1
2@media print {
3 nav, footer {
4 display: none;
5 }
6}